Skip to main content

test_r/
lib.rs

1pub use test_r_macro::add_test;
2pub use test_r_macro::always_capture;
3pub use test_r_macro::always_ensure_time;
4pub use test_r_macro::always_report_time;
5pub use test_r_macro::bench;
6pub use test_r_macro::define_matrix_dimension;
7pub use test_r_macro::flaky;
8pub use test_r_macro::hosted_rpc;
9pub use test_r_macro::ignore_detached_panics;
10pub use test_r_macro::inherit_test_dep;
11pub use test_r_macro::matrix_suite;
12pub use test_r_macro::never_capture;
13pub use test_r_macro::never_ensure_time;
14pub use test_r_macro::never_report_time;
15pub use test_r_macro::non_flaky;
16pub use test_r_macro::sequential;
17pub use test_r_macro::sequential_suite;
18pub use test_r_macro::tag;
19pub use test_r_macro::tag_suite;
20pub use test_r_macro::test;
21pub use test_r_macro::test_dep;
22pub use test_r_macro::test_gen;
23pub use test_r_macro::timeout;
24pub use test_r_macro::timeout_suite;
25pub use test_r_macro::uses_test_r as enable;
26
27#[cfg(feature = "tokio")]
28pub use test_r_core::bench::AsyncBencher;
29pub use test_r_core::bench::Bencher;
30#[cfg(feature = "tokio")]
31pub use test_r_core::spawn::spawn;
32pub use test_r_core::spawn::spawn_thread;
33
34pub use test_r_core::internal::{
35    AsyncHostedDep, AsyncHostedRpcDep, CloneableDep, HostedDep, HostedRpcDep,
36};
37pub use test_r_core::worker_index;
38
39pub mod core {
40    use std::time::Duration;
41    pub use test_r_core::internal::{
42        AsyncHostedDep, AsyncHostedRpcDep, AsyncHostedRpcDispatcher, CaptureControl,
43        CloneableCodec, CloneableDep, DepScope, DependencyConstructor, DependencyView,
44        DetachedPanicPolicy, DynamicTestRegistration, FailureCause, FlakinessControl,
45        GeneratedTest, HostedBothShared, HostedDep, HostedRpcChannel, HostedRpcDep,
46        HostedRpcDispatcher, HostedRpcError, HostedRpcOwnerCell, HostedRpcTransport,
47        InProcessHostedRpcTransport, MatrixCase, ReportTimeControl, RpcFactory, ShouldPanic,
48        TestFunction, TestGeneratorFunction, TestProperties, TestReturnValue, TestType,
49        WorkerReconstructor,
50    };
51    pub use test_r_core::*;
52
53    #[allow(clippy::too_many_arguments)]
54    pub fn register_test(
55        name: &str,
56        module_path: &str,
57        is_ignored: bool,
58        should_panic: ShouldPanic,
59        test_type: TestType,
60        timeout: Option<Duration>,
61        flakiness_control: FlakinessControl,
62        capture_control: CaptureControl,
63        tags: Vec<String>,
64        report_time_control: ReportTimeControl,
65        ensure_time_control: ReportTimeControl,
66        detached_panic_policy: DetachedPanicPolicy,
67        run: TestFunction,
68        dependencies: Option<Vec<String>>,
69    ) {
70        let (crate_name, module_path) = split_module_path(module_path);
71
72        internal::REGISTERED_TESTS
73            .lock()
74            .unwrap()
75            .push(internal::RegisteredTest {
76                name: name.to_string(),
77                crate_name,
78                module_path,
79                run,
80                props: internal::TestProperties {
81                    should_panic,
82                    test_type,
83                    timeout,
84                    flakiness_control,
85                    capture_control,
86                    report_time_control,
87                    ensure_time_control,
88                    tags,
89                    is_ignored,
90                    detached_panic_policy,
91                },
92                dependencies,
93            });
94    }
95
96    pub fn register_dependency_constructor(
97        name: &str,
98        module_path: &str,
99        cons: DependencyConstructor,
100        dependencies: Vec<String>,
101    ) {
102        register_dependency_constructor_with_scope(
103            name,
104            module_path,
105            cons,
106            dependencies,
107            DepScope::Shared,
108            None,
109            None,
110            None,
111            None,
112        )
113    }
114
115    #[allow(clippy::too_many_arguments)]
116    pub fn register_dependency_constructor_with_scope(
117        name: &str,
118        module_path: &str,
119        cons: DependencyConstructor,
120        dependencies: Vec<String>,
121        scope: DepScope,
122        worker_fn: Option<WorkerReconstructor>,
123        cloneable_codec: Option<CloneableCodec>,
124        hosted_codec: Option<CloneableCodec>,
125        rpc_factory: Option<RpcFactory>,
126    ) {
127        register_dependency_constructor_with_scope_and_companions(
128            name,
129            module_path,
130            cons,
131            dependencies,
132            scope,
133            worker_fn,
134            cloneable_codec,
135            hosted_codec,
136            rpc_factory,
137            Vec::new(),
138        )
139    }
140
141    /// Registers a dependency constructor that must be retained
142    /// together with the listed `companions` during pruning. See
143    /// [`internal::RegisteredDependency::companions`] for the planner
144    /// semantics. All other parameters behave exactly as
145    /// [`register_dependency_constructor_with_scope`].
146    #[allow(clippy::too_many_arguments)]
147    pub fn register_dependency_constructor_with_scope_and_companions(
148        name: &str,
149        module_path: &str,
150        cons: DependencyConstructor,
151        dependencies: Vec<String>,
152        scope: DepScope,
153        worker_fn: Option<WorkerReconstructor>,
154        cloneable_codec: Option<CloneableCodec>,
155        hosted_codec: Option<CloneableCodec>,
156        rpc_factory: Option<RpcFactory>,
157        companions: Vec<String>,
158    ) {
159        let (crate_name, module_path) = split_module_path(module_path);
160
161        internal::REGISTERED_DEPENDENCY_CONSTRUCTORS
162            .lock()
163            .unwrap()
164            .push(internal::RegisteredDependency {
165                name: name.to_string(),
166                crate_name,
167                module_path,
168                constructor: cons,
169                dependencies,
170                scope,
171                worker_fn,
172                cloneable_codec,
173                hosted_codec,
174                rpc_factory,
175                companions,
176            });
177    }
178
179    pub fn register_suite_sequential(name: &str, module_path: &str) {
180        let (crate_name, module_path) = split_module_path(module_path);
181
182        internal::REGISTERED_TESTSUITE_PROPS.lock().unwrap().push(
183            internal::RegisteredTestSuiteProperty::Sequential {
184                name: name.to_string(),
185                crate_name,
186                module_path,
187            },
188        );
189    }
190
191    pub fn register_suite_timeout(name: &str, module_path: &str, timeout: Duration) {
192        let (crate_name, module_path) = split_module_path(module_path);
193
194        internal::REGISTERED_TESTSUITE_PROPS.lock().unwrap().push(
195            internal::RegisteredTestSuiteProperty::Timeout {
196                name: name.to_string(),
197                crate_name,
198                module_path,
199                timeout,
200            },
201        );
202    }
203
204    pub fn register_suite_tag(name: &str, module_path: &str, tag: String) {
205        let (crate_name, module_path) = split_module_path(module_path);
206
207        internal::REGISTERED_TESTSUITE_PROPS.lock().unwrap().push(
208            internal::RegisteredTestSuiteProperty::Tag {
209                name: name.to_string(),
210                crate_name,
211                module_path,
212                tag,
213            },
214        );
215    }
216
217    /// Register a runtime matrix-suite dimension (Strategy B). Every registered
218    /// test under `<crate>::<module_path>::<name>` whose `dependencies` contain
219    /// `dep_name` is multiplied into one test per `case` at suite-property
220    /// application time. `cases` is typically produced by calling the
221    /// `test_r_get_dep_tags_<dim>()` helper that `define_matrix_dimension!`
222    /// emits, dropping the per-case getter (the multiplied test reuses its own
223    /// compiled getter, with the dependency view aliased to the case's tagged
224    /// dep name).
225    pub fn register_suite_matrix(
226        name: &str,
227        module_path: &str,
228        dep_name: String,
229        cases: Vec<internal::MatrixCase>,
230    ) {
231        let (crate_name, module_path) = split_module_path(module_path);
232
233        internal::REGISTERED_TESTSUITE_PROPS.lock().unwrap().push(
234            internal::RegisteredTestSuiteProperty::Matrix {
235                name: name.to_string(),
236                crate_name,
237                module_path,
238                dep_name,
239                cases,
240            },
241        );
242    }
243
244    pub fn register_test_generator(
245        name: &str,
246        module_path: &str,
247        is_ignored: bool,
248        run: TestGeneratorFunction,
249    ) {
250        let (crate_name, module_path) = split_module_path(module_path);
251
252        internal::REGISTERED_TEST_GENERATORS.lock().unwrap().push(
253            internal::RegisteredTestGenerator {
254                name: name.to_string(),
255                crate_name,
256                module_path,
257                run,
258                is_ignored,
259            },
260        );
261    }
262
263    fn split_module_path(module_path: &str) -> (String, String) {
264        let (crate_name, module_path) =
265            if let Some((crate_name, module_path)) = module_path.split_once("::") {
266                (crate_name.to_string(), module_path.to_string())
267            } else {
268                (module_path.to_string(), String::new())
269            };
270        (crate_name, module_path)
271    }
272}
273
274pub use ::ctor;
275
276/// **Hidden macro-support helper.** Runtime-flavor selector for code
277/// emitted by `#[test_r::test_dep]` (specifically the
278/// `worker = both(Trait)` lowering) that needs to pick a different
279/// expression depending on whether the `test-r` crate was compiled
280/// with its `tokio` feature.
281///
282/// The proc macro itself cannot read the user crate's cargo features,
283/// so we route the runtime-flavor choice through this `macro_rules!`
284/// definition in `test-r`. Because `#[cfg(feature = "tokio")]` on a
285/// `macro_rules!` evaluates at the *defining* crate's compile time,
286/// the variant of the macro that gets exported reflects whether
287/// `test-r/tokio` was enabled — exactly the same toggle that decides
288/// which `test-r-core` helper variants are linked.
289///
290/// The expected invocation shape is:
291///
292/// ```ignore
293/// test_r::__test_r_select_runtime! {
294///     sync { /* tokens used when the sync runtime is active */ }
295///     tokio { /* tokens used when the tokio runtime is active */ }
296/// }
297/// ```
298///
299/// Each branch is a brace-delimited token group; the macro expands to
300/// the contents of the matching branch with no extra braces.
301#[cfg(feature = "tokio")]
302#[doc(hidden)]
303#[macro_export]
304macro_rules! __test_r_select_runtime {
305    ( sync { $($_sync:tt)* } tokio { $($tokio:tt)* } ) => {
306        $($tokio)*
307    };
308}
309
310/// Sync-runtime variant of [`__test_r_select_runtime`]; see that
311/// macro's doc-comment.
312#[cfg(not(feature = "tokio"))]
313#[doc(hidden)]
314#[macro_export]
315macro_rules! __test_r_select_runtime {
316    ( sync { $($sync:tt)* } tokio { $($_tokio:tt)* } ) => {
317        $($sync)*
318    };
319}