Skip to content

Commit 2e3d702

Browse files
committed
fix(harness): Generalize function parameters with traits
Cherry pick d935e0b (#283)
1 parent 25f412d commit 2e3d702

File tree

1 file changed

+55
-10
lines changed

1 file changed

+55
-10
lines changed

crates/tryfn/src/lib.rs

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,34 +45,47 @@ pub use snapbox::data::DataFormat;
4545
pub use snapbox::Data;
4646

4747
/// [`Harness`] for discovering test inputs and asserting against snapshot files
48-
pub struct Harness<S, T> {
48+
pub struct Harness<S, T, I, E> {
4949
root: std::path::PathBuf,
5050
overrides: Option<ignore::overrides::Override>,
5151
setup: S,
5252
test: T,
5353
config: snapbox::Assert,
54+
test_output: std::marker::PhantomData<I>,
55+
test_error: std::marker::PhantomData<E>,
5456
}
5557

56-
impl<S, T, I, E> Harness<S, T>
58+
impl<S, T, I, E> Harness<S, T, I, E>
5759
where
60+
S: Setup + Send + Sync + 'static,
61+
T: Test<I, E> + Clone + Send + Sync + 'static,
5862
I: std::fmt::Display,
5963
E: std::fmt::Display,
60-
S: Fn(std::path::PathBuf) -> Case + Send + Sync + 'static,
61-
T: Fn(&std::path::Path) -> Result<I, E> + Send + Sync + 'static + Clone,
6264
{
6365
/// Specify where the test scenarios
6466
///
6567
/// - `input_root`: where to find the files. See [`Self::select`] for restricting what files
6668
/// are considered
6769
/// - `setup`: Given a path, choose the test name and the output location
6870
/// - `test`: Given a path, return the actual output value
71+
///
72+
/// By default filters are applied, including:
73+
/// - `...` is a line-wildcard when on a line by itself
74+
/// - `[..]` is a character-wildcard when inside a line
75+
/// - `[EXE]` matches `.exe` on Windows
76+
/// - `\` to `/`
77+
/// - Newlines
78+
///
79+
/// To limit this to newline normalization for text, have [`Setup`] call [`Data::raw`][snapbox::Data::raw] on `expected`.
6980
pub fn new(input_root: impl Into<std::path::PathBuf>, setup: S, test: T) -> Self {
7081
Self {
7182
root: input_root.into(),
7283
overrides: None,
7384
setup,
7485
test,
7586
config: snapbox::Assert::new().action_env(snapbox::assert::DEFAULT_ACTION_ENV),
87+
test_output: Default::default(),
88+
test_error: Default::default(),
7689
}
7790
}
7891

@@ -120,17 +133,17 @@ where
120133
let tests: Vec<_> = tests
121134
.into_iter()
122135
.map(|path| {
123-
let case = (self.setup)(path);
136+
let case = self.setup.setup(path);
124137
assert!(
125138
case.expected.source().map(|s| s.is_path()).unwrap_or(false),
126139
"`Case::expected` must be from a file"
127140
);
128141
let test = self.test.clone();
129142
let config = shared_config.clone();
130143
Trial::test(case.name.clone(), move || {
131-
let actual = (test)(&case.fixture)?;
144+
let actual = test.run(&case.fixture)?;
132145
let actual = actual.to_string();
133-
let actual = crate::Data::text(actual);
146+
let actual = snapbox::Data::text(actual);
134147
config.try_eq(Some(&case.name), actual, case.expected.clone())?;
135148
Ok(())
136149
})
@@ -145,9 +158,41 @@ where
145158
}
146159
}
147160

148-
/// A test case enumerated by the [`Harness`] with data from the `setup` function
149-
///
150-
/// See [`harness`][crate] for more details
161+
/// Function signature for generating a test [`Case`] from a path fixture
162+
pub trait Setup {
163+
fn setup(&self, fixture: std::path::PathBuf) -> Case;
164+
}
165+
166+
impl<F> Setup for F
167+
where
168+
F: Fn(std::path::PathBuf) -> Case,
169+
{
170+
fn setup(&self, fixture: std::path::PathBuf) -> Case {
171+
(self)(fixture)
172+
}
173+
}
174+
175+
/// Function signature for running a test [`Case`]
176+
pub trait Test<S, E>
177+
where
178+
S: std::fmt::Display,
179+
E: std::fmt::Display,
180+
{
181+
fn run(&self, fixture: &std::path::Path) -> Result<S, E>;
182+
}
183+
184+
impl<F, S, E> Test<S, E> for F
185+
where
186+
F: Fn(&std::path::Path) -> Result<S, E>,
187+
S: std::fmt::Display,
188+
E: std::fmt::Display,
189+
{
190+
fn run(&self, fixture: &std::path::Path) -> Result<S, E> {
191+
(self)(fixture)
192+
}
193+
}
194+
195+
/// A test case enumerated by the [`Harness`] with data from the [`Setup`] function
151196
pub struct Case {
152197
/// Display name
153198
pub name: String,

0 commit comments

Comments
 (0)