From 760b4c37b9cb5bb8787f668db3372b4c48336622 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Sat, 30 Jan 2021 10:42:18 +0200 Subject: [PATCH] all: support _test.vv files (to test _test.v errors/checks too) --- vlib/v/builder/cc.v | 2 +- vlib/v/builder/compile.v | 2 +- vlib/v/checker/checker.v | 2 +- .../a_test_file_with_0_test_fns_test.out | 6 +++ .../tests/a_test_file_with_0_test_fns_test.vv | 1 + vlib/v/gen/cgen.v | 6 +-- vlib/v/gen/js/js.v | 51 +++++++++---------- vlib/v/pref/default.v | 2 +- 8 files changed, 38 insertions(+), 34 deletions(-) create mode 100644 vlib/v/checker/tests/a_test_file_with_0_test_fns_test.out create mode 100644 vlib/v/checker/tests/a_test_file_with_0_test_fns_test.vv diff --git a/vlib/v/builder/cc.v b/vlib/v/builder/cc.v index b9efcfdc5e..9c6d666b54 100644 --- a/vlib/v/builder/cc.v +++ b/vlib/v/builder/cc.v @@ -545,7 +545,7 @@ fn (mut v Builder) cc() { builtin_obj_path := v.rebuild_cached_module(vexe, 'vlib/builtin') libs << builtin_obj_path for ast_file in v.parsed_files { - is_test := ast_file.path.ends_with('_test.v') + is_test := ast_file.path.ends_with('_test.v') || ast_file.path.ends_with('_test.vv') if is_test && ast_file.mod.name != 'main' { imp_path := v.find_module_path(ast_file.mod.name, ast_file.path) or { verror('cannot import module "$ast_file.mod.name" (not found)') diff --git a/vlib/v/builder/compile.v b/vlib/v/builder/compile.v index f843d791a2..21fead410e 100644 --- a/vlib/v/builder/compile.v +++ b/vlib/v/builder/compile.v @@ -245,7 +245,7 @@ pub fn (v &Builder) get_user_files() []string { if v.pref.is_prof { user_files << os.join_path(preludes_path, 'profiled_program.v') } - is_test := dir.ends_with('_test.v') + is_test := dir.ends_with('_test.v') || dir.ends_with('_test.vv') mut is_internal_module_test := false if is_test { tcontent := os.read_file(dir) or { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 176865da2b..9907366e56 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -5392,7 +5392,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { // TODO c.pref.is_vet if node.language == .v && !node.is_method && node.params.len == 0 && node.name.after('.').starts_with('test_') { - if !c.file.path.ends_with('_test.v') { + if !c.pref.is_test { // simple heuristic for st in node.stmts { if st is ast.AssertStmt { diff --git a/vlib/v/checker/tests/a_test_file_with_0_test_fns_test.out b/vlib/v/checker/tests/a_test_file_with_0_test_fns_test.out new file mode 100644 index 0000000000..3734061291 --- /dev/null +++ b/vlib/v/checker/tests/a_test_file_with_0_test_fns_test.out @@ -0,0 +1,6 @@ +vlib/v/checker/tests/a_test_file_with_0_test_fns_test.vv:1:1: error: a _test.v file should have *at least* one `test_` function + 1 | fn abc() {} + | ^ +Details: The name of a test function in V, should start with `test_`. +The test function should take 0 parameters, and no return type. Example: +fn test_xyz(){ assert 2 + 2 == 4 } diff --git a/vlib/v/checker/tests/a_test_file_with_0_test_fns_test.vv b/vlib/v/checker/tests/a_test_file_with_0_test_fns_test.vv new file mode 100644 index 0000000000..45f81ae7e6 --- /dev/null +++ b/vlib/v/checker/tests/a_test_file_with_0_test_fns_test.vv @@ -0,0 +1 @@ +fn abc() {} diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 1f84510971..fcea13dc78 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -215,10 +215,8 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string } // println('\ncgen "$g.file.path" nr_stmts=$file.stmts.len') // building_v := true && (g.file.path.contains('/vlib/') || g.file.path.contains('cmd/v')) - is_test := g.file.path.ends_with('.vv') || g.file.path.ends_with('_test.v') - if g.file.path.ends_with('_test.v') { - g.is_test = is_test - } + is_test := g.file.path.ends_with('_test.vv') || g.file.path.ends_with('_test.v') + g.is_test = is_test if g.file.path == '' || !g.pref.autofree { // cgen test or building V // println('autofree=false') diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index a3a773f2bd..63f261c23e 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -11,10 +11,11 @@ import v.depgraph const ( // https://ecma-international.org/ecma-262/#sec-reserved-words js_reserved = ['await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger', - 'default', 'delete', 'do', 'else', 'enum', 'export', 'extends', 'finally', 'for', 'function', 'if', - 'implements', 'import', 'in', 'instanceof', 'interface', 'let', 'new', 'package', 'private', 'protected', - 'public', 'return', 'static', 'super', 'switch', 'this', 'throw', 'try', 'typeof', 'var', 'void', - 'while', 'with', 'yield', 'Number', 'String', 'Boolean', 'Array', 'Map'] + 'default', 'delete', 'do', 'else', 'enum', 'export', 'extends', 'finally', 'for', 'function', + 'if', 'implements', 'import', 'in', 'instanceof', 'interface', 'let', 'new', 'package', + 'private', 'protected', 'public', 'return', 'static', 'super', 'switch', 'this', 'throw', + 'try', 'typeof', 'var', 'void', 'while', 'with', 'yield', 'Number', 'String', 'Boolean', + 'Array', 'Map'] // used to generate type structs v_types = ['i8', 'i16', 'int', 'i64', 'byte', 'u16', 'u32', 'u64', 'f32', 'f64', 'int_literal', 'float_literal', 'size_t', 'bool', 'string', 'map', 'array'] @@ -23,7 +24,7 @@ const ( ) struct Namespace { - name string + name string mut: out strings.Builder = strings.new_builder(128) pub_vars []string @@ -33,8 +34,8 @@ mut: } struct JsGen { - table &table.Table - pref &pref.Preferences + table &table.Table + pref &pref.Preferences mut: definitions strings.Builder ns &Namespace @@ -53,7 +54,7 @@ mut: stmt_start_pos int defer_stmts []ast.DeferStmt fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0 - str_types []string // types that need automatic str() generation + str_types []string // types that need automatic str() generation method_fn_decls map[string][]ast.FnDecl builtin_fns []string // Functions defined in `builtin` empty_line bool @@ -81,14 +82,14 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string for file in files { g.file = file g.enter_namespace(g.file.mod.name) - g.is_test = g.file.path.ends_with('_test.v') + g.is_test = g.file.path.ends_with('_test.v') || g.file.path.ends_with('_test.vv') g.find_class_methods(file.stmts) g.escape_namespace() } for file in files { g.file = file g.enter_namespace(g.file.mod.name) - g.is_test = g.file.path.ends_with('_test.v') + g.is_test = g.file.path.ends_with('_test.v') || g.file.path.ends_with('_test.vv') // store imports mut imports := []string{} for imp in g.file.imports { @@ -132,7 +133,7 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string out += '\n\treturn {' // export builtin types if name == 'builtin' { - for typ in v_types { + for typ in js.v_types { out += '\n\t\t$typ,' } } @@ -158,14 +159,14 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string if name == 'builtin' { out += '// builtin type casts\n' out += 'const [' - for i, typ in v_types { + for i, typ in js.v_types { if i > 0 { out += ', ' } out += '$typ' } out += '] = [' - for i, typ in v_types { + for i, typ in js.v_types { if i > 0 { out += ',' } @@ -245,7 +246,7 @@ fn verror(msg string) { [inline] pub fn (mut g JsGen) gen_indent() { if g.ns.indent > 0 && g.empty_line { - g.ns.out.write(tabs[g.ns.indent]) + g.ns.out.write(js.tabs[g.ns.indent]) } g.empty_line = false } @@ -323,7 +324,7 @@ fn (mut g JsGen) js_name(name_ string) string { mut parts := name.split('.') if !is_js { for i, p in parts { - if p in js_reserved { + if p in js.js_reserved { parts[i] = 'v_$p' } } @@ -547,7 +548,7 @@ fn (mut g JsGen) expr(node ast.Expr) { g.gen_string_inter_literal(node) } ast.StringLiteral { - text := node.val.replace("\'", "\\'") + text := node.val.replace("'", "\\'") if g.file.mod.name == 'builtin' { g.write('new ') } @@ -988,7 +989,7 @@ fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) { if name.starts_with('JS.') { return } - if name in v_types && g.ns.name == 'builtin' { + if name in js.v_types && g.ns.name == 'builtin' { return } js_name := g.js_name(name) @@ -1368,8 +1369,8 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) { g.write(')') } } else { - both_are_int := int(it.left_type) in table.integer_type_idxs && - int(it.right_type) in table.integer_type_idxs + both_are_int := int(it.left_type) in table.integer_type_idxs + && int(it.right_type) in table.integer_type_idxs is_arithmetic := it.op in [token.Kind.plus, .minus, .mul, .div, .mod] if is_arithmetic { g.write('${g.typ(g.greater_typ(it.left_type, it.right_type))}(') @@ -1404,9 +1405,8 @@ fn (mut g JsGen) greater_typ(left table.Type, right table.Type) table.Type { if table.string_type_idx in lr { return table.Type(table.string_type_idx) } - should_float := (l in table.integer_type_idxs && - r in table.float_type_idxs) || - (r in table.integer_type_idxs && l in table.float_type_idxs) + should_float := (l in table.integer_type_idxs && r in table.float_type_idxs) + || (r in table.integer_type_idxs && l in table.float_type_idxs) if should_float { if table.f64_type_idx in lr { return table.Type(table.f64_type_idx) @@ -1559,12 +1559,11 @@ fn (mut g JsGen) gen_typeof_expr(it ast.TypeOf) { } fn (mut g JsGen) gen_type_cast_expr(it ast.CastExpr) { - is_literal := ((it.expr is ast.IntegerLiteral && - it.typ in table.integer_type_idxs) || - (it.expr is ast.FloatLiteral && it.typ in table.float_type_idxs)) + is_literal := ((it.expr is ast.IntegerLiteral && it.typ in table.integer_type_idxs) + || (it.expr is ast.FloatLiteral && it.typ in table.float_type_idxs)) typ := g.typ(it.typ) if !is_literal { - if !(typ in v_types) || g.ns.name == 'builtin' { + if !(typ in js.v_types) || g.ns.name == 'builtin' { g.write('new ') } g.write('${typ}(') diff --git a/vlib/v/pref/default.v b/vlib/v/pref/default.v index b7ceee37db..a8df86f89f 100644 --- a/vlib/v/pref/default.v +++ b/vlib/v/pref/default.v @@ -70,7 +70,7 @@ pub fn (mut p Preferences) fill_with_defaults() { } p.find_cc_if_cross_compiling() p.ccompiler_type = cc_from_string(p.ccompiler) - p.is_test = p.path.ends_with('_test.v') + p.is_test = p.path.ends_with('_test.v') || p.path.ends_with('_test.vv') p.is_vsh = p.path.ends_with('.vsh') p.is_script = p.is_vsh || p.path.ends_with('.v') || p.path.ends_with('.vv') if p.third_party_option == '' {