1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00
v/cmd/tools/vcomplete_test.v
2022-12-06 13:02:32 +02:00

240 lines
6.3 KiB
V

import os
const vexe = @VEXE
const tfolder = os.join_path(os.vtmp_dir(), 'v', 'vcomplete_test')
enum Shell {
bash
fish
zsh
powershell
}
fn string_to_shell(shell string) !Shell {
return match shell {
'bash' {
.bash
}
'fish' {
.fish
}
'zsh' {
.zsh
}
'powershell' {
.powershell
}
else {
error('${shell} is not supported')
}
}
}
fn testsuite_begin() {
os.mkdir_all(tfolder) or {}
}
fn testsuite_end() {
os.rmdir_all(tfolder) or {}
}
fn detect_shell() Shell {
forced_shell := os.getenv('VTEST_VCOMPLETE_SHELL')
if forced_shell != '' {
return string_to_shell(forced_shell) or { panic(err) }
}
$if linux || macos {
return .bash
}
$if windows {
return .powershell
}
return .bash
}
struct CompleteTestCase {
shell Shell = detect_shell()
structure []string
completes map[string][]string
}
const test_cases = [
CompleteTestCase{
// Tests the completion of "v complet<tab>" *completeception*
structure: [] // no test folders
completes: {
'v complet': ['complete']
}
},
CompleteTestCase{
// Tests the completion of "v ru<tab>"
structure: [] // no test folders
completes: {
'v ru': ['run']
}
},
CompleteTestCase{
// Tests with one sub-folder in test root
// vfmt off
structure: [
os.join_path('examples', 'ex1'), // Empty dir
os.join_path('examples', 'ex2'), // Two files
os.join_path('examples', 'ex2', 'ex2_0.v'),
os.join_path('examples', 'ex2', 'ex2_1.v'),
os.join_path('examples', 'ex3'), // One file
os.join_path('examples', 'ex3', 'ex3.v')
]
// vfmt on
completes: {
'v run e': ['examples/']
'v run': ['examples/']
'v run ': ['examples/']
'v run examples/': ['ex1', 'ex2', 'ex3']
'v run examples/ex': ['examples/ex1/', 'examples/ex2/', 'examples/ex3/']
'v run examples/ex1': ['examples/ex1/']
'v run examples/ex1/': []
'v run examples/ex2/': ['ex2_0.v', 'ex2_1.v']
'v run examples/ex3/': ['examples/ex3/ex3.v']
'v run examples/ex3/ex3.v': ['examples/ex3/ex3.v']
'v examp': ['examples/']
'v examples/f': []
'v examples/': ['ex1', 'ex2', 'ex3']
'v examples/ex': ['examples/ex1/', 'examples/ex2/', 'examples/ex3/']
'v examples/ex1': ['examples/ex1/']
'v examples/ex1/': []
'v examples/ex2/': ['ex2_0.v', 'ex2_1.v']
'v examples/ex3/': ['examples/ex3/ex3.v']
'v examples/ex3/ex3.v': ['examples/ex3/ex3.v']
}
},
CompleteTestCase{
// Tests with two sub-folder in test root
// vfmt off
structure: [
os.join_path('sub0', 'ex1'), // Empty dir
os.join_path('sub0', 'ex2'), // Two files
os.join_path('sub0', 'ex2', 'ex2_0.v'),
os.join_path('sub0', 'ex2', 'ex2_1.v'),
os.join_path('sub0', 'ex3'), // One file
os.join_path('sub0', 'ex3', 'ex3.v'),
os.join_path('sub1', 'vex1'),
os.join_path('sub1', 'vex2'),
os.join_path('sub1', 'vex3'),
os.join_path('sub1', 'vex3', 'vex3.v')
]
// vfmt on
completes: {
// sub0
'v run ./': ['sub0/', 'sub1/']
'v run ./s': ['./sub0/', './sub1/']
'v run': ['sub0/', 'sub1/']
'v run ': ['sub0/', 'sub1/']
'v run sub0/': ['ex1', 'ex2', 'ex3']
'v run sub0/ex': ['sub0/ex1/', 'sub0/ex2/', 'sub0/ex3/']
'v run sub0/ex1': ['sub0/ex1/']
'v run sub0/ex1/': []
'v run sub0/ex2/': ['ex2_0.v', 'ex2_1.v']
'v run sub0/ex3/': ['sub0/ex3/ex3.v']
'v run sub0/ex3/ex3.v': ['sub0/ex3/ex3.v']
'v su': ['sub0/', 'sub1/']
'v sub': ['sub0/', 'sub1/']
'v sub0/f': []
'v sub0/': ['ex1', 'ex2', 'ex3']
'v sub0/ex': ['sub0/ex1/', 'sub0/ex2/', 'sub0/ex3/']
'v sub0/ex1': ['sub0/ex1/']
'v sub0/ex1/': []
'v sub0/ex2/': ['ex2_0.v', 'ex2_1.v']
'v sub0/ex3/': ['sub0/ex3/ex3.v']
'v sub0/ex3/ex3.v': ['sub0/ex3/ex3.v']
// sub1
'v run sub1/': ['vex1', 'vex2', 'vex3']
'v sub1/vex1/': []
'v sub1/vex2/': []
'v sub1/vex3/': ['sub1/vex3/vex3.v']
}
},
]
fn run_individual_test(case CompleteTestCase) ! {
// Clean plate
os.rmdir_all(tfolder) or {}
os.mkdir_all(tfolder) or {}
// Work relative to the test dir
os.chdir(tfolder) or { panic(err) }
for relative_path in case.structure {
path := os.join_path(tfolder, relative_path)
rel_parts := relative_path.split(os.path_separator)
if rel_parts.last().contains('.') {
// Make the containing dir
os.mkdir_all(os.dir(path)) or { panic(err) }
// Create empty file
mut f := os.create(path) or { panic(err) }
f.close()
} else {
os.mkdir_all(path) or { panic(err) }
}
}
for complete, expected in case.completes {
mut pre_strip := ''
mut post_strip := ''
mut complete_command := '${vexe} complete'
match case.shell {
.bash {
pre_strip = "COMPREPLY+=('"
post_strip = "')"
complete_command += ' bash'
}
.fish {
complete_command += ' fish'
}
.zsh {
pre_strip = 'compadd -U -S"" -- \''
post_strip = "';"
complete_command += ' zsh'
}
.powershell {
complete_command += ' powershell'
}
}
mut normalized_complete := complete
if case.shell == .powershell {
normalized_complete = normalized_complete.replace('/', '\\')
}
complete_command += ' ${normalized_complete}'
res := os.execute('${complete_command}')
mut lines := res.output.split('\n')
for mut line in lines {
if case.shell == .powershell {
line = line.replace('\r', '')
line = line.all_after('.\\')
}
line = line.trim_string_left(pre_strip).trim_string_right(post_strip)
}
lines = lines.filter(it != '')
lines.sort()
mut sorted_expected := expected.clone()
if case.shell == .powershell {
sorted_expected = sorted_expected.map(fn (path string) string {
mut normalized_path := path.replace('/', '\\')
normalized_path = normalized_path.all_after('.\\')
return normalized_path
})
}
sorted_expected.sort()
// eprintln('${complete} ${lines} vs ${sorted_expected}') // kept for easier debugging
assert lines.len == sorted_expected.len
for i, line in lines {
assert line == sorted_expected[i]
}
}
}
fn test_all_complete_cases() {
for case in test_cases {
run_individual_test(case)!
}
}