diff options
author | Jussi Pakkanen <jpakkane@gmail.com> | 2021-01-06 00:05:48 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-06 00:05:48 +0000 |
commit | c9d9dacdbc9fad31f00f871b24ec6b99a611ff5e (patch) | |
tree | 07ea0773d50c41e3e87081e1be6095a7788da9df | |
parent | f9dd75f213b1c3a7ab397133b6a157ddba511d90 (diff) | |
parent | 827fa95de1c619b51457c5a04297b6ce9adc2177 (diff) | |
download | meson-c9d9dacdbc9fad31f00f871b24ec6b99a611ff5e.zip meson-c9d9dacdbc9fad31f00f871b24ec6b99a611ff5e.tar.gz meson-c9d9dacdbc9fad31f00f871b24ec6b99a611ff5e.tar.bz2 |
Merge pull request #7860 from dcbaker/wip/2020-10/rust-module
Add a rust module
-rw-r--r-- | CODEOWNERS | 1 | ||||
-rw-r--r-- | docs/markdown/Reference-manual.md | 1 | ||||
-rw-r--r-- | docs/markdown/Rust-module.md | 35 | ||||
-rw-r--r-- | docs/markdown/_Sidebar.md | 1 | ||||
-rw-r--r-- | docs/markdown/snippets/rust_test_format_support.md | 4 | ||||
-rw-r--r-- | docs/markdown/snippets/unstable-rust-module.md | 4 | ||||
-rw-r--r-- | docs/sitemap.txt | 11 | ||||
-rw-r--r-- | docs/theme/extra/templates/navbar_links.html | 45 | ||||
-rw-r--r-- | mesonbuild/backend/backends.py | 5 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 19 | ||||
-rw-r--r-- | mesonbuild/modules/unstable_rust.py | 137 | ||||
-rw-r--r-- | mesonbuild/mtest.py | 73 | ||||
-rwxr-xr-x | run_mypy.py | 1 | ||||
-rw-r--r-- | test cases/rust/9 unit tests/meson.build | 43 | ||||
-rw-r--r-- | test cases/rust/9 unit tests/test.rs | 24 | ||||
-rw-r--r-- | test cases/rust/9 unit tests/test2.rs | 11 |
16 files changed, 364 insertions, 51 deletions
@@ -2,6 +2,7 @@ /mesonbuild/modules/pkgconfig.py @xclaesse /mesonbuild/modules/cmake.py @mensinda /mesonbuild/modules/unstable_external_project.py @xclaesse +/mesonbuild/modules/unstable_rust.py @dcbaker /mesonbuild/ast/ @mensinda /mesonbuild/cmake/ @mensinda /mesonbuild/compilers/ @dcbaker diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 924047c..525c3da 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -1745,6 +1745,7 @@ test(..., env: nomalloc, ...) to record the outcome of the test). - `tap`: [Test Anything Protocol](https://www.testanything.org/). - `gtest` *(since 0.55.0)*: for Google Tests. + - `rust` *(since 0.56.0)*: for native rust tests - `priority` *(since 0.52.0)*:specifies the priority of a test. Tests with a higher priority are *started* before tests with a lower priority. diff --git a/docs/markdown/Rust-module.md b/docs/markdown/Rust-module.md new file mode 100644 index 0000000..0fdba94 --- /dev/null +++ b/docs/markdown/Rust-module.md @@ -0,0 +1,35 @@ +--- +short-description: Rust language integration module +authors: + - name: Dylan Baker + email: dylan@pnwbakers.com + years: [2020] +... + +# Unstable Rust module + +*(new in 0.57.0)* + +**Note** Unstable modules make no backwards compatible API guarantees. + +The rust module provides helper to integrate rust code into meson. The goal +is to make using rust in meson more pleasant, while still remaining mesonic, +this means that it attempts to make rust work more like meson, rather than +meson work more like rust. + +## Functions + +### test(name: string, target: library | executable, dependencies: []Dependency) + +This function creates a new rust unittest target from an existing rust based +target, which may be a library or executable. It does this by copying the +sources and arguments passed to the original target and adding the `--test` +argument to the compilation, then creates a new test target which calls that +executable, using the rust test protocol. + +This accepts all of the keyword arguments as the +[`test`](Reference-manual.md#test) function except `protocol`, it will set +that automatically. + +Additional, test only dependencies may be passed via the dependencies +argument. diff --git a/docs/markdown/_Sidebar.md b/docs/markdown/_Sidebar.md index 2637d68..0ca1762 100644 --- a/docs/markdown/_Sidebar.md +++ b/docs/markdown/_Sidebar.md @@ -12,3 +12,4 @@ * [gnome](Gnome-module.md) * [i18n](i18n-module.md) * [pkgconfig](Pkgconfig-module.md) +* [rust](Rust-module.md) diff --git a/docs/markdown/snippets/rust_test_format_support.md b/docs/markdown/snippets/rust_test_format_support.md new file mode 100644 index 0000000..69e9aa1 --- /dev/null +++ b/docs/markdown/snippets/rust_test_format_support.md @@ -0,0 +1,4 @@ +## Meson test() now accepts `protocol : 'rust'` + +This allows native rust tests to be run and parsed by meson, simply set the +protocol to `rust` and meson takes care of the rest. diff --git a/docs/markdown/snippets/unstable-rust-module.md b/docs/markdown/snippets/unstable-rust-module.md new file mode 100644 index 0000000..15a7ecb --- /dev/null +++ b/docs/markdown/snippets/unstable-rust-module.md @@ -0,0 +1,4 @@ +## Untable Rust module + +A new unstable module has been added to make using rust with meson easier. +Currently it adds a single function to ease defining rust tests. diff --git a/docs/sitemap.txt b/docs/sitemap.txt index 4cae9fe..3164440 100644 --- a/docs/sitemap.txt +++ b/docs/sitemap.txt @@ -34,24 +34,25 @@ index.md Disabler.md Modules.md CMake-module.md + Cuda-module.md Dlang-module.md + External-Project-module.md Fs-module.md Gnome-module.md Hotdoc-module.md - i18n-module.md Icestorm-module.md + Keyval-module.md Pkgconfig-module.md - Python-module.md Python-3-module.md + Python-module.md Qt4-module.md Qt5-module.md RPM-module.md + Rust-module.md Simd-module.md SourceSet-module.md Windows-module.md - Cuda-module.md - Keyval-module.md - External-Project-module.md + i18n-module.md Java.md Vala.md D.md diff --git a/docs/theme/extra/templates/navbar_links.html b/docs/theme/extra/templates/navbar_links.html index 832bd2c..8df082f 100644 --- a/docs/theme/extra/templates/navbar_links.html +++ b/docs/theme/extra/templates/navbar_links.html @@ -5,28 +5,29 @@ Modules <span class="caret"></span> </a> <ul class="dropdown-menu" id="modules-menu"> - @for tup in ( \ - ("CMake-module.html","CMake"), \ - ("Cuda-module.html","CUDA"), \ - ("Dlang-module.html","Dlang"), \ - ("Fs-module.html","Filesystem"), \ - ("Gnome-module.html","GNOME"), \ - ("Hotdoc-module.html","Hotdoc"), \ - ("i18n-module.html","i18n"), \ - ("Icestorm-module.html","Icestorm"), \ - ("Keyval-module.html","Keyval"), \ - ("Pkgconfig-module.html","Pkgconfig"), \ - ("Python-module.html","Python"), \ - ("Python-3-module.html","Python 3"), \ - ("Qt4-module.html","Qt4"), \ - ("Qt5-module.html","Qt5"), \ - ("RPM-module.html","RPM"), \ - ("SourceSet-module.html","SourceSet"), \ - ("Windows-module.html","Windows")): - <li> - <a href="@tup[0]">@tup[1]</a> - </li> - @end + @for tup in [ \ + ("CMake-module.html","CMake"), \ + ("Cuda-module.html","CUDA"), \ + ("Dlang-module.html","Dlang"), \ + ("Fs-module.html","Filesystem"), \ + ("Gnome-module.html","GNOME"), \ + ("Hotdoc-module.html","Hotdoc"), \ + ("Icestorm-module.html","Icestorm"), \ + ("Keyval-module.html","Keyval"), \ + ("Pkgconfig-module.html","Pkgconfig"), \ + ("Python-3-module.html","Python 3"), \ + ("Python-module.html","Python"), \ + ("Qt4-module.html","Qt4"), \ + ("Qt5-module.html","Qt5"), \ + ("RPM-module.html","RPM"), \ + ("Rust-module.html","Rust"), \ + ("SourceSet-module.html","SourceSet"), \ + ("Windows-module.html","Windows"), \ + ("i18n-module.html","i18n")]: + <li> + <a href="@tup[0]">@tup[1]</a> + </li> + @end </ul> </li> \ diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index ec3aca6..9bb870c 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -46,6 +46,7 @@ class TestProtocol(enum.Enum): EXITCODE = 0 TAP = 1 GTEST = 2 + RUST = 3 @classmethod def from_str(cls, string: str) -> 'TestProtocol': @@ -55,6 +56,8 @@ class TestProtocol(enum.Enum): return cls.TAP elif string == 'gtest': return cls.GTEST + elif string == 'rust': + return cls.RUST raise MesonException('unknown test format {}'.format(string)) def __str__(self) -> str: @@ -62,6 +65,8 @@ class TestProtocol(enum.Enum): return 'exitcode' elif self is self.GTEST: return 'gtest' + elif self is self.RUST: + return 'rust' return 'tap' diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index c20c205..6e04235 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -2593,6 +2593,8 @@ class Interpreter(InterpreterBase): self.process_new_values(v.sources[0]) elif isinstance(v, InstallDir): self.build.install_dirs.append(v) + elif isinstance(v, Test): + self.build.tests.append(v) elif hasattr(v, 'held_object'): pass elif isinstance(v, (int, str, bool, Disabler)): @@ -4120,7 +4122,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self env = env.held_object return env - def add_test(self, node, args, kwargs, is_base_test): + def make_test(self, node: mparser.BaseNode, args: T.List, kwargs: T.Dict[str, T.Any]): if len(args) != 2: raise InterpreterException('test expects 2 arguments, {} given'.format(len(args))) name = args[0] @@ -4159,8 +4161,8 @@ This will become a hard error in the future.''' % kwargs['input'], location=self if not isinstance(timeout, int): raise InterpreterException('Timeout must be an integer.') protocol = kwargs.get('protocol', 'exitcode') - if protocol not in {'exitcode', 'tap', 'gtest'}: - raise InterpreterException('Protocol must be "exitcode", "tap", or "gtest".') + if protocol not in {'exitcode', 'tap', 'gtest', 'rust'}: + raise InterpreterException('Protocol must be one of "exitcode", "tap", "gtest", or "rust".') suite = [] prj = self.subproject if self.is_subproject() else self.build.project_name for s in mesonlib.stringlistify(kwargs.get('suite', '')): @@ -4174,14 +4176,17 @@ This will become a hard error in the future.''' % kwargs['input'], location=self priority = kwargs.get('priority', 0) if not isinstance(priority, int): raise InterpreterException('Keyword argument priority must be an integer.') - t = Test(name, prj, suite, exe.held_object, depends, par, cmd_args, - env, should_fail, timeout, workdir, protocol, priority) + return Test(name, prj, suite, exe.held_object, depends, par, cmd_args, + env, should_fail, timeout, workdir, protocol, priority) + + def add_test(self, node: mparser.BaseNode, args: T.List, kwargs: T.Dict[str, T.Any], is_base_test: bool): + t = self.make_test(node, args, kwargs) if is_base_test: self.build.tests.append(t) - mlog.debug('Adding test', mlog.bold(name, True)) + mlog.debug('Adding test', mlog.bold(t.name, True)) else: self.build.benchmarks.append(t) - mlog.debug('Adding benchmark', mlog.bold(name, True)) + mlog.debug('Adding benchmark', mlog.bold(t.name, True)) @FeatureNewKwargs('install_headers', '0.47.0', ['install_mode']) @permittedKwargs(permitted_kwargs['install_headers']) diff --git a/mesonbuild/modules/unstable_rust.py b/mesonbuild/modules/unstable_rust.py new file mode 100644 index 0000000..72b5217 --- /dev/null +++ b/mesonbuild/modules/unstable_rust.py @@ -0,0 +1,137 @@ +# Copyright © 2020 Intel Corporation + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing as T + +from . import ExtensionModule, ModuleReturnValue +from .. import mlog +from ..build import BuildTarget, Executable, InvalidArguments +from ..dependencies import Dependency, ExternalLibrary +from ..interpreter import ExecutableHolder, permitted_kwargs +from ..interpreterbase import InterpreterException, permittedKwargs, FeatureNew +from ..mesonlib import stringlistify, unholder, listify + +if T.TYPE_CHECKING: + from ..interpreter import ModuleState, Interpreter + + +class RustModule(ExtensionModule): + + """A module that holds helper functions for rust.""" + + @FeatureNew('rust module', '0.57.0') + def __init__(self, interpreter: 'Interpreter') -> None: + super().__init__(interpreter) + + @permittedKwargs(permitted_kwargs['test'] | {'dependencies'} ^ {'protocol'}) + def test(self, state: 'ModuleState', args: T.List, kwargs: T.Dict[str, T.Any]) -> ModuleReturnValue: + """Generate a rust test target from a given rust target. + + Rust puts it's unitests inside it's main source files, unlike most + languages that put them in external files. This means that normally + you have to define two seperate targets with basically the same + arguments to get tests: + + ```meson + rust_lib_sources = [...] + rust_lib = static_library( + 'rust_lib', + rust_lib_sources, + ) + + rust_lib_test = executable( + 'rust_lib_test', + rust_lib_sources, + rust_args : ['--test'], + ) + + test( + 'rust_lib_test', + rust_lib_test, + protocol : 'rust', + ) + ``` + + This is all fine, but not very DRY. This method makes it much easier + to define rust tests: + + ```meson + rust = import('unstable-rust') + + rust_lib = static_library( + 'rust_lib', + [sources], + ) + + rust.test('rust_lib_test', rust_lib) + ``` + """ + if len(args) != 2: + raise InterpreterException('rustmod.test() takes exactly 2 positional arguments') + name: str = args[0] + if not isinstance(name, str): + raise InterpreterException('First positional argument to rustmod.test() must be a string') + base_target: BuildTarget = unholder(args[1]) + if not isinstance(base_target, BuildTarget): + raise InterpreterException('Second positional argument to rustmod.test() must be a library or executable') + if not base_target.get_using_rustc(): + raise InterpreterException('Second positional argument to rustmod.test() must be a rust based target') + extra_args = stringlistify(kwargs.get('args', [])) + + # Delete any arguments we don't want passed + if '--test' in extra_args: + mlog.warning('Do not add --test to rustmod.test arguments') + extra_args.remove('--test') + if '--format' in extra_args: + mlog.warning('Do not add --format to rustmod.test arguments') + i = extra_args.index('--format') + # Also delete the argument to --format + del extra_args[i + 1] + del extra_args[i] + for i, a in enumerate(extra_args): + if a.startswith('--format='): + del extra_args[i] + break + + dependencies = unholder(listify(kwargs.get('dependencies', []))) + for d in dependencies: + if not isinstance(d, (Dependency, ExternalLibrary)): + raise InvalidArguments('dependencies must be a dependency or external library') + + kwargs['args'] = extra_args + ['--test', '--format', 'pretty'] + kwargs['protocol'] = 'rust' + + new_target_kwargs = base_target.kwargs.copy() + # Don't mutate the shallow copied list, instead replace it with a new + # one + new_target_kwargs['rust_args'] = new_target_kwargs.get('rust_args', []) + ['--test'] + new_target_kwargs['install'] = False + new_target_kwargs['dependencies'] = new_target_kwargs.get('dependencies', []) + dependencies + + new_target = Executable( + name, base_target.subdir, state.subproject, + base_target.for_machine, base_target.sources, + base_target.objects, base_target.environment, + new_target_kwargs + ) + + e = ExecutableHolder(new_target, self.interpreter) + test = self.interpreter.make_test( + self.interpreter.current_node, [name, e], kwargs) + + return ModuleReturnValue([], [e, test]) + + +def initialize(*args: T.List, **kwargs: T.Dict) -> RustModule: + return RustModule(*args, **kwargs) # type: ignore diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py index 7e3ebea..9db271e 100644 --- a/mesonbuild/mtest.py +++ b/mesonbuild/mtest.py @@ -595,17 +595,17 @@ class JunitBuilder(TestLogger): 'testsuite', name=suitename, tests=str(len(test.results)), - errors=str(sum(1 for r in test.results if r in + errors=str(sum(1 for r in test.results.values() if r in {TestResult.INTERRUPT, TestResult.ERROR})), - failures=str(sum(1 for r in test.results if r in + failures=str(sum(1 for r in test.results.values() if r in {TestResult.FAIL, TestResult.UNEXPECTEDPASS, TestResult.TIMEOUT})), - skipped=str(sum(1 for r in test.results if r is TestResult.SKIP)), + skipped=str(sum(1 for r in test.results.values() if r is TestResult.SKIP)), ) - for i, result in enumerate(test.results): + for i, result in test.results.items(): # Both name and classname are required. Set them both to the # number of the test in a TAP test, as TAP doesn't give names. - testcase = et.SubElement(suite, 'testcase', name=str(i), classname=str(i)) + testcase = et.SubElement(suite, 'testcase', name=i, classname=i) if result is TestResult.SKIP: et.SubElement(testcase, 'skipped') elif result is TestResult.ERROR: @@ -666,6 +666,28 @@ class JunitBuilder(TestLogger): tree.write(f, encoding='utf-8', xml_declaration=True) +def parse_rust_test(stdout: str) -> T.Dict[str, TestResult]: + """Parse the output of rust tests.""" + res = {} # type; T.Dict[str, TestResult] + + def parse_res(res: str) -> TestResult: + if res == 'ok': + return TestResult.OK + elif res == 'ignored': + return TestResult.SKIP + elif res == 'FAILED': + return TestResult.FAIL + raise MesonException('Unsupported output from rust test: {}'.format(res)) + + for line in stdout.splitlines(): + if line.startswith('test ') and not line.startswith('test result'): + _, name, _, result = line.split(' ') + name = name.replace('::', '.') + res[name] = parse_res(result) + + return res + + class TestRun: TEST_NUM = 0 @@ -675,7 +697,7 @@ class TestRun: self.test = test self._num = None # type: T.Optional[int] self.name = name - self.results = list() # type: T.List[TestResult] + self.results: T.Dict[str, TestResult] = {} self.returncode = 0 self.starttime = None # type: T.Optional[float] self.duration = None # type: T.Optional[float] @@ -713,23 +735,23 @@ class TestRun: res = TestResult.EXPECTEDFAIL if bool(returncode) else TestResult.UNEXPECTEDPASS else: res = TestResult.FAIL if bool(returncode) else TestResult.OK - self.complete(res, [], returncode, stdo, stde, cmd, **kwargs) + self.complete(res, {}, returncode, stdo, stde, cmd, **kwargs) def complete_tap(self, returncode: int, stdo: str, stde: str, cmd: T.List[str]) -> None: res = None # type: T.Optional[TestResult] - results = [] # type: T.List[TestResult] + results = {} # type: T.Dict[str, TestResult] failed = False - for i in TAPParser(io.StringIO(stdo)).parse(): + for n, i in enumerate(TAPParser(io.StringIO(stdo)).parse()): if isinstance(i, TAPParser.Bailout): - results.append(TestResult.ERROR) + results[str(n)] = TestResult.ERROR failed = True elif isinstance(i, TAPParser.Test): - results.append(i.result) + results[str(n)] = i.result if i.result not in {TestResult.OK, TestResult.EXPECTEDFAIL, TestResult.SKIP}: failed = True elif isinstance(i, TAPParser.Error): - results.append(TestResult.ERROR) + results[str(n)] = TestResult.ERROR stde += '\nTAP parsing error: ' + i.message failed = True @@ -739,7 +761,7 @@ class TestRun: if res is None: # Now determine the overall result of the test based on the outcome of the subcases - if all(t is TestResult.SKIP for t in results): + if all(t is TestResult.SKIP for t in results.values()): # This includes the case where num_tests is zero res = TestResult.SKIP elif self.should_fail: @@ -749,6 +771,21 @@ class TestRun: self.complete(res, results, returncode, stdo, stde, cmd) + def complete_rust(self, returncode: int, stdo: str, stde: str, cmd: T.List[str]) -> None: + results = parse_rust_test(stdo) + + failed = TestResult.FAIL in results.values() + # Now determine the overall result of the test based on the outcome of the subcases + if all(t is TestResult.SKIP for t in results.values()): + # This includes the case where num_tests is zero + res = TestResult.SKIP + elif self.should_fail: + res = TestResult.EXPECTEDFAIL if failed else TestResult.UNEXPECTEDPASS + else: + res = TestResult.FAIL if failed else TestResult.OK + + self.complete(res, results, returncode, stdo, stde, cmd) + @property def num(self) -> int: if self._num is None: @@ -756,13 +793,13 @@ class TestRun: self._num = TestRun.TEST_NUM return self._num - def complete(self, res: TestResult, results: T.List[TestResult], + def complete(self, res: TestResult, results: T.Dict[str, TestResult], returncode: int, stdo: T.Optional[str], stde: T.Optional[str], cmd: T.List[str], *, junit: T.Optional[et.ElementTree] = None) -> None: assert isinstance(res, TestResult) self.res = res - self.results = results + self.results = results # May be empty self.returncode = returncode self.duration = time.time() - self.starttime self.stdo = stdo @@ -906,7 +943,7 @@ class SingleTestRunner: self.runobj.start() if cmd is None: skip_stdout = 'Not run because can not execute cross compiled binaries.' - self.runobj.complete(TestResult.SKIP, [], GNU_SKIP_RETURNCODE, skip_stdout, None, None) + self.runobj.complete(TestResult.SKIP, {}, GNU_SKIP_RETURNCODE, skip_stdout, None, None) else: wrap = TestHarness.get_wrapper(self.options) if self.options.gdb: @@ -1063,12 +1100,14 @@ class SingleTestRunner: stdo = "" stde = additional_error if result: - self.runobj.complete(result, [], returncode, stdo, stde, cmd) + self.runobj.complete(result, {}, returncode, stdo, stde, cmd) else: if self.test.protocol is TestProtocol.EXITCODE: self.runobj.complete_exitcode(returncode, stdo, stde, cmd) elif self.test.protocol is TestProtocol.GTEST: self.runobj.complete_gtest(returncode, stdo, stde, cmd) + elif self.test.protocol is TestProtocol.RUST: + return self.runobj.complete_rust(returncode, stdo, stde, cmd) else: if self.options.verbose: print(stdo, end='') diff --git a/run_mypy.py b/run_mypy.py index 01fa9ff..888403c 100755 --- a/run_mypy.py +++ b/run_mypy.py @@ -29,6 +29,7 @@ modules = [ 'mesonbuild/mintro.py', 'mesonbuild/mlog.py', 'mesonbuild/modules/fs.py', + 'mesonbuild/modules/unstable_rust.py', 'mesonbuild/mparser.py', 'mesonbuild/msetup.py', 'mesonbuild/mtest.py', diff --git a/test cases/rust/9 unit tests/meson.build b/test cases/rust/9 unit tests/meson.build new file mode 100644 index 0000000..b649abb --- /dev/null +++ b/test cases/rust/9 unit tests/meson.build @@ -0,0 +1,43 @@ +project('rust unit tests', 'rust') + +t = executable( + 'rust_test', + ['test.rs'], + rust_args : ['--test'], +) + +test( + 'rust test (should fail)', + t, + protocol : 'rust', + suite : ['foo'], + should_fail : true, +) + +test( + 'rust test (should pass)', + t, + args : ['--skip', 'test_add_intentional_fail'], + protocol : 'rust', + suite : ['foo'], +) + + +test( + 'rust test (should skip)', + t, + args : ['--skip', 'test_add'], + protocol : 'rust', + suite : ['foo'], +) + +exe = executable('rust_exe', ['test2.rs', 'test.rs']) + +rust = import('unstable-rust') +rust.test('rust_test_from_exe', exe, should_fail : true) + +lib = static_library('rust_static', ['test.rs']) +rust.test('rust_test_from_static', lib, args: ['--skip', 'test_add_intentional_fail']) + +lib = shared_library('rust_shared', ['test.rs']) +rust.test('rust_test_from_shared', lib, args: ['--skip', 'test_add_intentional_fail']) diff --git a/test cases/rust/9 unit tests/test.rs b/test cases/rust/9 unit tests/test.rs new file mode 100644 index 0000000..0225be5 --- /dev/null +++ b/test cases/rust/9 unit tests/test.rs @@ -0,0 +1,24 @@ +pub fn add(a: i32, b: i32) -> i32 { + return a + b; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_add() { + assert_eq!(add(1, 2), 3); + } + + #[test] + fn test_add_intentional_fail() { + assert_eq!(add(1, 2), 5); + } + + #[test] + #[ignore] + fn test_add_intentional_fail2() { + assert_eq!(add(1, 7), 5); + } +} diff --git a/test cases/rust/9 unit tests/test2.rs b/test cases/rust/9 unit tests/test2.rs new file mode 100644 index 0000000..9623c7c --- /dev/null +++ b/test cases/rust/9 unit tests/test2.rs @@ -0,0 +1,11 @@ +mod test; +use std::env; + +fn main() { + let args: Vec<String> = env::args().collect(); + let first = args[1].parse::<i32>().expect("Invliad value for first argument."); + let second = args[2].parse::<i32>().expect("Invliad value for second argument."); + + let new = test::add(first, second); + println!("New value: {}", new); +} |