Setup a testing bench

Signed-off-by: Marcel Müller <neikos@neikos.email>
This commit is contained in:
Marcel Müller 2026-03-06 13:56:39 +01:00
parent 4470af3926
commit d3e6410ec0
16 changed files with 336 additions and 4 deletions

81
Cargo.lock generated
View file

@ -2,6 +2,15 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "aho-corasick"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "annotate-snippets" name = "annotate-snippets"
version = "0.12.13" version = "0.12.13"
@ -31,6 +40,16 @@ version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
[[package]]
name = "bstr"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
dependencies = [
"memchr",
"serde",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.4" version = "1.0.4"
@ -107,6 +126,19 @@ dependencies = [
"wasip3", "wasip3",
] ]
[[package]]
name = "globset"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3"
dependencies = [
"aho-corasick",
"bstr",
"log",
"regex-automata",
"regex-syntax",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.15.5" version = "0.15.5"
@ -153,9 +185,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e82db8c87c7f1ccecb34ce0c24399b8a73081427f3c7c50a5d597925356115e4" checksum = "e82db8c87c7f1ccecb34ce0c24399b8a73081427f3c7c50a5d597925356115e4"
dependencies = [ dependencies = [
"console", "console",
"globset",
"once_cell", "once_cell",
"similar", "similar",
"tempfile", "tempfile",
"walkdir",
] ]
[[package]] [[package]]
@ -234,6 +268,23 @@ version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
[[package]]
name = "regex-automata"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "1.1.4" version = "1.1.4"
@ -247,6 +298,15 @@ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.61.2",
] ]
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.27" version = "1.0.27"
@ -260,6 +320,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [ dependencies = [
"serde_core", "serde_core",
"serde_derive",
] ]
[[package]] [[package]]
@ -334,6 +395,7 @@ dependencies = [
"insta", "insta",
"serde", "serde",
"serde_json", "serde_json",
"temple",
"thiserror", "thiserror",
"winnow", "winnow",
] ]
@ -376,6 +438,16 @@ version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]] [[package]]
name = "wasip2" name = "wasip2"
version = "1.0.2+wasi-0.2.9" version = "1.0.2+wasi-0.2.9"
@ -428,6 +500,15 @@ dependencies = [
"semver", "semver",
] ]
[[package]]
name = "winapi-util"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "windows-link" name = "windows-link"
version = "0.2.1" version = "0.2.1"

View file

@ -6,11 +6,19 @@ edition = "2024"
[dependencies] [dependencies]
annotate-snippets = "0.12.13" annotate-snippets = "0.12.13"
displaydoc = "0.2.5" displaydoc = "0.2.5"
serde = "1.0.228" serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149" serde_json = "1.0.149"
thiserror = "2.0.18" thiserror = "2.0.18"
winnow = { version = "0.7.14", features = ["unstable-recover"] } winnow = { version = "0.7.14", features = ["unstable-recover"] }
[dev-dependencies] [dev-dependencies]
annotate-snippets = { version = "0.12.13", features = ["testing-colors"] } annotate-snippets = { version = "0.12.13", features = ["testing-colors"] }
insta = "1.46.3" insta = { version = "1.46.3", features = ["glob"] }
temple = { path = ".", features = ["serialize"] }
[profile.dev.package]
insta.opt-level = 3
similar.opt-level = 3
[features]
serialize = []

View file

