Skip to content

Commit a72a1ef

Browse files
committed
Merge branch 'issue-12-macros-tests-r060-stack' into release/0.6.0
2 parents 9e0d306 + 565bffd commit a72a1ef

File tree

11 files changed

+191
-2
lines changed

11 files changed

+191
-2
lines changed

Cargo.lock

Lines changed: 47 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/solverforge-macros/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ quote.workspace = true
1414
proc-macro2.workspace = true
1515

1616
[dev-dependencies]
17+
solverforge = { path = "../solverforge" }
18+
trybuild = "1.0.114"

crates/solverforge-macros/WIREFRAME.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ When `#[shadow_variable_updates]` is configured, `update_entity_shadows(entity_i
196196
7. Entity computes (call method to compute entity fields)
197197
8. Post-update listener (call method once per entity)
198198

199-
### No Tests in Crate
199+
## Test Coverage
200200

201-
This is a proc-macro crate. Tests are integration-level, run via the consuming crates (examples and the facade).
201+
- `tests/trybuild.rs` — compile-pass and compile-fail coverage for the public macros
202+
- Unit tests in `planning_entity.rs` and `planning_solution.rs` — token-level golden checks for generated code shape

crates/solverforge-macros/src/planning_entity.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,31 @@ pub fn expand_derive(input: DeriveInput) -> Result<TokenStream, Error> {
223223

224224
Ok(expanded)
225225
}
226+
227+
#[cfg(test)]
228+
mod tests {
229+
use super::expand_derive;
230+
use syn::parse_quote;
231+
232+
#[test]
233+
fn golden_entity_expansion_includes_descriptor_and_planning_id() {
234+
let input = parse_quote! {
235+
struct Task {
236+
#[planning_id]
237+
id: String,
238+
#[planning_variable(allows_unassigned = true, value_range_provider = "workers")]
239+
worker_idx: Option<usize>,
240+
}
241+
};
242+
243+
let expanded = expand_derive(input)
244+
.expect("entity expansion should succeed")
245+
.to_string();
246+
247+
assert!(expanded.contains("impl :: solverforge :: __internal :: PlanningEntity for Task"));
248+
assert!(expanded.contains("impl :: solverforge :: __internal :: PlanningId for Task"));
249+
assert!(expanded.contains("with_allows_unassigned (true)"));
250+
assert!(expanded.contains("with_value_range (\"workers\")"));
251+
assert!(expanded.contains("pub fn entity_descriptor"));
252+
}
253+
}

crates/solverforge-macros/src/planning_solution.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,3 +1170,42 @@ fn extract_collection_inner_type(ty: &syn::Type) -> Option<&syn::Type> {
11701170
}
11711171
None
11721172
}
1173+
1174+
#[cfg(test)]
1175+
mod tests {
1176+
use super::expand_derive;
1177+
use syn::parse_quote;
1178+
1179+
#[test]
1180+
fn golden_solution_expansion_emits_constraint_streams_and_descriptor() {
1181+
let input = parse_quote! {
1182+
#[solverforge_constraints_path = "crate::constraints::create_constraints"]
1183+
#[basic_variable_config(
1184+
entity_collection = "tasks",
1185+
variable_field = "worker_idx",
1186+
variable_type = "usize",
1187+
value_range = "workers"
1188+
)]
1189+
struct Plan {
1190+
#[problem_fact_collection]
1191+
workers: Vec<Worker>,
1192+
#[planning_entity_collection]
1193+
tasks: Vec<Task>,
1194+
#[planning_score]
1195+
score: Option<HardSoftScore>,
1196+
}
1197+
};
1198+
1199+
let expanded = expand_derive(input)
1200+
.expect("solution expansion should succeed")
1201+
.to_string();
1202+
1203+
assert!(expanded.contains("impl :: solverforge :: __internal :: PlanningSolution for Plan"));
1204+
assert!(expanded.contains("pub trait PlanConstraintStreams"));
1205+
assert!(expanded.contains("pub trait TaskUnassignedFilter"));
1206+
assert!(expanded.contains(
1207+
"pub fn descriptor () -> :: solverforge :: __internal :: SolutionDescriptor"
1208+
));
1209+
assert!(expanded.contains("create_constraints"));
1210+
}
1211+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#[test]
2+
fn macros_compile_and_fail_as_expected() {
3+
let cases = trybuild::TestCases::new();
4+
cases.pass("tests/ui/pass/*.rs");
5+
cases.compile_fail("tests/ui/fail/*.rs");
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
use solverforge_macros::planning_entity;
2+
3+
#[planning_entity]
4+
struct Task(String);
5+
6+
fn main() {}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: expected one of `;` or `where`, found `<eof>`
2+
--> tests/ui/fail/planning_entity_tuple_struct.rs:4:12
3+
|
4+
4 | struct Task(String);
5+
| ^^^^^^^^ expected one of `;` or `where`
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use solverforge_macros::{planning_entity, planning_solution};
2+
3+
#[planning_entity]
4+
struct Task {
5+
#[planning_id]
6+
id: String,
7+
}
8+
9+
#[planning_solution]
10+
struct Plan {
11+
#[planning_entity_collection]
12+
tasks: Vec<Task>,
13+
}
14+
15+
fn main() {}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
error: #[planning_solution] requires a #[planning_score] field
2+
--> tests/ui/fail/planning_solution_missing_score.rs:9:1
3+
|
4+
9 | #[planning_solution]
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: this error originates in the attribute macro `planning_solution` (in Nightly builds, run with -Z macro-backtrace for more info)

0 commit comments

Comments
 (0)