From 4f997feee7ceb6ab893c9a1cdfba24827874dbd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Atl=C3=A1ntico?= <49457785+Sarctiann@users.noreply.github.com> Date: Fri, 15 Jul 2022 01:59:11 -0300 Subject: [PATCH] tools: add tests for `v where`; improve usability (#15059) --- cmd/tools/vwhere/finder.v | 87 +++++--- cmd/tools/vwhere/finder_utils.v | 48 +++-- cmd/tools/vwhere/test/file_one.v | 28 +++ cmd/tools/vwhere/test/file_two.v | 29 +++ .../vwhere/test/nested_mod/nested_file.v | 7 + cmd/tools/vwhere/vwhere.v | 9 +- cmd/tools/vwhere/vwhere_test.v | 186 ++++++++++++++++++ cmd/v/help/where.txt | 18 +- 8 files changed, 356 insertions(+), 56 deletions(-) create mode 100644 cmd/tools/vwhere/test/file_one.v create mode 100644 cmd/tools/vwhere/test/file_two.v create mode 100644 cmd/tools/vwhere/test/nested_mod/nested_file.v create mode 100644 cmd/tools/vwhere/vwhere_test.v diff --git a/cmd/tools/vwhere/finder.v b/cmd/tools/vwhere/finder.v index e9bb29e26..273592eab 100755 --- a/cmd/tools/vwhere/finder.v +++ b/cmd/tools/vwhere/finder.v @@ -8,40 +8,49 @@ import os.cmdline // Finder is entity that contains all the logic struct Finder { mut: - symbol Symbol - visib Visibility - mutab Mutability - name string - modul string - mth_of string - dirs []string - matches []Match + symbol Symbol + visib Visibility + mutab Mutability + name string + modul string + receiver string + dirs []string + matches []Match } -fn (mut fdr Finder) configure_from_arguments() { +fn (mut fdr Finder) configure_from_arguments(args []string) { match args.len { 1 { fdr.name = args[0] } - 2 { - fdr.symbol.set_from_str(args[0]) - fdr.name = args[1] - } else { fdr.symbol.set_from_str(args[0]) - fdr.name = args[1] + if fdr.symbol == .method && !args[1].contains('.') { + make_and_print_error('method require a special notation:', [ + 'Receiver.method', + ], '${args[1]}') + } else if fdr.symbol == .method { + temp_args := args[1].split('.') + fdr.receiver = temp_args[0] + fdr.name = temp_args[1] + } else { + fdr.name = args[1] + } + if fdr.name.contains('-') { + make_and_print_error('It seems you forgot positional arg name:', [], fdr.name) + } fdr.visib.set_from_str(cmdline.option(args, '-vis', '${Visibility.all}')) + if fdr.symbol == .var && fdr.visib != .all { + make_and_print_error('-vis $fdr.visib just can be setted with symbol_type:', + ['fn', 'method', 'const', 'struct', 'enum', 'interface', 'regexp'], + '$fdr.symbol') + } fdr.mutab.set_from_str(cmdline.option(args, '-mut', '${Mutability.any}')) if fdr.symbol != .var && fdr.mutab != .any { make_and_print_error('-mut $fdr.mutab just can be setted with symbol_type:', ['var'], '$fdr.symbol') } fdr.modul = cmdline.option(args, '-mod', '') - fdr.mth_of = cmdline.option(args, '-m-of', '') - if fdr.symbol !in [.@fn, .regexp] && fdr.mth_of != '' { - make_and_print_error('-m-of $fdr.mth_of just can be setted with symbol_types:', - ['fn', 'regexp'], '$fdr.symbol') - } fdr.dirs = cmdline.options(args, '-dir') } } @@ -53,24 +62,32 @@ fn (mut fdr Finder) search_for_matches() { mut paths_to_search := []string{} if fdr.dirs.len == 0 && fdr.modul == '' { paths_to_search << [current_dir, vmod_dir] - if vroot !in paths_to_search { - paths_to_search << vroot + if vlib_dir !in paths_to_search { + paths_to_search << vlib_dir } paths_to_search << vmod_paths } else if fdr.dirs.len == 0 && fdr.modul != '' { - paths_to_search << if fdr.modul == 'main' { current_dir } else { fdr.modul } + paths_to_search << if fdr.modul == 'main' { current_dir } else { resolve_module(fdr.modul) or { + panic(err)} } } else if fdr.dirs.len != 0 && fdr.modul == '' { recursive = false - paths_to_search << fdr.dirs + paths_to_search << fdr.dirs.map(resolve_module(it) or { panic(err) }) } else { recursive = false - paths_to_search << if fdr.modul == 'main' { current_dir } else { fdr.modul } - paths_to_search << fdr.dirs + paths_to_search << if fdr.modul == 'main' { current_dir } else { resolve_module(fdr.modul) or { + panic(err)} } + paths_to_search << fdr.dirs.map(resolve_module(it) or { panic(err) }) } + // for p in paths_to_search { + // println(p) + // } mut files_to_search := []string{} for path in paths_to_search { files_to_search << collect_v_files(path, recursive) or { panic(err) } } + // for f in files_to_search { + // println(f) + // } // Auxiliar rgx sp := r'\s*' @@ -79,12 +96,15 @@ fn (mut fdr Finder) search_for_matches() { // Build regex query sy := '$fdr.symbol' - st := if fdr.mth_of != '' { '$sp$op$sp[a-z].*$sp$fdr.mth_of$cp$sp' } else { '.*' } + st := if fdr.receiver != '' { '$sp$op$sp[a-z].*$sp$fdr.receiver$cp$sp' } else { '.*' } na := '$fdr.name' query := match fdr.symbol { .@fn { - '.*$sy$st$na$sp${op}.*${cp}.*' + '.*$sy$sp$na$sp${op}.*${cp}.*' + } + .method { + '.*fn$st$na$sp${op}.*${cp}.*' } .var { '.*$na$sp:=.*' @@ -129,16 +149,16 @@ fn (mut fdr Finder) search_within_file(file string, query string) { } } if re.matches_string(line) && (const_found || line.contains('const')) { - words := line.split(' ').map(it.trim('\t')) + words := line.split(' ').filter(it != '').map(it.trim('\t')) match fdr.visib { .all {} .@pub { - if 'pub' !in words { + if 'pub' !in words && fdr.symbol != .@const { continue } } .pri { - if 'pub' in words { + if 'pub' in words && fdr.symbol != .@const { continue } } @@ -156,7 +176,10 @@ fn (mut fdr Finder) search_within_file(file string, query string) { } } } - fdr.matches << Match{file, n_line, line.replace(' {', '').trim('\t')} + fdr.matches << Match{file, n_line, words.join(' ').trim(' {')} + } + if line.starts_with(')') && fdr.symbol == .@const { + const_found = false } n_line++ } @@ -182,7 +205,7 @@ fn (fdr Finder) show_results() { fn (fdr Finder) str() string { v := maybe_color(term.bright_red, '$fdr.visib') m := maybe_color(term.bright_red, '$fdr.mutab') - st := if fdr.mth_of != '' { ' ( _ $fdr.mth_of)' } else { '' } + st := if fdr.receiver != '' { ' ( _ $fdr.receiver)' } else { '' } s := maybe_color(term.bright_magenta, '$fdr.symbol') n := maybe_color(term.bright_cyan, '$fdr.name') diff --git a/cmd/tools/vwhere/finder_utils.v b/cmd/tools/vwhere/finder_utils.v index f80f61914..7f169358a 100755 --- a/cmd/tools/vwhere/finder_utils.v +++ b/cmd/tools/vwhere/finder_utils.v @@ -8,6 +8,7 @@ import os.cmdline // Symbol type to search enum Symbol { @fn + method @struct @interface @enum @@ -31,12 +32,13 @@ enum Mutability { } const ( - args = os.args[2..] - verbose = '-v' in cmdline.only_options(args) - header = '-h' in cmdline.only_options(args) - format = '-f' in cmdline.only_options(args) + _args = os.args + verbose = '-v' in cmdline.only_options(_args) + header = '-h' in cmdline.only_options(_args) + format = '-f' in cmdline.only_options(_args) symbols = { 'fn': Symbol.@fn + 'method': .method 'struct': .@struct 'interface': .@interface 'enum': .@enum @@ -55,7 +57,7 @@ const ( 'not': .not } vexe = pref.vexe_path() - vroot = os.dir(vexe) + vlib_dir = os.join_path(os.dir(vexe), 'vlib') vmod_dir = os.vmodules_dir() vmod_paths = os.vmodules_paths()[1..] current_dir = os.abs_path('.') @@ -106,12 +108,12 @@ fn invalid_option(invalid ParamOption, arg string) { } } -fn valid_args_quantity_or_show_help() { +fn valid_args_quantity_or_show_help(args []string) { if true in [ args.len < 1, - '-help' in os.args, - '--help' in os.args, - os.args[1..] == ['where', 'help'], + '-help' in args, + '--help' in args, + args == ['help'], ] { os.system('${os.quoted_path(vexe)} help where') exit(0) @@ -119,11 +121,19 @@ fn valid_args_quantity_or_show_help() { } fn make_and_print_error(msg string, opts []string, arg string) { - eprintln('\n' + maybe_color(term.bright_yellow, msg)) - if opts.len > 0 { - eprint(opts.map(maybe_color(term.bright_green, it)).join(' | ')) + if verbose || format { + eprintln('\n' + maybe_color(term.bright_yellow, msg)) + if opts.len > 0 { + eprint(opts.map(maybe_color(term.bright_green, it)).join(' | ')) + } + eprintln(' ...can not be ${maybe_color(term.bright_red, arg)}') + } else { + eprint(maybe_color(term.bright_yellow, msg) + ' ') + if opts.len > 0 { + eprint(opts.map(maybe_color(term.bright_green, it)).join(' | ')) + } + eprintln(' ...can not be ${maybe_color(term.bright_red, arg)}') } - eprintln(' ...can not be ${maybe_color(term.bright_red, arg)}') exit(1) } @@ -158,3 +168,15 @@ fn collect_v_files(path string, recursive bool) ?[]string { } return all_files } + +fn resolve_module(path string) ?string { + if os.is_dir(path) { + return path + } else if os.is_dir(os.join_path(vmod_dir, path)) { + return os.join_path(vmod_dir, path) + } else if os.is_dir(os.join_path(vlib_dir, path)) { + return os.join_path(vlib_dir, path) + } else { + return error('Path: $path not found') + } +} diff --git a/cmd/tools/vwhere/test/file_one.v b/cmd/tools/vwhere/test/file_one.v new file mode 100644 index 000000000..9b0f65987 --- /dev/null +++ b/cmd/tools/vwhere/test/file_one.v @@ -0,0 +1,28 @@ +module test + +// Test declarations + +fn main() { + p_1 := Programmer{'Programmer', 'Inmutable'} + mut p_2 := Programmer{'Programmer', 'Mutable'} +} + +struct Programmer { + f_name string + l_name string +} + +fn (p Programmer) drink(cups int) string { + return 'drink coffee, return program' +} + +pub struct Brogrammer { + f_name string + life []Stories +} + +pub fn (p Brogrammer) drink(glasses int) string { + return 'drink beer, return script cluster' +} + +struct Stories {} diff --git a/cmd/tools/vwhere/test/file_two.v b/cmd/tools/vwhere/test/file_two.v new file mode 100644 index 000000000..c7186cf82 --- /dev/null +++ b/cmd/tools/vwhere/test/file_two.v @@ -0,0 +1,29 @@ +module test + +const ( + x = 10 + y = 100 + z = 1000 +) + +pub enum Public { + importable + shareable +} + +enum Private { + storable + donwloadable +} + +interface Drinker { + drink(int) string +} + +pub fn sprint(dkr Drinker) { + println(drk.drink(6)) +} + +fn some_function_name(foo string, bar int) string { + return 'baz' +} diff --git a/cmd/tools/vwhere/test/nested_mod/nested_file.v b/cmd/tools/vwhere/test/nested_mod/nested_file.v new file mode 100644 index 000000000..62a0b4617 --- /dev/null +++ b/cmd/tools/vwhere/test/nested_mod/nested_file.v @@ -0,0 +1,7 @@ +module nested_mod + +pub const ( + a = 30 + b = 60 + c = 120 +) diff --git a/cmd/tools/vwhere/vwhere.v b/cmd/tools/vwhere/vwhere.v index e362c9319..9749fffcb 100755 --- a/cmd/tools/vwhere/vwhere.v +++ b/cmd/tools/vwhere/vwhere.v @@ -1,9 +1,14 @@ module main +import os + fn main() { - valid_args_quantity_or_show_help() + args := os.args[2..] + + valid_args_quantity_or_show_help(args) + mut fdr := Finder{} - fdr.configure_from_arguments() + fdr.configure_from_arguments(args) fdr.search_for_matches() fdr.show_results() } diff --git a/cmd/tools/vwhere/vwhere_test.v b/cmd/tools/vwhere/vwhere_test.v new file mode 100644 index 000000000..cd90cd155 --- /dev/null +++ b/cmd/tools/vwhere/vwhere_test.v @@ -0,0 +1,186 @@ +module main + +import os + +const test_dir = os.join_path(os.dir(vexe), 'cmd', 'tools', 'vwhere', 'test') + +fn test_create_finder() { + mut fdr := Finder{} + + fdr.configure_from_arguments(['some']) + assert fdr.symbol == .@fn + assert fdr.name == 'some' + assert fdr.visib == .all + assert fdr.mutab == .any + + fdr.configure_from_arguments(['fn', 'some', '-vis', 'pub']) + assert fdr.symbol == .@fn + assert fdr.name == 'some' + assert fdr.visib == .@pub + + fdr.configure_from_arguments(['method', 'Some.some', '-vis', 'pri']) + assert fdr.symbol == .method + assert fdr.receiver == 'Some' + assert fdr.name == 'some' + assert fdr.visib == .pri + + fdr.configure_from_arguments(['struct', 'Some', '-mod', 'foo']) + assert fdr.symbol == .@struct + assert fdr.name == 'Some' + assert fdr.modul == 'foo' + + fdr.configure_from_arguments(['interface', 'Some', '-mod', 'foo', '-dir', 'bar']) + assert fdr.symbol == .@interface + assert fdr.name == 'Some' + assert fdr.modul == 'foo' + assert fdr.dirs == ['bar'] + + fdr.configure_from_arguments(['enum', 'Some', '-dir', 'bar', '-dir', 'baz']) + assert fdr.symbol == .@enum + assert fdr.name == 'Some' + assert fdr.dirs == ['bar', 'baz'] + + fdr.configure_from_arguments(['const', 'some']) + assert fdr.symbol == .@const + assert fdr.name == 'some' + + fdr.configure_from_arguments(['var', 'some', '-mut', 'yes']) + assert fdr.symbol == .var + assert fdr.name == 'some' + assert fdr.mutab == .yes + + fdr.configure_from_arguments(['var', 'some', '-mut', 'not']) + assert fdr.symbol == .var + assert fdr.name == 'some' + assert fdr.mutab == .not + + fdr.configure_from_arguments(['regexp', '.*some.*']) + assert fdr.symbol == .regexp + assert fdr.name == '.*some.*' +} + +fn test_find_mut_var() { + args := ['var', 'p_2', '-mut', 'yes', '-dir', test_dir] + mut fdr := Finder{} + fdr.configure_from_arguments(args) + fdr.search_for_matches() + assert fdr.matches == [ + Match{ + path: os.join_path(test_dir, 'file_one.v') + line: 7 + text: "mut p_2 := Programmer{'Programmer', 'Mutable'}" + }, + ] +} + +fn test_find_non_mut_var() { + args := ['var', 'p_1', '-mut', 'not', '-dir', test_dir] + mut fdr := Finder{} + fdr.configure_from_arguments(args) + fdr.search_for_matches() + assert fdr.matches == [ + Match{ + path: os.join_path(test_dir, 'file_one.v') + line: 6 + text: "p_1 := Programmer{'Programmer', 'Inmutable'}" + }, + ] +} + +fn test_find_method() { + args := ['method', 'Programmer.drink', '-dir', test_dir] + mut fdr := Finder{} + fdr.configure_from_arguments(args) + fdr.search_for_matches() + assert fdr.matches == [ + Match{ + path: os.join_path(test_dir, 'file_one.v') + line: 15 + text: 'fn (p Programmer) drink(cups int) string' + }, + ] +} + +fn test_find_pub_method() { + args := ['method', 'Brogrammer.drink', '-vis', 'pub', '-dir', test_dir] + mut fdr := Finder{} + fdr.configure_from_arguments(args) + fdr.search_for_matches() + assert fdr.matches == [ + Match{ + path: os.join_path(test_dir, 'file_one.v') + line: 24 + text: 'pub fn (p Brogrammer) drink(glasses int) string' + }, + ] +} + +fn test_find_pri_const() { + args := ['const', 'y', '-vis', 'pri', '-dir', test_dir] + mut fdr := Finder{} + fdr.configure_from_arguments(args) + fdr.search_for_matches() + assert fdr.matches == [ + Match{ + path: os.join_path(test_dir, 'file_two.v') + line: 5 + text: 'y = 100' + }, + ] +} + +fn test_find_pub_enum() { + args := ['enum', 'Public', '-vis', 'pub', '-dir', test_dir] + mut fdr := Finder{} + fdr.configure_from_arguments(args) + fdr.search_for_matches() + assert fdr.matches == [ + Match{ + path: os.join_path(test_dir, 'file_two.v') + line: 9 + text: 'pub enum Public' + }, + ] +} + +fn test_find_pri_enum() { + args := ['enum', 'Private', '-vis', 'pri', '-dir', test_dir] + mut fdr := Finder{} + fdr.configure_from_arguments(args) + fdr.search_for_matches() + assert fdr.matches == [ + Match{ + path: os.join_path(test_dir, 'file_two.v') + line: 14 + text: 'enum Private' + }, + ] +} + +fn test_find_fn() { + args := ['fn', 'some_function_name', '-dir', test_dir] + mut fdr := Finder{} + fdr.configure_from_arguments(args) + fdr.search_for_matches() + assert fdr.matches == [ + Match{ + path: os.join_path(test_dir, 'file_two.v') + line: 27 + text: 'fn some_function_name(foo string, bar int) string' + }, + ] +} + +fn test_find_pub_const_with_mod() { + args := ['const', 'b', '-vis', 'pub', '-mod', test_dir] + mut fdr := Finder{} + fdr.configure_from_arguments(args) + fdr.search_for_matches() + assert fdr.matches == [ + Match{ + path: os.join_path(test_dir, 'nested_mod', 'nested_file.v') + line: 5 + text: 'b = 60' + }, + ] +} diff --git a/cmd/v/help/where.txt b/cmd/v/help/where.txt index 621925052..c8fc5b198 100755 --- a/cmd/v/help/where.txt +++ b/cmd/v/help/where.txt @@ -1,11 +1,11 @@ Usage: - v where [symbol_type] [symbol_name] [params] + v where symbol_type symbol_name [params] Examples: v where fn main v where struct User - v where fn say_hello -mod Person - v where fn area -m-of Square + v where method Square.area + v where fn pow -mod math v where interface callable -dir some -dir other -------------------------------------------------------------------------------- @@ -13,7 +13,8 @@ Prints the location of the searched symbols in the scope of the current project. -------------------------------------------------------------------------------- symbol_name can be: - fn (by default if omit [symbol_type]) + fn by default if omit symbol_type (don't omit preferably) + method require Struct.method notation struct interface enum @@ -23,19 +24,18 @@ symbol_name can be: params: -mod [mod_name] Restrict to search recursively only within of the given - module, if not provided search in entire v scope. + module, if not provided search in entire v scope + (use -mod main to search inside all your project). -dir [dir_path] Restrict to search non recursively within the given folder/s, if not provided, search in entire v scope. -vis [visibility] Can be: all, pub, pri (all by default if not provided). Restrict to search symbols with the given visibility. -mut [mutability] Can be: any, yes, not (any by default if not provided). Restrict to search symbols with the given mutability. - -m-of [struct_name] (just for fn symbol_name). - Restrict to search fn as method of the given struct. flags: - -h Include header + -h include Header -f Format output (each match uses 3 lines) - -v For both above + -v for both above (more Verbose) Note: This tool is inspired by the vdoc tool and its design. However, this is -- 2.39.5