From 5fc7b6d3d6266007cd371989426c731ed6bc711e Mon Sep 17 00:00:00 2001 From: Larpon Date: Tue, 6 Dec 2022 12:02:32 +0100 Subject: [PATCH] tools: add tests for vcomplete (#16587) --- cmd/tools/vcomplete_test.v | 239 +++++++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 cmd/tools/vcomplete_test.v diff --git a/cmd/tools/vcomplete_test.v b/cmd/tools/vcomplete_test.v new file mode 100644 index 0000000000..224158b373 --- /dev/null +++ b/cmd/tools/vcomplete_test.v @@ -0,0 +1,239 @@ +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" *completeception* + structure: [] // no test folders + completes: { + 'v complet': ['complete'] + } + }, + CompleteTestCase{ + // Tests the completion of "v ru" + 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)! + } +}