Skip to content

Commit d298f08

Browse files
committed
multifile support and better relation between {,Borrowed}File{Config,Content}
1 parent e50fd77 commit d298f08

File tree

7 files changed

+389
-302
lines changed

7 files changed

+389
-302
lines changed

examples/simple.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{error::Error, path::Path, sync::Arc, time::Duration};
22

3-
use erudite::{context::TestContext, runner::TestFileContent};
3+
use erudite::{context::TestContext, BorrowedFileContent};
44
use leucite::Rules;
55
use regex::Regex;
66
use tracing::info;
@@ -38,7 +38,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
3838
let compiled = Arc::new(context)
3939
.test_runner()
4040
.file(
41-
TestFileContent::string(include_str!("./solution.rs")),
41+
BorrowedFileContent::string(include_str!("./solution.rs")),
4242
Path::new("./solution.rs"),
4343
)
4444
.filter_tests(|test| *test.data())

src/context/builder.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
use crate::cases::{ExpectedOutput, TestCase};
1+
use crate::{
2+
cases::{ExpectedOutput, TestCase},
3+
FileContent,
4+
};
25

3-
use super::{CommandConfig, FileConfig, FileContent, TestContext};
6+
use super::{CommandConfig, FileConfig, TestContext};
47
use std::{marker::PhantomData, path::Path, time::Duration};
58