@ -15,7 +15,10 @@ pub enum EvaluationError {
ExplicitAbort, ExplicitAbort,
} }
pub fn execute(instructions: &[Instruction], global_context: &Context) -> Result<String, EvaluationError> { pub fn execute(
instructions: &[Instruction],
global_context: &Context,
) -> Result<String, EvaluationError> {
let mut output = String::new(); let mut output = String::new();
let mut scopes: HashMap<crate::emit::VariableSlot, serde_json::Value> = HashMap::new(); let mut scopes: HashMap<crate::emit::VariableSlot, serde_json::Value> = HashMap::new();

View file

@ -14,12 +14,31 @@ pub struct TempleInput {
range: Range<usize>, range: Range<usize>,
} }
impl TempleInput {
pub fn from_parts(backing: Arc<str>, range: Range<usize>) -> TempleInput {
TempleInput { backing, range }
}
pub fn into_parts(self) -> (Arc<str>, Range<usize>) {
(self.backing, self.range)
}
}
impl std::fmt::Debug for TempleInput { impl std::fmt::Debug for TempleInput {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "\"{}\"", self.as_str()) write!(f, "\"{}\"", self.as_str())
} }
} }
impl From<String> for TempleInput {
fn from(value: String) -> Self {
let range = 0..value.len();
let backing = Arc::from(value);
TempleInput { backing, range }
}
}
impl From<&str> for TempleInput { impl From<&str> for TempleInput {
fn from(value: &str) -> Self { fn from(value: &str) -> Self {
let backing = Arc::from(value.to_string()); let backing = Arc::from(value.to_string());

View file

@ -11,7 +11,7 @@ use crate::input::TempleInput;
pub mod ast; pub mod ast;
pub mod emit; pub mod emit;
pub mod eval; pub mod eval;
mod input; pub mod input;
pub mod parser; pub mod parser;
#[derive(Debug, Error, Display)] #[derive(Debug, Error, Display)]

View file

@ -0,0 +1,42 @@
---
source: tests/file_tests.rs
expression: ast
input_file: tests/cases/interpolation.temple
---
TemplateAst {
root: [
StaticContent(
TemplateToken {
kind: Content,
source: "Hello! I'm",
},
),
Interpolation {
prev_whitespace: Some(
TemplateToken {
kind: Whitespace,
source: " ",
},
),
wants_output: Some(
TemplateToken {
kind: WantsOutput,
source: "=",
},
),
expression: VariableAccess(
TemplateToken {
kind: Ident,
source: "name",
},
),
post_whitespace: Some(
TemplateToken {
kind: Whitespace,
source: "
",
},
),
},
],
}

View file

@ -0,0 +1,16 @@
---
source: tests/file_tests.rs
expression: ast
input_file: tests/cases/simple.temple
---
TemplateAst {
root: [
StaticContent(
TemplateToken {
kind: Content,
source: "Hello World!
",
},
),
],
}

View file

@ -0,0 +1,28 @@
---
source: tests/file_tests.rs
expression: emit
input_file: tests/cases/interpolation.temple
---
[
AppendContent {
content: "Hello! I'm",
},
AppendContent {
content: " ",
},
LoadFromContextToSlot {
name: "name",
slot: VariableSlot {
index: 0,
},
},
EmitFromSlot {
slot: VariableSlot {
index: 0,
},
},
AppendContent {
content: "
",
},
]

View file

@ -0,0 +1,11 @@
---
source: tests/file_tests.rs
expression: emit
input_file: tests/cases/simple.temple
---
[
AppendContent {
content: "Hello World!
",
},
]

View file

@ -0,0 +1,5 @@
{
"name": "Hemera"
}
---
Hello! I'm {{= name }}

View file

@ -0,0 +1,6 @@
---
source: tests/file_tests.rs
expression: output
input_file: tests/cases/interpolation.temple
---
"Hello! I'm Hemera\n"

View file

@ -0,0 +1,6 @@
---
source: tests/file_tests.rs
expression: output
input_file: tests/cases/simple.temple
---
"Hello World!\n"

View file

@ -0,0 +1,46 @@
---
source: tests/file_tests.rs
expression: parsed
input_file: tests/cases/interpolation.temple
---
ParsedTemplate {
tokens: [
TemplateToken {
kind: Content,
source: "Hello! I'm",
},
TemplateToken {
kind: Whitespace,
source: " ",
},
TemplateToken {
kind: LeftDelim,
source: "{{",
},
TemplateToken {
kind: WantsOutput,
source: "=",
},
TemplateToken {
kind: Whitespace,
source: " ",
},
TemplateToken {
kind: Ident,
source: "name",
},
TemplateToken {
kind: Whitespace,
source: " ",
},
TemplateToken {
kind: RightDelim,
source: "}}",
},
TemplateToken {
kind: Whitespace,
source: "
",
},
],
}

View file

@ -0,0 +1,14 @@
---
source: tests/file_tests.rs
expression: parsed
input_file: tests/cases/simple.temple
---
ParsedTemplate {
tokens: [
TemplateToken {
kind: Content,
source: "Hello World!
",
},
],
}

View file

@ -0,0 +1 @@
Hello World!

46
tests/file_tests.rs Normal file
View file

@ -0,0 +1,46 @@
use std::collections::HashMap;
use temple::Context;
#[test]
fn check_cases() {
insta::glob!("cases/*.temple", |path| {
let mut settings = insta::Settings::clone_current();
settings.set_snapshot_path("cases");
settings.set_snapshot_suffix(path.file_stem().unwrap().display().to_string());
settings.set_prepend_module_to_snapshot(false);
let _guard = settings.bind_to_scope();
let input = std::fs::read_to_string(path).unwrap();
let (context, input) = input.split_once("\n---\n").unwrap_or_else(|| ("", &input));
let map = if !context.is_empty() {
serde_json::from_str::<HashMap<String, serde_json::Value>>(context).unwrap()
} else {
HashMap::new()
};
let mut context = Context::new();
for (k, v) in map {
context.insert(k, v);
}
let parsed = temple::parser::parse(input.into()).unwrap();
insta::assert_debug_snapshot!("parsed", parsed);
let ast = temple::ast::parse(parsed.tokens()).unwrap();
insta::assert_debug_snapshot!("ast", ast);
let emit = temple::emit::emit_machine(ast);
insta::assert_debug_snapshot!("instructions", emit);
let output = temple::eval::execute(&emit, &context).unwrap();
insta::assert_debug_snapshot!("output", output);
});
}