Something went wrong. Try again.
atproto Thingiverse but good
Something went wrong. Try again.
31 kB · 867 lines
Rust
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868use crate::{ CanonicalRecord, ExpectedOutcome, ExpectedRecord, FixtureCase, OracleProjection, Profile, SCHEMA_VERSION,};use serde::{Deserialize, Serialize};use std::collections::BTreeSet;use thiserror::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]#[serde(rename_all = "snake_case")]pub enum GateScope { Authored, OracleProjection, Both,}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]pub struct GateDefinition { pub id: &'static str, pub profiles: &'static [Profile], pub tags: &'static [&'static str], pub required_fields: &'static [&'static str], pub scope: GateScope,}
pub const GATE_DEFINITIONS: &[GateDefinition] = &[ GateDefinition { id: "syntax_types_0_to_5", profiles: &[Profile::Strict, Profile::Compatibility, Profile::Lossless], tags: &["syntax_types_0_to_5"], required_fields: &["candidate.syntax"], scope: GateScope::Both, }, GateDefinition { id: "profile_acceptance_and_diagnostics", profiles: &[Profile::Strict, Profile::Compatibility, Profile::Lossless], tags: &["profile_acceptance_and_diagnostics"], required_fields: &["candidate.diagnostics"], scope: GateScope::Both, }, GateDefinition { id: "mpd_and_data_boundaries", profiles: &[Profile::Strict], tags: &["mpd_and_data_boundaries"], required_fields: &[ "candidate.semantic.canonical_path", "candidate.semantic.target_identity", ], scope: GateScope::Both, }, GateDefinition { id: "path_and_resolution_independence", profiles: &[Profile::Strict, Profile::Compatibility], tags: &["path_and_resolution_independence"], required_fields: &[ "candidate.semantic.canonical_path", "candidate.semantic.root_identity", "candidate.semantic.target_identity", "candidate.semantic.cache_identity", ], scope: GateScope::Both, }, GateDefinition { id: "bfc_state_and_invertnext", profiles: &[Profile::Strict], tags: &["bfc_state_and_invertnext"], required_fields: &["candidate.semantic.bfc_state"], scope: GateScope::Both, }, GateDefinition { id: "colours_and_ldconfig", profiles: &[Profile::Strict], tags: &["colours_and_ldconfig"], required_fields: &["candidate.semantic.colour_state"], scope: GateScope::Both, }, GateDefinition { id: "graph_identity_and_instances", profiles: &[Profile::Strict, Profile::Compatibility], tags: &["graph_identity_and_instances"], required_fields: &["candidate.scene.instances"], scope: GateScope::Both, }, GateDefinition { id: "steps_and_transforms", profiles: &[Profile::Strict], tags: &["steps_and_transforms"], required_fields: &[ "candidate.semantic.steps", "candidate.scene.bounds", "candidate.scene.reflection", ], scope: GateScope::Both, }, GateDefinition { id: "numeric_finiteness_and_raw_preservation", profiles: &[Profile::Lossless], tags: &["numeric_finiteness_and_raw_preservation"], required_fields: &["candidate.syntax", "candidate.diagnostics"], scope: GateScope::Both, }, GateDefinition { id: "semantic_limits_and_cancellation", profiles: &[Profile::Compatibility, Profile::Lossless], tags: &["semantic_limits_and_cancellation"], required_fields: &["candidate.semantic.limits", "candidate.diagnostics"], scope: GateScope::Both, }, GateDefinition { id: "conditional_line_projection", profiles: &[Profile::Strict], tags: &["conditional_line_projection"], required_fields: &["candidate.scene"], scope: GateScope::Both, }, GateDefinition { id: "texmap_projection_v1", profiles: &[Profile::Strict], tags: &["texmap_projection_v1"], required_fields: &["candidate.semantic.texmap_events"], scope: GateScope::Both, }, GateDefinition { id: "points_and_explicit_edges", profiles: &[Profile::Strict], tags: &["points_and_explicit_edges"], required_fields: &["candidate.scene"], scope: GateScope::Both, },];
pub const GATE_NAMES: &[&str] = &[ "syntax_types_0_to_5", "profile_acceptance_and_diagnostics", "mpd_and_data_boundaries", "path_and_resolution_independence", "bfc_state_and_invertnext", "colours_and_ldconfig", "graph_identity_and_instances", "steps_and_transforms", "numeric_finiteness_and_raw_preservation", "semantic_limits_and_cancellation", "conditional_line_projection", "texmap_projection_v1", "points_and_explicit_edges",];
#[derive(Debug, Error, Clone, PartialEq, Eq, Serialize, Deserialize)]pub enum GateFailure { #[error("gate {gate} does not apply to fixture {fixture} under {profile:?}")] NotApplicable { gate: String, fixture: String, profile: Profile, }, #[error("gate {gate} found a schema mismatch for {fixture}")] SchemaMismatch { gate: String, fixture: String }, #[error("gate {gate} found a field mismatch for {fixture}: {field}")] FieldMismatch { gate: String, fixture: String, field: String, }, #[error("gate {gate} found an invalid oracle certification for {fixture}")] InvalidCertification { gate: String, fixture: String }, #[error("gate {gate} cannot validate {fixture}: {field}")] MissingAuthority { gate: String, fixture: String, field: String, }, #[error("gate {gate} found a rejection mismatch for {fixture}: {detail}")] RejectedMismatch { gate: String, fixture: String, detail: String, },}
pub trait CorpusGate { fn definition(&self) -> &'static GateDefinition; fn evaluate( &self, fixture: &FixtureCase, expected: &ExpectedRecord, actual: &CanonicalRecord, ) -> Result<(), GateFailure>; fn evaluate_with_files( &self, fixture: &FixtureCase, expected: &ExpectedRecord, actual: &CanonicalRecord, files: &[polymodel_ldraw_core::OwnedVirtualFile], ) -> Result<(), GateFailure>; fn evaluate_rejection( &self, fixture: &FixtureCase, expected: &ExpectedRecord, error: &polymodel_ldraw_core::LdrawError, ) -> Result<(), GateFailure>;}
#[derive(Debug, Clone, Copy)]pub struct NamedGate { pub definition: &'static GateDefinition,}
impl CorpusGate for NamedGate { fn definition(&self) -> &'static GateDefinition { self.definition }
fn evaluate_rejection( &self, fixture: &FixtureCase, expected: &ExpectedRecord, error: &polymodel_ldraw_core::LdrawError, ) -> Result<(), GateFailure> { if !matches!( fixture.outcome, ExpectedOutcome::Rejected | ExpectedOutcome::Cancelled ) { return Err(GateFailure::RejectedMismatch { gate: self.definition.id.into(), fixture: fixture.id.into(), detail: "rejection evaluation used for an accepted outcome".into(), }); } let matches_expected = match (fixture.outcome, error) { (ExpectedOutcome::Cancelled, polymodel_ldraw_core::LdrawError::Cancelled) => true, (ExpectedOutcome::Rejected, polymodel_ldraw_core::LdrawError::Diagnostic(_actual)) => { expected.oracle_expected.status == "error" && expected.oracle_expected.error.is_some() } _ => false, }; if matches_expected { Ok(()) } else { Err(GateFailure::RejectedMismatch { gate: self.definition.id.into(), fixture: fixture.id.into(), detail: format!( "actual={error:?} expected_outcome={:?} expected_diagnostics={:?}", fixture.outcome, expected.oracle_expected.diagnostics ), }) } }
fn evaluate( &self, fixture: &FixtureCase, expected: &ExpectedRecord, actual: &CanonicalRecord, ) -> Result<(), GateFailure> { self.evaluate_with_files(fixture, expected, actual, &[]) }
fn evaluate_with_files( &self, fixture: &FixtureCase, expected: &ExpectedRecord, actual: &CanonicalRecord, files: &[polymodel_ldraw_core::OwnedVirtualFile], ) -> Result<(), GateFailure> { let definition = self.definition; let fail = |field: &str| { Err(GateFailure::FieldMismatch { gate: definition.id.into(), fixture: fixture.id.into(), field: field.into(), }) }; if !definition.profiles.contains(&expected.profile) || !fixture.applies_to(expected.profile) || !definition.tags.iter().any(|tag| fixture.tags.contains(tag)) { return Err(GateFailure::NotApplicable { gate: definition.id.into(), fixture: fixture.id.into(), profile: expected.profile, }); } if actual.schema_version != polymodel_ldraw_core::SCHEMA_VERSION || expected.oracle_expected.schema_version != crate::ORACLE_SCHEMA_VERSION { return Err(GateFailure::SchemaMismatch { gate: definition.id.into(), fixture: fixture.id.into(), }); } match definition.id { "texmap_projection_v1" => { let actual = serde_json::Value::Array( actual .semantic .texmap_events .iter() .map(|event| { serde_json::json!({ "kind": event.kind, "mode": event.mode, "parameters": event.parameters, "reference": event.reference, "state": event.state, }) }) .collect(), ); let expected = serde_json::Value::Array( expected.polymodel_policy_expected.texmap_events.clone(), ); if actual == expected { Ok(()) } else { Err(GateFailure::FieldMismatch { gate: definition.id.into(), fixture: fixture.id.into(), field: format!( "polymodel_policy_expected.texmap_events actual={actual} expected={expected}" ), }) } } "mpd_and_data_boundaries" => { let actual = serde_json::Value::Array(data_payload_values(files)); let expected = serde_json::Value::Array( expected.polymodel_policy_expected.data_payloads.clone(), ); if actual == expected { Ok(()) } else { fail("polymodel_policy_expected.data_payloads") } } "numeric_finiteness_and_raw_preservation" => { if actual.syntax.is_empty() || actual .syntax .iter() .any(|record| record.raw_tail.is_empty() && record.fields.is_empty()) || actual .diagnostics .iter() .any(|diagnostic| diagnostic.message.is_empty()) { return fail("candidate.syntax"); } Ok(()) } "semantic_limits_and_cancellation" => { let expected = &expected.polymodel_policy_expected.limits; if actual .semantic .limits .iter() .map(|value| value.to_string()) .collect::<Vec<_>>() == *expected { Ok(()) } else { fail("polymodel_policy_expected.limits") } } "syntax_types_0_to_5" | "profile_acceptance_and_diagnostics" | "conditional_line_projection" | "points_and_explicit_edges" => { for field in definition.required_fields { let present = match *field { "candidate.syntax" => !actual.syntax.is_empty(), "candidate.diagnostics" => actual .diagnostics .iter() .all(|diagnostic| !diagnostic.message.is_empty()), "candidate.scene" => { actual.scene.instances.len() == actual.scene.instance_ids.len() && actual.scene.bounds.is_none_or(|bounds| { bounds.min.x <= bounds.max.x && bounds.min.y <= bounds.max.y && bounds.min.z <= bounds.max.z }) } "candidate.semantic.limits" => !actual.semantic.limits.is_empty(), "candidate.semantic.texmap_events" => { actual.semantic.texmap_events.iter().all(|event| { event .reference .as_ref() .is_none_or(|reference| !reference.is_empty()) }) } "candidate.semantic.canonical_path" => { actual.semantic.canonical_path.is_some() } "candidate.semantic.target_identity" => { actual.semantic.target_identity.is_some() } _ => { return Err(GateFailure::MissingAuthority { gate: definition.id.into(), fixture: fixture.id.into(), field: (*field).into(), }); } }; if !present { return Err(GateFailure::MissingAuthority { gate: definition.id.into(), fixture: fixture.id.into(), field: (*field).into(), }); } } Ok(()) } "path_and_resolution_independence" => { for field in definition.required_fields { let present = match *field { "candidate.semantic.canonical_path" => { actual.semantic.canonical_path.is_some() } "candidate.semantic.root_identity" => { actual.semantic.root_identity.is_some() } "candidate.semantic.target_identity" => { actual.semantic.target_identity.is_some() } "candidate.semantic.cache_identity" => { actual.semantic.cache_identity.is_some() } _ => { return Err(GateFailure::MissingAuthority { gate: definition.id.into(), fixture: fixture.id.into(), field: (*field).into(), }); } }; if !present { return Err(GateFailure::MissingAuthority { gate: definition.id.into(), fixture: fixture.id.into(), field: (*field).into(), }); } } Ok(()) } "bfc_state_and_invertnext" => { if actual.semantic.bfc_state == polymodel_ldraw_core::BfcState::Unknown { return fail("candidate.semantic.bfc_state"); } Ok(()) } "colours_and_ldconfig" => { if let Some(model) = expected.oracle_expected.root_model.as_ref() && u64::from(actual.semantic.colour_state.0) != model.default_color { return fail("candidate.semantic.colour_state"); } Ok(()) } "graph_identity_and_instances" => { let ids = actual .scene .instances .iter() .map(|instance| instance.instance_id.as_str()) .collect::<Vec<_>>(); if ids.len() != actual.scene.instance_ids.len() || ids .iter() .zip(&actual.scene.instance_ids) .any(|(actual, expected)| *actual != expected) || actual .scene .instances .windows(2) .any(|instances| instances[0].instance_id == instances[1].instance_id) || actual.scene.instances.iter().any(|instance| { instance.source_model.is_empty() || instance.target_model.is_empty() }) { return fail("candidate.scene.instances"); } Ok(()) } "steps_and_transforms" => { let expected_steps = expected .oracle_expected .root_model .as_ref() .ok_or_else(|| GateFailure::MissingAuthority { gate: definition.id.into(), fixture: fixture.id.into(), field: "oracle_expected.root_model.step_ends".into(), })? .step_ends .len(); if actual.semantic.steps.len() != expected_steps { return fail("candidate.semantic.steps"); } if actual.scene.reflection && actual.scene.bounds.is_none() { return fail("candidate.scene.reflection"); } Ok(()) } other => Err(GateFailure::MissingAuthority { gate: other.into(), fixture: fixture.id.into(), field: "unknown gate field".into(), }), } }}
fn data_payload_values(files: &[polymodel_ldraw_core::OwnedVirtualFile]) -> Vec<serde_json::Value> { let mut payloads = Vec::new(); let mut data_name = None; let mut encoded = String::new(); for line in files.iter().flat_map(|file| file.lines.iter()) { let text = String::from_utf8_lossy(line); let text = text.trim_end_matches(['\r', '\n']).trim(); if let Some(name) = text.strip_prefix("0 !DATA ") { flush_data_payload(&mut payloads, &mut data_name, &mut encoded); data_name = Some(name.trim().to_owned()); } else if data_name.is_some() && text.starts_with("0 !:") { encoded.push_str(text[4..].trim()); } else { flush_data_payload(&mut payloads, &mut data_name, &mut encoded); } } flush_data_payload(&mut payloads, &mut data_name, &mut encoded); payloads}
fn flush_data_payload( payloads: &mut Vec<serde_json::Value>, data_name: &mut Option<String>, encoded: &mut String,) { let Some(filename) = data_name.take() else { return; }; let value = std::mem::take(encoded); if let Some(bytes) = decode_base64(&value) { payloads.push(serde_json::json!({"filename": filename, "bytes": bytes})); }}
fn decode_base64(encoded: &str) -> Option<Vec<u8>> { const ALPHABET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; let clean = encoded .bytes() .filter(|byte| !byte.is_ascii_whitespace()) .collect::<Vec<_>>(); if clean.is_empty() || clean.len() % 4 != 0 { return None; } let mut output = Vec::new(); for chunk in clean.chunks_exact(4) { let value = |byte: u8| -> Option<u32> { if byte == b'=' { Some(0) } else { ALPHABET .iter() .position(|candidate| *candidate == byte) .map(|index| index as u32) } }; let a = value(chunk[0])?; let b = value(chunk[1])?; let c = value(chunk[2])?; let d = value(chunk[3])?; output.push(((a << 2) | (b >> 4)) as u8); if chunk[2] != b'=' { output.push(((b << 4) | (c >> 2)) as u8); } if chunk[3] != b'=' { output.push(((c << 6) | d) as u8); } } Some(output)}
pub fn named_gates() -> Vec<NamedGate> { GATE_DEFINITIONS .iter() .map(|definition| NamedGate { definition }) .collect()}
#[derive(Debug, Error, Clone, PartialEq, Eq)]pub enum GateSetError { #[error("duplicate gate name: {0}")] DuplicateName(String), #[error("missing required gate: {0}")] MissingRequiredGate(String), #[error("fixture {0} has no applicable gate")] NoApplicableGate(String),}
pub struct CorpusGateSet { gates: Vec<NamedGate>,}
impl CorpusGateSet { pub fn new(gates: Vec<NamedGate>) -> Result<Self, GateSetError> { let mut names = BTreeSet::new(); for gate in &gates { if !names.insert(gate.definition.id) { return Err(GateSetError::DuplicateName(gate.definition.id.into())); } } for required in GATE_NAMES { if !names.contains(required) { return Err(GateSetError::MissingRequiredGate((*required).into())); } } Ok(Self { gates }) }
pub fn gates(&self) -> &[NamedGate] { &self.gates }
pub fn validate_inventory(&self, fixtures: &[FixtureCase]) -> Result<(), GateSetError> { for fixture in fixtures { if !self.gates.iter().any(|gate| { gate.definition .tags .iter() .any(|tag| fixture.tags.contains(tag)) }) { return Err(GateSetError::NoApplicableGate(fixture.id.into())); } } Ok(()) }
pub fn evaluate( &self, fixture: &FixtureCase, actual: &CanonicalRecord, ) -> Vec<Result<(), GateFailure>> { self.gates .iter() .filter(|gate| { gate.definition .tags .iter() .any(|tag| fixture.tags.contains(tag)) && fixture.applies_to(fixture.expected.profile) }) .map(|gate| gate.evaluate(fixture, &fixture.expected, actual)) .collect() }
pub fn evaluate_with_files( &self, fixture: &FixtureCase, actual: &CanonicalRecord, files: &[polymodel_ldraw_core::OwnedVirtualFile], ) -> Vec<Result<(), GateFailure>> { self.gates .iter() .filter(|gate| { gate.definition .tags .iter() .any(|tag| fixture.tags.contains(tag)) && fixture.applies_to(fixture.expected.profile) }) .map(|gate| gate.evaluate_with_files(fixture, &fixture.expected, actual, files)) .collect() }
pub fn evaluate_rejection( &self, fixture: &FixtureCase, error: &polymodel_ldraw_core::LdrawError, ) -> Vec<Result<(), GateFailure>> { self.gates .iter() .filter(|gate| { gate.definition .tags .iter() .any(|tag| fixture.tags.contains(tag)) && fixture.applies_to(fixture.expected.profile) }) .map(|gate| gate.evaluate_rejection(fixture, &fixture.expected, error)) .collect() }}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]pub struct CoverageReport { pub schema_version: String, pub fixture_count: usize, pub byte_count: usize, pub gates: Vec<String>, pub profiles: Vec<Profile>, pub tags: Vec<String>,}
pub fn coverage_report(fixtures: &[FixtureCase]) -> CoverageReport { let mut tags = BTreeSet::new(); for fixture in fixtures { tags.extend(fixture.tags.iter().map(|tag| (*tag).to_string())); } CoverageReport { schema_version: SCHEMA_VERSION.into(), fixture_count: fixtures.len(), byte_count: fixtures.iter().map(|fixture| fixture.bytes.len()).sum(), gates: GATE_NAMES.iter().map(|name| (*name).into()).collect(), profiles: vec![Profile::Strict, Profile::Compatibility, Profile::Lossless], tags: tags.into_iter().collect(), }}
pub fn compare_oracle_expected( expected_projection: &OracleProjection, actual_projection: &OracleProjection, fixture: &str,) -> Result<(), GateFailure> { let field_mismatch = |field: &str| GateFailure::FieldMismatch { gate: "oracle_expected".into(), fixture: fixture.into(), field: field.into(), }; if expected_projection.schema_version != actual_projection.schema_version { return Err(field_mismatch("schema_version")); } for (field, expected, actual) in [ ( "oracle_revision", &expected_projection.oracle_revision, &actual_projection.oracle_revision, ), ( "wrapper_schema_version", &expected_projection.wrapper_schema_version, &actual_projection.wrapper_schema_version, ), ( "projection_rule_version", &expected_projection.projection_rule_version, &actual_projection.projection_rule_version, ), ( "patch_identity", &expected_projection.patch_identity, &actual_projection.patch_identity, ), ( "fixture_path", &expected_projection.fixture_path, &actual_projection.fixture_path, ), ( "fixture_sha256", &expected_projection.fixture_sha256, &actual_projection.fixture_sha256, ), ( "status", &expected_projection.status, &actual_projection.status, ), ] { if expected != actual { return Err(field_mismatch(field)); } } if expected_projection.model_names != actual_projection.model_names { return Err(field_mismatch("model_names")); } if expected_projection.root_model != actual_projection.root_model { return Err(field_mismatch("root_model")); } if expected_projection.models != actual_projection.models { return Err(field_mismatch("models")); } if expected_projection.tokenized_models != actual_projection.tokenized_models { return Err(field_mismatch("tokenized_models")); } if expected_projection.tokenized_geometry != actual_projection.tokenized_geometry { return Err(field_mismatch("tokenized_geometry")); } if expected_projection.resolved_geometry != actual_projection.resolved_geometry { return Err(field_mismatch("resolved_geometry")); } if expected_projection.diagnostics != actual_projection.diagnostics { return Err(field_mismatch("diagnostics")); } if expected_projection.error != actual_projection.error { return Err(field_mismatch("error")); } if expected_projection.authority_rules != actual_projection.authority_rules { return Err(field_mismatch("authority_rules")); } Ok(())}
#[cfg(test)]mod tests { use super::*; use crate::OracleDiagnostic;
#[test] fn gate_definitions_are_unique_and_complete() { let gates = CorpusGateSet::new(named_gates()).unwrap(); assert_eq!(gates.gates().len(), GATE_NAMES.len()); }
#[test] fn oracle_comparison_rejects_each_projection_metadata_change() { let fixtures = crate::inventory(); let expected = &fixtures[0].expected.oracle_expected; let mut actual = expected.clone(); actual.patch_identity.push_str("-tampered"); let error = compare_oracle_expected(expected, &actual, fixtures[0].id).unwrap_err(); assert!( matches!(error, GateFailure::FieldMismatch { field, .. } if field == "patch_identity") );
let mut actual = expected.clone(); actual.diagnostics.push(OracleDiagnostic { message: "unexpected".into(), token: "token".into(), fatal: false, }); let error = compare_oracle_expected(expected, &actual, fixtures[0].id).unwrap_err(); assert!( matches!(error, GateFailure::FieldMismatch { field, .. } if field == "diagnostics") ); }
#[test] fn live_testkit_sources_do_not_contain_heuristic_generators() { let source_root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src"); let files = ["schema.rs", "inventory.rs", "gates.rs", "lib.rs"]; let canonical = ["canonical", "("].concat(); let parse_syntax = ["parse_syntax", "("].concat(); for file in files { let source = std::fs::read_to_string(source_root.join(file)).unwrap(); let has_canonical_call = source.match_indices(&canonical).any(|(index, _)| { index == 0 || (!source.as_bytes()[index - 1].is_ascii_alphanumeric() && source.as_bytes()[index - 1] != b'_') }); assert!( !has_canonical_call, "heuristic generator call found in {file}" ); assert!( !source.contains(&parse_syntax), "heuristic generator call found in {file}" ); } }}