all: support _test.vv files (to test _test.v errors/checks too)
parent
5564a2c1da
commit
760b4c37b9
|
@ -545,7 +545,7 @@ fn (mut v Builder) cc() {
|
||||||
builtin_obj_path := v.rebuild_cached_module(vexe, 'vlib/builtin')
|
builtin_obj_path := v.rebuild_cached_module(vexe, 'vlib/builtin')
|
||||||
libs << builtin_obj_path
|
libs << builtin_obj_path
|
||||||
for ast_file in v.parsed_files {
|
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' {
|
if is_test && ast_file.mod.name != 'main' {
|
||||||
imp_path := v.find_module_path(ast_file.mod.name, ast_file.path) or {
|
imp_path := v.find_module_path(ast_file.mod.name, ast_file.path) or {
|
||||||
verror('cannot import module "$ast_file.mod.name" (not found)')
|
verror('cannot import module "$ast_file.mod.name" (not found)')
|
||||||
|
|
|
@ -245,7 +245,7 @@ pub fn (v &Builder) get_user_files() []string {
|
||||||
if v.pref.is_prof {
|
if v.pref.is_prof {
|
||||||
user_files << os.join_path(preludes_path, 'profiled_program.v')
|
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
|
mut is_internal_module_test := false
|
||||||
if is_test {
|
if is_test {
|
||||||
tcontent := os.read_file(dir) or {
|
tcontent := os.read_file(dir) or {
|
||||||
|
|
|
@ -5392,7 +5392,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||||
// TODO c.pref.is_vet
|
// TODO c.pref.is_vet
|
||||||
if node.language == .v && !node.is_method && node.params.len == 0
|
if node.language == .v && !node.is_method && node.params.len == 0
|
||||||
&& node.name.after('.').starts_with('test_') {
|
&& node.name.after('.').starts_with('test_') {
|
||||||
if !c.file.path.ends_with('_test.v') {
|
if !c.pref.is_test {
|
||||||
// simple heuristic
|
// simple heuristic
|
||||||
for st in node.stmts {
|
for st in node.stmts {
|
||||||
if st is ast.AssertStmt {
|
if st is ast.AssertStmt {
|
||||||
|
|
|
@ -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 }
|
|
@ -0,0 +1 @@
|
||||||
|
fn abc() {}
|
|
@ -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')
|
// println('\ncgen "$g.file.path" nr_stmts=$file.stmts.len')
|
||||||
// building_v := true && (g.file.path.contains('/vlib/') || g.file.path.contains('cmd/v'))
|
// 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')
|
is_test := g.file.path.ends_with('_test.vv') || g.file.path.ends_with('_test.v')
|
||||||
if g.file.path.ends_with('_test.v') {
|
g.is_test = is_test
|
||||||
g.is_test = is_test
|
|
||||||
}
|
|
||||||
if g.file.path == '' || !g.pref.autofree {
|
if g.file.path == '' || !g.pref.autofree {
|
||||||
// cgen test or building V
|
// cgen test or building V
|
||||||
// println('autofree=false')
|
// println('autofree=false')
|
||||||
|
|
|
@ -11,10 +11,11 @@ import v.depgraph
|
||||||
const (
|
const (
|
||||||
// https://ecma-international.org/ecma-262/#sec-reserved-words
|
// https://ecma-international.org/ecma-262/#sec-reserved-words
|
||||||
js_reserved = ['await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger',
|
js_reserved = ['await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger',
|
||||||
'default', 'delete', 'do', 'else', 'enum', 'export', 'extends', 'finally', 'for', 'function', 'if',
|
'default', 'delete', 'do', 'else', 'enum', 'export', 'extends', 'finally', 'for', 'function',
|
||||||
'implements', 'import', 'in', 'instanceof', 'interface', 'let', 'new', 'package', 'private', 'protected',
|
'if', 'implements', 'import', 'in', 'instanceof', 'interface', 'let', 'new', 'package',
|
||||||
'public', 'return', 'static', 'super', 'switch', 'this', 'throw', 'try', 'typeof', 'var', 'void',
|
'private', 'protected', 'public', 'return', 'static', 'super', 'switch', 'this', 'throw',
|
||||||
'while', 'with', 'yield', 'Number', 'String', 'Boolean', 'Array', 'Map']
|
'try', 'typeof', 'var', 'void', 'while', 'with', 'yield', 'Number', 'String', 'Boolean',
|
||||||
|
'Array', 'Map']
|
||||||
// used to generate type structs
|
// used to generate type structs
|
||||||
v_types = ['i8', 'i16', 'int', 'i64', 'byte', 'u16', 'u32', 'u64', 'f32', 'f64', 'int_literal',
|
v_types = ['i8', 'i16', 'int', 'i64', 'byte', 'u16', 'u32', 'u64', 'f32', 'f64', 'int_literal',
|
||||||
'float_literal', 'size_t', 'bool', 'string', 'map', 'array']
|
'float_literal', 'size_t', 'bool', 'string', 'map', 'array']
|
||||||
|
@ -23,7 +24,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
struct Namespace {
|
struct Namespace {
|
||||||
name string
|
name string
|
||||||
mut:
|
mut:
|
||||||
out strings.Builder = strings.new_builder(128)
|
out strings.Builder = strings.new_builder(128)
|
||||||
pub_vars []string
|
pub_vars []string
|
||||||
|
@ -33,8 +34,8 @@ mut:
|
||||||
}
|
}
|
||||||
|
|
||||||
struct JsGen {
|
struct JsGen {
|
||||||
table &table.Table
|
table &table.Table
|
||||||
pref &pref.Preferences
|
pref &pref.Preferences
|
||||||
mut:
|
mut:
|
||||||
definitions strings.Builder
|
definitions strings.Builder
|
||||||
ns &Namespace
|
ns &Namespace
|
||||||
|
@ -53,7 +54,7 @@ mut:
|
||||||
stmt_start_pos int
|
stmt_start_pos int
|
||||||
defer_stmts []ast.DeferStmt
|
defer_stmts []ast.DeferStmt
|
||||||
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
|
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
|
method_fn_decls map[string][]ast.FnDecl
|
||||||
builtin_fns []string // Functions defined in `builtin`
|
builtin_fns []string // Functions defined in `builtin`
|
||||||
empty_line bool
|
empty_line bool
|
||||||
|
@ -81,14 +82,14 @@ pub fn gen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||||
for file in files {
|
for file in files {
|
||||||
g.file = file
|
g.file = file
|
||||||
g.enter_namespace(g.file.mod.name)
|
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.find_class_methods(file.stmts)
|
||||||
g.escape_namespace()
|
g.escape_namespace()
|
||||||
}
|
}
|
||||||
for file in files {
|
for file in files {
|
||||||
g.file = file
|
g.file = file
|
||||||
g.enter_namespace(g.file.mod.name)
|
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
|
// store imports
|
||||||
mut imports := []string{}
|
mut imports := []string{}
|
||||||
for imp in g.file.imports {
|
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 {'
|
out += '\n\treturn {'
|
||||||
// export builtin types
|
// export builtin types
|
||||||
if name == 'builtin' {
|
if name == 'builtin' {
|
||||||
for typ in v_types {
|
for typ in js.v_types {
|
||||||
out += '\n\t\t$typ,'
|
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' {
|
if name == 'builtin' {
|
||||||
out += '// builtin type casts\n'
|
out += '// builtin type casts\n'
|
||||||
out += 'const ['
|
out += 'const ['
|
||||||
for i, typ in v_types {
|
for i, typ in js.v_types {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
out += ', '
|
out += ', '
|
||||||
}
|
}
|
||||||
out += '$typ'
|
out += '$typ'
|
||||||
}
|
}
|
||||||
out += '] = ['
|
out += '] = ['
|
||||||
for i, typ in v_types {
|
for i, typ in js.v_types {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
out += ','
|
out += ','
|
||||||
}
|
}
|
||||||
|
@ -245,7 +246,7 @@ fn verror(msg string) {
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (mut g JsGen) gen_indent() {
|
pub fn (mut g JsGen) gen_indent() {
|
||||||
if g.ns.indent > 0 && g.empty_line {
|
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
|
g.empty_line = false
|
||||||
}
|
}
|
||||||
|
@ -323,7 +324,7 @@ fn (mut g JsGen) js_name(name_ string) string {
|
||||||
mut parts := name.split('.')
|
mut parts := name.split('.')
|
||||||
if !is_js {
|
if !is_js {
|
||||||
for i, p in parts {
|
for i, p in parts {
|
||||||
if p in js_reserved {
|
if p in js.js_reserved {
|
||||||
parts[i] = 'v_$p'
|
parts[i] = 'v_$p'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -547,7 +548,7 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
||||||
g.gen_string_inter_literal(node)
|
g.gen_string_inter_literal(node)
|
||||||
}
|
}
|
||||||
ast.StringLiteral {
|
ast.StringLiteral {
|
||||||
text := node.val.replace("\'", "\\'")
|
text := node.val.replace("'", "\\'")
|
||||||
if g.file.mod.name == 'builtin' {
|
if g.file.mod.name == 'builtin' {
|
||||||
g.write('new ')
|
g.write('new ')
|
||||||
}
|
}
|
||||||
|
@ -988,7 +989,7 @@ fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) {
|
||||||
if name.starts_with('JS.') {
|
if name.starts_with('JS.') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if name in v_types && g.ns.name == 'builtin' {
|
if name in js.v_types && g.ns.name == 'builtin' {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
js_name := g.js_name(name)
|
js_name := g.js_name(name)
|
||||||
|
@ -1368,8 +1369,8 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
both_are_int := int(it.left_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
|
&& int(it.right_type) in table.integer_type_idxs
|
||||||
is_arithmetic := it.op in [token.Kind.plus, .minus, .mul, .div, .mod]
|
is_arithmetic := it.op in [token.Kind.plus, .minus, .mul, .div, .mod]
|
||||||
if is_arithmetic {
|
if is_arithmetic {
|
||||||
g.write('${g.typ(g.greater_typ(it.left_type, it.right_type))}(')
|
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 {
|
if table.string_type_idx in lr {
|
||||||
return table.Type(table.string_type_idx)
|
return table.Type(table.string_type_idx)
|
||||||
}
|
}
|
||||||
should_float := (l in table.integer_type_idxs &&
|
should_float := (l in table.integer_type_idxs && r in table.float_type_idxs)
|
||||||
r in table.float_type_idxs) ||
|
|| (r in table.integer_type_idxs && l in table.float_type_idxs)
|
||||||
(r in table.integer_type_idxs && l in table.float_type_idxs)
|
|
||||||
if should_float {
|
if should_float {
|
||||||
if table.f64_type_idx in lr {
|
if table.f64_type_idx in lr {
|
||||||
return table.Type(table.f64_type_idx)
|
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) {
|
fn (mut g JsGen) gen_type_cast_expr(it ast.CastExpr) {
|
||||||
is_literal := ((it.expr is ast.IntegerLiteral &&
|
is_literal := ((it.expr is ast.IntegerLiteral && it.typ in table.integer_type_idxs)
|
||||||
it.typ in table.integer_type_idxs) ||
|
|| (it.expr is ast.FloatLiteral && it.typ in table.float_type_idxs))
|
||||||
(it.expr is ast.FloatLiteral && it.typ in table.float_type_idxs))
|
|
||||||
typ := g.typ(it.typ)
|
typ := g.typ(it.typ)
|
||||||
if !is_literal {
|
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('new ')
|
||||||
}
|
}
|
||||||
g.write('${typ}(')
|
g.write('${typ}(')
|
||||||
|
|
|
@ -70,7 +70,7 @@ pub fn (mut p Preferences) fill_with_defaults() {
|
||||||
}
|
}
|
||||||
p.find_cc_if_cross_compiling()
|
p.find_cc_if_cross_compiling()
|
||||||
p.ccompiler_type = cc_from_string(p.ccompiler)
|
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_vsh = p.path.ends_with('.vsh')
|
||||||
p.is_script = p.is_vsh || p.path.ends_with('.v') || p.path.ends_with('.vv')
|
p.is_script = p.is_vsh || p.path.ends_with('.v') || p.path.ends_with('.vv')
|
||||||
if p.third_party_option == '' {
|
if p.third_party_option == '' {
|
||||||
|
|
Loading…
Reference in New Issue