diff --git a/cmd/tools/modules/testing/output.v b/cmd/tools/modules/testing/output.v index 72cde635d9..62e733ad2c 100644 --- a/cmd/tools/modules/testing/output.v +++ b/cmd/tools/modules/testing/output.v @@ -30,13 +30,13 @@ pub: pub interface Reporter { mut: - session_start(message string, mut ts TestSession) // called once per test session, in the main thread, suitable for setting up supporting infrastructure. - session_stop(message string, mut ts TestSession) // called once per test session, in the main thread, after everything else, suitable for summaries, creating .xml reports, uploads etc. + session_start(message string, mut ts TestSession) // called once per test session, in the main thread, suitable for setting up supporting infrastructure. + session_stop(message string, mut ts TestSession) // called once per test session, in the main thread, after everything else, suitable for summaries, creating .xml reports, uploads etc. worker_threads_start(files []string, mut ts TestSession) // called once per test session, in the main thread, right before all the worker threads start - worker_threads_finish(mut ts TestSession) // called once per test session, in the main thread, right after all the worker threads finish + worker_threads_finish(mut ts TestSession) // called once per test session, in the main thread, right after all the worker threads finish // report(index int, log_msg LogMessage) // called once per each message, that will be shown (ok/fail/skip etc), only in the reporting thread. - report_stop() // called just once after all messages are processed, only in the reporting thread, but before stop_session. + report_stop() // called just once after all messages are processed, only in the reporting thread, but before stop_session. // // TODO: reconsider, whether the next methods, should be kept for all reporters, or just moved inside the normal reporter, to simplify the interface progress(index int, message string) diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index e2b9fba8b8..c52082463d 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -1400,27 +1400,36 @@ pub fn (mut f Fmt) interface_decl(node ast.InterfaceDecl) { } mut type_align := new_field_align() - mut comment_align := new_field_align() - mut default_expr_align := new_field_align() - mut attr_align := new_field_align() + mut comment_align := new_field_align(use_threshold: true) + mut default_expr_align := new_field_align(use_threshold: true) + mut attr_align := new_field_align(use_threshold: true) mut field_types := []string{cap: node.fields.len} // Calculate the alignments first f.calculate_alignment(node.fields, mut type_align, mut comment_align, mut default_expr_align, mut attr_align, mut field_types) + mut method_comment_align := new_field_align(use_threshold: true) + for method in node.methods { + end_comments := method.comments.filter(it.pos.pos > method.pos.pos) + if end_comments.len > 0 { + method_str := f.table.stringify_fn_decl(&method, f.cur_mod, f.mod2alias, false).all_after_first('fn ') + method_comment_align.add_info(method_str.len, method.pos.line_nr) + } + } + // TODO: alignment, comments, etc. for field in immut_fields { if field.has_prev_newline { f.writeln('') } - f.interface_field(field, type_align.max_len(field.pos.line_nr)) + f.interface_field(field, mut type_align, mut comment_align) } for method in immut_methods { if method.has_prev_newline { f.writeln('') } - f.interface_method(method) + f.interface_method(method, mut method_comment_align) } if mut_fields.len + mut_methods.len > 0 { f.writeln('mut:') @@ -1428,13 +1437,13 @@ pub fn (mut f Fmt) interface_decl(node ast.InterfaceDecl) { if field.has_prev_newline { f.writeln('') } - f.interface_field(field, type_align.max_len(field.pos.line_nr)) + f.interface_field(field, mut type_align, mut comment_align) } for method in mut_methods { if method.has_prev_newline { f.writeln('') } - f.interface_method(method) + f.interface_method(method, mut method_comment_align) } } f.writeln('}\n') @@ -1497,7 +1506,7 @@ pub fn (mut f Fmt) calculate_alignment(fields []ast.StructField, mut type_align } } -pub fn (mut f Fmt) interface_field(field ast.StructField, max_len int) { +pub fn (mut f Fmt) interface_field(field ast.StructField, mut type_align FieldAlign, mut comment_align FieldAlign) { ft := f.no_cur_mod(f.table.type_to_str_using_aliases(field.typ, f.mod2alias)) mut pre_cmts, mut end_cmts, mut next_line_cmts := []ast.Comment{}, []ast.Comment{}, []ast.Comment{} for cmt in field.comments { @@ -1507,11 +1516,9 @@ pub fn (mut f Fmt) interface_field(field ast.StructField, max_len int) { else { end_cmts << cmt } } } - before_len := f.line_len if pre_cmts.len > 0 { f.comments(pre_cmts, level: .indent) } - comments_len := f.line_len - before_len sym := f.table.sym(field.typ) if sym.info is ast.Struct { @@ -1525,10 +1532,12 @@ pub fn (mut f Fmt) interface_field(field ast.StructField, max_len int) { f.write('\t${field.name} ') } if !(sym.info is ast.Struct && sym.info.is_anon) { - f.write(strings.repeat(` `, max_len - field.name.len - comments_len)) + f.write(strings.repeat(` `, type_align.max_len(field.pos.line_nr) - field.name.len)) f.write(ft) } if end_cmts.len > 0 { + f.write(strings.repeat(` `, comment_align.max_len(field.pos.line_nr) - ft.len)) + f.write(' ') f.comments(end_cmts, level: .indent) } else { f.writeln('') @@ -1539,16 +1548,22 @@ pub fn (mut f Fmt) interface_field(field ast.StructField, max_len int) { f.mark_types_import_as_used(field.typ) } -pub fn (mut f Fmt) interface_method(method ast.FnDecl) { +pub fn (mut f Fmt) interface_method(method ast.FnDecl, mut comment_align FieldAlign) { before_comments := method.comments.filter(it.pos.pos < method.pos.pos) end_comments := method.comments.filter(it.pos.pos > method.pos.pos) if before_comments.len > 0 { f.comments(before_comments, level: .indent) } f.write('\t') - f.write(f.table.stringify_fn_decl(&method, f.cur_mod, f.mod2alias, false).all_after_first('fn ')) - f.comments(end_comments, same_line: true, has_nl: false, level: .indent) - f.writeln('') + method_str := f.table.stringify_fn_decl(&method, f.cur_mod, f.mod2alias, false).all_after_first('fn ') + f.write(method_str) + if end_comments.len > 0 { + f.write(strings.repeat(` `, comment_align.max_len(method.pos.line_nr) - method_str.len)) + f.write(' ') + f.comments(end_comments, level: .indent) + } else { + f.writeln('') + } f.comments(method.next_comments, level: .indent) for param in method.params { f.mark_types_import_as_used(param.typ) diff --git a/vlib/v/fmt/tests/interface_declaration_comments_keep.vv b/vlib/v/fmt/tests/interface_declaration_comments_keep.vv index 16e99b0296..d561428f68 100644 --- a/vlib/v/fmt/tests/interface_declaration_comments_keep.vv +++ b/vlib/v/fmt/tests/interface_declaration_comments_keep.vv @@ -1,6 +1,6 @@ pub interface ReaderWriter { read(mut buf []u8) ?int // from Reader - write(buf []u8) ?int // from Writer + write(buf []u8) ?int // from Writer } interface Speaker { @@ -38,10 +38,10 @@ mut: assert_fails u64 test_fn_info &TestFnMetaInfo // filled in by generated code, before .fn_start() is called. start(ntests int) // called before all tests, you can initialise private data here. ntests is the number of test functions in the _test.v file. - finish() // called after all tests are finished, you should free all the private data here. + finish() // called after all tests are finished, you should free all the private data here. // fn_start() // called at the start of each test_ function - fn_pass() // called at the end of each test_ function, with no failed assertion + fn_pass() // called at the end of each test_ function, with no failed assertion fn_error(line_nr int, file string, mod string, fn_name string, errmsg string) // called only for `fn test_xyz() ? { return error('message') }` fn_fail() // called at the end of each test_ function, with a failed assertion, *or* returning an error // diff --git a/vlib/v/preludes/test_runner.c.v b/vlib/v/preludes/test_runner.c.v index 66df23f124..ceecafde6e 100644 --- a/vlib/v/preludes/test_runner.c.v +++ b/vlib/v/preludes/test_runner.c.v @@ -13,29 +13,28 @@ __global test_runner TestRunner interface TestRunner { mut: file_test_info VTestFileMetaInfo // filled in by generated code, before .start() is called. - fn_test_info VTestFnMetaInfo // filled in by generated code, before .fn_start() is called. - fn_assert_passes u64 // reset this to 0 in .fn_start(), increase it in .assert_pass() - fn_passes u64 // increase this in .fn_pass() - fn_fails u64 // increase this in .fn_fails() - total_assert_passes u64 // increase this in .assert_pass() - total_assert_fails u64 // increase this in .assert_fail() + fn_test_info VTestFnMetaInfo // filled in by generated code, before .fn_start() is called. + fn_assert_passes u64 // reset this to 0 in .fn_start(), increase it in .assert_pass() + fn_passes u64 // increase this in .fn_pass() + fn_fails u64 // increase this in .fn_fails() + total_assert_passes u64 // increase this in .assert_pass() + total_assert_fails u64 // increase this in .assert_fail() + start(ntests int) // called before all tests, you can initialise private data here. ntests is the number of test functions in the _test.v file. - finish() // called after all tests are finished, you can print some stats if you want here. - exit_code() int // called right after finish(), it should return the exit code, that the test program will exit with. - // + finish() // called after all tests are finished, you can print some stats if you want here. + exit_code() int // called right after finish(), it should return the exit code, that the test program will exit with. + fn_start() bool // called before the start of each test_ function. Return false, if the function should be skipped. - fn_pass() // called after the end of each test_ function, with NO failed assertion. - fn_fail() // called after the end of each test_ function, with a failed assertion, *or* returning an error. + fn_pass() // called after the end of each test_ function, with NO failed assertion. + fn_fail() // called after the end of each test_ function, with a failed assertion, *or* returning an error. fn_error(line_nr int, file string, mod string, fn_name string, errmsg string) // called only for `fn test_xyz() ? { return error('message') }`, before .fn_fail() is called. - // + assert_pass(i &VAssertMetaInfo) // called after each `assert true`. assert_fail(i &VAssertMetaInfo) // called after each `assert false`. - // + free() // you should free all the private data of your runner here. } -// - struct VTestFileMetaInfo { file string tests int @@ -57,8 +56,6 @@ fn (i &VTestFileMetaInfo) free() { } } -// - struct VTestFnMetaInfo { name string mod string @@ -85,8 +82,6 @@ fn (i &VTestFnMetaInfo) free() { } } -// - @[typedef] pub struct C.main__TestRunner { mut: