1#![doc(
12 html_logo_url = "https://avatars.githubusercontent.com/u/91469139?s=128",
13 html_favicon_url = "https://avatars.githubusercontent.com/u/91469139?s=256"
14)]
15#![doc = include_str!("../README.md")]
16#![cfg_attr(docsrs, feature(doc_auto_cfg))]
17#![deny(
18 macro_use_extern_crate,
19 nonstandard_style,
20 rust_2018_idioms,
21 rustdoc::all,
22 trivial_casts,
23 trivial_numeric_casts
24)]
25#![forbid(non_ascii_idents, unsafe_code)]
26#![warn(
27 clippy::absolute_paths,
28 clippy::as_conversions,
29 clippy::as_ptr_cast_mut,
30 clippy::assertions_on_result_states,
31 clippy::branches_sharing_code,
32 clippy::clear_with_drain,
33 clippy::clone_on_ref_ptr,
34 clippy::collection_is_never_read,
35 clippy::create_dir,
36 clippy::dbg_macro,
37 clippy::debug_assert_with_mut_call,
38 clippy::decimal_literal_representation,
39 clippy::default_union_representation,
40 clippy::derive_partial_eq_without_eq,
41 clippy::else_if_without_else,
42 clippy::empty_drop,
43 clippy::empty_line_after_outer_attr,
44 clippy::empty_structs_with_brackets,
45 clippy::equatable_if_let,
46 clippy::empty_enum_variants_with_brackets,
47 clippy::exit,
48 clippy::expect_used,
49 clippy::fallible_impl_from,
50 clippy::filetype_is_file,
51 clippy::float_cmp_const,
52 clippy::fn_to_numeric_cast,
53 clippy::fn_to_numeric_cast_any,
54 clippy::format_push_string,
55 clippy::get_unwrap,
56 clippy::if_then_some_else_none,
57 clippy::imprecise_flops,
58 clippy::index_refutable_slice,
59 clippy::infinite_loop,
60 clippy::iter_on_empty_collections,
61 clippy::iter_on_single_items,
62 clippy::iter_over_hash_type,
63 clippy::iter_with_drain,
64 clippy::large_include_file,
65 clippy::large_stack_frames,
66 clippy::let_underscore_untyped,
67 clippy::lossy_float_literal,
68 clippy::manual_c_str_literals,
69 clippy::map_err_ignore,
70 clippy::mem_forget,
71 clippy::missing_assert_message,
72 clippy::missing_asserts_for_indexing,
73 clippy::missing_const_for_fn,
74 clippy::missing_docs_in_private_items,
75 clippy::multiple_inherent_impl,
76 clippy::multiple_unsafe_ops_per_block,
77 clippy::mutex_atomic,
78 clippy::mutex_integer,
79 clippy::needless_collect,
80 clippy::needless_pass_by_ref_mut,
81 clippy::needless_raw_strings,
82 clippy::nonstandard_macro_braces,
83 clippy::option_if_let_else,
84 clippy::or_fun_call,
85 clippy::panic_in_result_fn,
86 clippy::partial_pub_fields,
87 clippy::pedantic,
88 clippy::print_stderr,
89 clippy::print_stdout,
90 clippy::pub_without_shorthand,
91 clippy::ref_as_ptr,
92 clippy::rc_buffer,
93 clippy::rc_mutex,
94 clippy::read_zero_byte_vec,
95 clippy::redundant_clone,
96 clippy::redundant_type_annotations,
97 clippy::ref_patterns,
98 clippy::rest_pat_in_fully_bound_structs,
99 clippy::same_name_method,
100 clippy::semicolon_inside_block,
101 clippy::shadow_unrelated,
102 clippy::significant_drop_in_scrutinee,
103 clippy::significant_drop_tightening,
104 clippy::str_to_string,
105 clippy::string_add,
106 clippy::string_lit_as_bytes,
107 clippy::string_lit_chars_any,
108 clippy::string_slice,
109 clippy::string_to_string,
110 clippy::suboptimal_flops,
111 clippy::suspicious_operation_groupings,
112 clippy::suspicious_xor_used_as_pow,
113 clippy::tests_outside_test_module,
114 clippy::todo,
115 clippy::trailing_empty_array,
116 clippy::transmute_undefined_repr,
117 clippy::trivial_regex,
118 clippy::try_err,
119 clippy::undocumented_unsafe_blocks,
120 clippy::unimplemented,
121 clippy::uninhabited_references,
122 clippy::unnecessary_safety_comment,
123 clippy::unnecessary_safety_doc,
124 clippy::unnecessary_self_imports,
125 clippy::unnecessary_struct_initialization,
126 clippy::unneeded_field_pattern,
127 clippy::unused_peekable,
128 clippy::unwrap_in_result,
129 clippy::unwrap_used,
130 clippy::use_debug,
131 clippy::use_self,
132 clippy::useless_let_if_seq,
133 clippy::verbose_file_reads,
134 clippy::wildcard_enum_match_arm,
135 explicit_outlives_requirements,
136 future_incompatible,
137 let_underscore_drop,
138 meta_variable_misuse,
139 missing_abi,
140 missing_copy_implementations,
141 missing_debug_implementations,
142 missing_docs,
143 redundant_lifetimes,
144 semicolon_in_expressions_from_macros,
145 single_use_lifetimes,
146 unit_bindings,
147 unnameable_types,
148 unreachable_pub,
149 unsafe_op_in_unsafe_fn,
150 unstable_features,
151 unused_crate_dependencies,
152 unused_extern_crates,
153 unused_import_braces,
154 unused_lifetimes,
155 unused_macro_rules,
156 unused_qualifications,
157 unused_results,
158 variant_size_differences
159)]
160#![allow(clippy::uninlined_format_args)]
162
163pub mod cli;
164mod cucumber;
165pub mod event;
166pub mod feature;
167pub(crate) mod future;
168pub mod parser;
169pub mod runner;
170pub mod step;
171pub mod tag;
172pub mod writer;
173
174#[cfg(feature = "macros")]
175pub mod codegen;
176#[cfg(feature = "tracing")]
177pub mod tracing;
178
179#[cfg(test)]
181mod actually_used_crates_in_tests_and_book {
182 use rand as _;
183 use tempfile as _;
184 use tokio as _;
185}
186
187#[cfg(feature = "macros")]
188use std::{fmt::Debug, path::Path};
189use std::{fmt::Display, future::Future};
190
191#[cfg(feature = "macros")]
192use self::{
193 codegen::{StepConstructor as _, WorldInventory},
194 cucumber::DefaultCucumber,
195};
196
197pub use gherkin;
198
199#[cfg(feature = "macros")]
200#[doc(inline)]
201pub use self::codegen::Parameter;
202#[cfg(feature = "macros")]
203#[doc(inline)]
204pub use cucumber_codegen::{given, then, when, Parameter, World};
205
206#[doc(inline)]
207pub use self::{
208 cucumber::Cucumber,
209 event::Event,
210 parser::Parser,
211 runner::{Runner, ScenarioType},
212 step::Step,
213 writer::{
214 Arbitrary as ArbitraryWriter, Ext as WriterExt, Stats as StatsWriter,
215 Writer,
216 },
217};
218
219pub trait World: Sized + 'static {
233 type Error: Display;
235
236 fn new() -> impl Future<Output = Result<Self, Self::Error>>;
238
239 #[cfg(feature = "macros")]
240 #[must_use]
243 fn collection() -> step::Collection<Self>
244 where
245 Self: Debug + WorldInventory,
246 {
247 let mut out = step::Collection::new();
248
249 for given in inventory::iter::<Self::Given> {
250 let (loc, regex, fun) = given.inner();
251 out = out.given(Some(loc), regex(), fun);
252 }
253
254 for when in inventory::iter::<Self::When> {
255 let (loc, regex, fun) = when.inner();
256 out = out.when(Some(loc), regex(), fun);
257 }
258
259 for then in inventory::iter::<Self::Then> {
260 let (loc, regex, fun) = then.inner();
261 out = out.then(Some(loc), regex(), fun);
262 }
263
264 out
265 }
266
267 #[cfg(feature = "macros")]
268 #[must_use]
270 fn cucumber<I: AsRef<Path>>() -> DefaultCucumber<Self, I>
271 where
272 Self: Debug + WorldInventory,
273 {
274 Cucumber::new().steps(Self::collection())
275 }
276
277 #[cfg(feature = "macros")]
278 fn run<I: AsRef<Path>>(input: I) -> impl Future<Output = ()>
290 where
291 Self: Debug + WorldInventory,
292 {
293 Self::cucumber().run_and_exit(input)
294 }
295
296 #[cfg(feature = "macros")]
297 fn filter_run<I, F>(input: I, filter: F) -> impl Future<Output = ()>
311 where
312 Self: Debug + WorldInventory,
313 I: AsRef<Path>,
314 F: Fn(
315 &gherkin::Feature,
316 Option<&gherkin::Rule>,
317 &gherkin::Scenario,
318 ) -> bool
319 + 'static,
320 {
321 Self::cucumber().filter_run_and_exit(input, filter)
322 }
323}