all: support _test.vv files (to test _test.v errors/checks too)

pull/8422/head^2
Delyan Angelov 2021-01-30 10:42:18 +02:00
parent 5564a2c1da
commit 760b4c37b9
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
8 changed files with 38 additions and 34 deletions

View File

@ -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)')

View File

@ -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 {

View File

@ -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 {

View File

@ -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 }

View File

@ -0,0 +1 @@
fn abc() {}

View File

@ -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')

View File

@ -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}(')

View File

@ -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 == '' {