Skip to content

Commit

Permalink
mtest: rust: allow parsing doctest output
Browse files Browse the repository at this point in the history
Doctests have a slightly different output compared to what "protocol: rust"
supports:

  running 2 tests
  test ../doctest1.rs - my_func (line 7) ... ignored
  test ../doctest1.rs - (line 3) ... ok

  test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.12s

Add a little more parsing in order to accept this; a simple minded split()
fails to unpack the tuple.  I plan to contribute an extension of the rust
module to invoke doctests, for now this allows running rustdoc --test with
"protocol: 'rust'" and get information about the subtests:

  ▶ 4/8 ../doctest1.rs:my_func:7                     SKIP
  ▶ 4/8 ../doctest1.rs:3                             OK
  4/8 rust_unit_tests:doctests / rust doctest        OK              0.28s   1 subtests passed

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
  • Loading branch information
bonzini authored and dcbaker committed Dec 6, 2024
1 parent f9f69d8 commit 2fd0dac
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 2 deletions.
13 changes: 11 additions & 2 deletions mesonbuild/mtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@
UNENCODABLE_XML_CHR_RANGES = [fr'{chr(low)}-{chr(high)}' for (low, high) in UNENCODABLE_XML_UNICHRS]
UNENCODABLE_XML_CHRS_RE = re.compile('([' + ''.join(UNENCODABLE_XML_CHR_RANGES) + '])')

RUST_TEST_RE = re.compile(r'^test (?!result)(.*) \.\.\. (.*)$')
RUST_DOCTEST_RE = re.compile(r'^(.*?) - (.*? |)\(line (\d+)\)')


def is_windows() -> bool:
platname = platform.system().lower()
Expand Down Expand Up @@ -1157,8 +1160,14 @@ def parse_res(n: int, name: str, result: str) -> TAPParser.Test:

n = 1
async for line in lines:
if line.startswith('test ') and not line.startswith('test result'):
_, name, _, result = line.rstrip().split(' ')
match = RUST_TEST_RE.match(line)
if match:
name, result = match.groups()
doctest = RUST_DOCTEST_RE.match(name)
if doctest:
name = ':'.join((x.rstrip() for x in doctest.groups() if x))
else:
name = name.rstrip()
name = name.replace('::', '.')
t = parse_res(n, name, result)
self.results.append(t)
Expand Down
12 changes: 12 additions & 0 deletions test cases/rust/9 unit tests/doctest1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//! This is a doctest
//!
//! ```
//! assert_eq!(2+2, 4)
//! ```
/// ```ignore
/// this one will be skipped
/// ```
fn my_func()
{
}
13 changes: 13 additions & 0 deletions test cases/rust/9 unit tests/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ test(
suite : ['foo'],
)

rustdoc = find_program('rustdoc', required: false)
if rustdoc.found()
# rustdoc is invoked mostly like rustc. This is a simple example
# where it is easy enough to invoke it by hand.
test(
'rust doctest',
rustdoc,
args : ['--test', '--crate-name', 'doctest1', '--crate-type', 'lib', files('doctest1.rs')],
protocol : 'rust',
suite : ['doctests'],
)
endif

exe = executable('rust_exe', ['test2.rs', 'test.rs'], build_by_default : false)

rust = import('rust')
Expand Down

0 comments on commit 2fd0dac

Please sign in to comment.