mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 10:35:58 +00:00
kernel-cases: an smlib feature for the CLI, and no grading of a kernel the build isn't running
- solidcraft-cli and solidcraft-engine forward an `smlib` feature to solidcraft-kernel/smlib, so `cargo build -p solidcraft-cli --features smlib` gives the rig SMLib's check. - solidcraft_kernel::boolean_kernel() says which kernel this process runs booleans on. `default` until the SMLib switch (SOLIDCRAFT_BOOLEANS=smlib) lands and answers there. An smlib run on a build without the switch reports "not supported yet" instead of grading the default kernel under SMLib's name. - An area may keep its skipped list in parts (skipped-<part>.json). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,10 @@ default = ["raytrace-cpu"]
|
||||
bundled-render-library = ["solidcraft-engine/bundled-render-library"]
|
||||
raytrace-cpu = ["solidcraft-engine/raytrace-cpu"]
|
||||
|
||||
[features]
|
||||
# Link SMLib into the kernel, for the regression rig's smlib runs (tests/kernel-cases).
|
||||
smlib = ["solidcraft-engine/smlib"]
|
||||
|
||||
[dependencies]
|
||||
solidcraft-engine = { workspace = true }
|
||||
solidcraft-gpu = { workspace = true }
|
||||
|
||||
@@ -62,7 +62,13 @@ fn check_case(dir: &str) -> Value {
|
||||
};
|
||||
if kernel() == "smlib" && !solidcraft_engine::kernel::smlib_built() {
|
||||
out["status"] = json!("unsupported");
|
||||
out["error"] = json!("this build has no SMLib: build solidcraft-cli with --features solidcraft-kernel/smlib");
|
||||
out["error"] = json!("this build has no SMLib: build solidcraft-cli with --features smlib");
|
||||
return out;
|
||||
}
|
||||
let running = solidcraft_engine::kernel::boolean_kernel();
|
||||
if kernel() != running {
|
||||
out["status"] = json!("unsupported");
|
||||
out["error"] = json!(format!("this build runs booleans on the {running} kernel, not {}", kernel()));
|
||||
return out;
|
||||
}
|
||||
let refused = want["outcome"].as_str() == Some("refused");
|
||||
|
||||
@@ -13,6 +13,8 @@ default = []
|
||||
# Optional authored texture/HDR bytes; the command registry and metadata remain available.
|
||||
bundled-render-library = []
|
||||
raytrace-cpu = ["solidcraft-render/raytrace-cpu"]
|
||||
# Link SMLib into the kernel (solidcraft-kernel/smlib; needs scripts/fetch-smlib.sh).
|
||||
smlib = ["solidcraft-kernel/smlib"]
|
||||
# Turns on the parameter-contract audit recorder (`SOLIDCRAFT_PARAM_AUDIT`, see
|
||||
# `src/schema/record.rs`), for checking a new contract against the whole test suite.
|
||||
param-audit = []
|
||||
|
||||
@@ -224,7 +224,7 @@ pub use sweep_path::{RailFit, SweepControl, SweepOrientation, sweep_path, sweep_
|
||||
pub use topo::{CylinderFace, cylinder_end_at, cylinder_face, cylinder_face_at};
|
||||
pub use topo::{TopoCounts, merged_topology, seam_flags};
|
||||
pub use tspline::tspline_sheet;
|
||||
pub use validity::{Validity, smlib_built, validity};
|
||||
pub use validity::{Validity, boolean_kernel, smlib_built, validity};
|
||||
pub use whole_face::{WholeFace, cut_takes_only_the_face, cut_tool, face_prism, matching_face};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, thiserror::Error)]
|
||||
|
||||
@@ -47,3 +47,11 @@ fn smlib_validity(_: &Body) -> Option<Result<(), String>> {
|
||||
pub fn smlib_built() -> bool {
|
||||
cfg!(feature = "smlib")
|
||||
}
|
||||
|
||||
/// The kernel booleans run on in this process: `"default"` or `"smlib"`. The regression rig
|
||||
/// refuses to grade a kernel the process isn't running. The SMLib boolean switch
|
||||
/// (`SOLIDCRAFT_BOOLEANS=smlib`) answers here once it lands; until then this is always
|
||||
/// `"default"`.
|
||||
pub fn boolean_kernel() -> &'static str {
|
||||
"default"
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ cargo xtask kernel-cases --kernel both --cli target/release/solidcraft-cli # a
|
||||
cargo run -p solidcraft-cli -- kernel-cases tests/kernel-cases/booleans/<id> # one case
|
||||
```
|
||||
|
||||
For the `smlib` column, build `solidcraft-cli` with `--features solidcraft-kernel/smlib` (after
|
||||
For the `smlib` column, build `solidcraft-cli` with `--features smlib` (after
|
||||
`scripts/fetch-smlib.sh`). The rig sets `SOLIDCRAFT_BOOLEANS=smlib` for those runs.
|
||||
|
||||
## Rules
|
||||
@@ -46,8 +46,8 @@ Each case has:
|
||||
specification, never a user's file).
|
||||
- `expected.json`: the right answer, graded by `solidcraft-cli kernel-cases`.
|
||||
|
||||
Each area also has `skipped.json`: every issue and PR looked at that did not become a case, with
|
||||
one line each saying why.
|
||||
Each area also has `skipped.json` (or several, `skipped-<part>.json`, where an area is triaged in
|
||||
parts): every issue and PR looked at that did not become a case, with one line each saying why.
|
||||
|
||||
```json
|
||||
[{"source": "tangency-labs/solidcraft#123", "why": "UI only: the selection highlight, no geometry"}]
|
||||
|
||||
@@ -189,6 +189,11 @@ fn sources_of(want: &Value) -> Vec<String> {
|
||||
want["sources"].as_array().into_iter().flatten().filter_map(|s| s.as_str().map(str::to_string)).collect()
|
||||
}
|
||||
|
||||
/// The number in `owner/repo#123`, for sorting.
|
||||
fn source_number(s: &str) -> u64 {
|
||||
s.rsplit('#').next().and_then(|n| n.parse().ok()).unwrap_or(u64::MAX)
|
||||
}
|
||||
|
||||
/// `tangency-labs/solidcraft#123` as a link.
|
||||
fn link(source: &str) -> String {
|
||||
match source.split_once('#') {
|
||||
@@ -274,8 +279,20 @@ fn write_report(o: &Options, dir: &Path, list: &[PathBuf], results: &[Value]) ->
|
||||
let mut area_dirs: Vec<PathBuf> = std::fs::read_dir(dir).map_err(|e| e.to_string())?.flatten().map(|e| e.path()).filter(|p| p.is_dir()).collect();
|
||||
area_dirs.sort();
|
||||
for a in area_dirs {
|
||||
let list = read(&a.join("skipped.json"));
|
||||
let Some(items) = list.as_array().filter(|l| !l.is_empty()) else { continue };
|
||||
// skipped.json, or several (skipped-<part>.json) where people triage an area in parts.
|
||||
let mut files: Vec<PathBuf> = std::fs::read_dir(&a)
|
||||
.map_err(|e| e.to_string())?
|
||||
.flatten()
|
||||
.map(|e| e.path())
|
||||
.filter(|p| p.file_name().and_then(|n| n.to_str()).is_some_and(|n| n.starts_with("skipped") && n.ends_with(".json")))
|
||||
.collect();
|
||||
files.sort();
|
||||
let mut items: Vec<Value> = files.iter().flat_map(|f| read(f).as_array().cloned().unwrap_or_default()).collect();
|
||||
if items.is_empty() {
|
||||
continue;
|
||||
}
|
||||
items.sort_by_key(|it| source_number(it["source"].as_str().unwrap_or("")));
|
||||
let items = &items;
|
||||
md += &format!("### {}\n\n| Source | Why skipped |\n|---|---|\n", a.file_name().map(|n| n.to_string_lossy().to_string()).unwrap_or_default());
|
||||
for it in items {
|
||||
skipped += 1;
|
||||
|
||||
Reference in New Issue
Block a user