69
use leucite::{MemorySize, Rules};
@@ -37,7 +40,7 @@ use hidden::*;
3740
/// # Usage
3841
///
3942
/// ```
40-
/// # use erudite::{context::{FileContent, TestContext}, Rules, MemorySize};
43+
/// # use erudite::{context::TestContext, FileContent, Rules, MemorySize};
4144
/// # use std::time::Duration;
4245
/// # let rules = Rules::new();
4346
/// let context = TestContext::builder()
@@ -165,7 +168,7 @@ impl<T, Tests, RunCmd> TestContextBuilder<T, Tests, RunCmd> {
165168
/// [`TestRunner::compile`]: crate::runner::TestRunner::compile
166169
///
167170
/// ```
168-
/// # use erudite::context::{TestContext, FileContent};
171+
/// # use erudite::{FileContent, context::TestContext};
169172
/// let ctx = TestContext::builder()
170173
/// .compile_command(["gcc", "-o", "solution", "solution.c"])
171174
/// .run_command(["solution.c"])
@@ -196,7 +199,7 @@ impl<T, Tests, RunCmd> TestContextBuilder<T, Tests, RunCmd> {
196199
/// `/foo/bar` -> `<test-env>/foo/bar`.
197200
///
198201
/// ```
199-
/// # use erudite::context::{TestContext, FileContent};
202+
/// # use erudite::{FileContent, context::TestContext};
200203
/// let ctx = TestContext::builder()
201204
/// .run_command(["node", "solution.js"])
202205
/// .test("hello world", "dlrow olleh", true)
@@ -224,7 +227,7 @@ impl<T, Tests, RunCmd> TestContextBuilder<T, Tests, RunCmd> {
224227
/// `/foo/bar` -> `<test-env>/foo/bar`.
225228
///
226229
/// ```
227-
/// # use erudite::context::{TestContext, FileContent, FileConfig};
230+
/// # use erudite::{FileContent, FileConfig, context::TestContext};
228231
/// let ctx = TestContext::builder()
229232
/// .run_command(["node", "solution.js"])
230233
/// .test("hello world", "dlrow olleh", true)

src/context/mod.rs

Lines changed: 32 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,11 @@
1-
use std::{
2-
path::{Path, PathBuf},
3-
sync::Arc,
4-
time::Duration,
5-
};
1+
use std::{sync::Arc, time::Duration};
62

7-
use derive_more::From;
83
use leucite::{MemorySize, Rules};
94

105
mod builder;
116
pub use builder::TestContextBuilder;
127

13-
use crate::{cases::TestCase, runner::TestRunner};
14-
15-
/// Configuration for how a file should be setup for test cases to be run
16-
#[derive(Clone, Debug, PartialEq, Eq)]
17-
pub struct FileConfig {
18-
/// This path is relative to the temporary directory created while running tests
19-
src: FileContent,
20-
dest: PathBuf,
21-
}
22-
23-
impl FileConfig {
24-
pub fn new(src: impl Into<FileContent>, dest: impl AsRef<Path>) -> Self {
25-
let dest = dest.as_ref();
26-
let dest = if dest.is_absolute() {
27-
dest.strip_prefix("/").unwrap().to_path_buf()
28-
} else {
29-
dest.to_path_buf()
30-
};
31-
32-
Self {
33-
src: src.into(),
34-
dest,
35-
}
36-
}
37-
38-
pub(crate) async fn write_file(&self, base: impl AsRef<Path>) -> std::io::Result<u64> {
39-
let target = base.as_ref().join(&self.dest);
40-
match self.src {
41-
FileContent::Path(ref path) => tokio::fs::copy(path, target).await,
42-
FileContent::Bytes(ref contents) => tokio::fs::write(target, contents)
43-
.await
44-
.map(|_| contents.len() as _),
45-
}
46-
}
47-
48-
pub fn dest(&self) -> &Path {
49-
&self.dest
50-
}
51-
}
52-
53-
impl<S, D> From<(S, D)> for FileConfig
54-
where
55-
S: Into<FileContent>,
56-
D: AsRef<Path>,
57-
{
58-
fn from((source, destination): (S, D)) -> Self {
59-
Self::new(source, destination)
60-
}
61-
}
62-
63-
/// Representation of the content of a file to be added into a test environment
64-
///
65-
/// [`FileContent::Path`] represents a path on the host system. The test runner will copy from
66-
/// this path into the test environment _at compile time_. If the data should be loaded now,
67-
/// consider using [`FileContent::Bytes`].
68-
///
69-
/// [`FileContent::Bytes`] contains a vec of bytes that will be written to the file when the tests
70-
/// are compiled.
71-
#[derive(Clone, Debug, From, PartialEq, Eq)]
72-
pub enum FileContent {
73-
/// Copies a file directly from this path
74-
///
75-
/// NOTE: This happens when the tests are compiled/run. If you want to load the file into
76-
/// memory first, use [`FileContent::Bytes`].
77-
Path(PathBuf),
78-
/// Creates a new file with this content
79-
Bytes(Vec<u8>),
80-
}
81-
82-
impl From<&Path> for FileContent {
83-
fn from(value: &Path) -> Self {
84-
Self::path(value)
85-
}
86-
}
87-
88-
impl From<&[u8]> for FileContent {
89-
fn from(value: &[u8]) -> Self {
90-
Self::bytes(value)
91-
}
92-
}
93-
94-
impl<const N: usize> From<&[u8; N]> for FileContent {
95-
fn from(value: &[u8; N]) -> Self {
96-
Self::bytes(value)
97-
}
98-
}
99-
100-
impl FileContent {
101-
/// Construct a `FileContent::Path` from something that's like a path
102-
///
103-
/// ```
104-
/// # use erudite::context::FileContent;
105-
/// let content = FileContent::path("/foo/bar");
106-
/// ```
107-
pub fn path(path: impl Into<PathBuf>) -> Self {
108-
Self::Path(path.into())
109-
}
110-
111-
/// Construct a `FileContent::Bytes` from something that's like a string.
112-
///
113-
/// ```
114-
/// # use erudite::context::FileContent;
115-
/// let content = FileContent::string("// some rust code");
116-
/// ```
117-
pub fn string(string: impl Into<String>) -> Self {
118-
Self::bytes(string.into())
119-
}
120-
121-
/// Construct a `FileContent::Bytes` from raw bytes
122-
///
123-
/// ```
124-
/// # use erudite::context::FileContent;
125-
/// let content = FileContent::bytes([0xfa, 0xca, 0xde]);
126-
/// ```
127-
pub fn bytes(bytes: impl Into<Vec<u8>>) -> Self {
128-
Self::Bytes(bytes.into())
129-
}
130-
}
8+
use crate::{cases::TestCase, runner::TestRunner, FileConfig};
1319

13210
// TODO: rename (and update test names)
13311
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -247,7 +125,10 @@ mod test {
247125

248126
use tmpdir::TmpDir;
249127

250-
use crate::context::{CommandConfig, FileConfig, FileContent};
128+
use crate::{
129+
context::{CommandConfig, FileConfig},
130+
FileContent,
131+
};
251132

252133
#[tokio::test]
253134
async fn file_config_path() {
@@ -270,6 +151,32 @@ mod test {
270151
assert_eq!(read, "some content");
271152
}
272153

154+
#[tokio::test]
155+
async fn file_config_path_dir() {
156+
let tmpdir = TmpDir::new("erudite-test").await.unwrap();
157+
let source = tmpdir.as_ref().join("foo");
158+
tokio::fs::create_dir_all(&source).await.unwrap();
159+
tokio::fs::write(source.join("bar.txt"), "Some content in /foo/bar.txt")
160+
.await
161+
.unwrap();
162+
163+
let config = FileConfig::new(source, "out");
164+
assert_eq!(config.dest(), Path::new("out"));
165+
config
166+
.write_file(&tmpdir)
167+
.await
168+
.expect("failed while copying file");
169+
170+
let dir = tokio::fs::metadata(tmpdir.as_ref().join("foo"))
171+
.await
172+
.expect("failed while reading file");
173+
assert!(dir.is_dir());
174+
let read = tokio::fs::read_to_string(tmpdir.as_ref().join("foo/bar.txt"))
175+
.await
176+
.expect("failed while reading file");
177+
assert_eq!(read, "Some content in /foo/bar.txt");
178+
}
179+
273180
#[tokio::test]
274181
async fn file_config_bytes() {
275182
let tmpdir = TmpDir::new("erudite-test").await.unwrap();

0 commit comments

Comments
 (0)