test: prune duplicate tests, re-sight two blind coverage guards

Follow-up to a fan-out audit of the whole test suite (742 tests, 21
read-only assessors + synthesis). Two clusters of the audit were
actioned here; the #66 hashing-removal cohort it surfaced is left for
the #66 scope, and the RED-first doc-rot sweep is deferred.

§2 — true duplicates removed (each kept test is a strict superset or
identical fixture+assertions of the deleted one):
- ailang-check param_in_reject_message_names_allowed_set (kept the
  _renders_allowed_set_in_ailang_syntax superset)
- ailang-check cross_module_pat_ctor_typedriven_resolves (kept ct2_;
  shared cross_module_ws helper retained, 2 other callers)
- ailang-core mq1_qualified_instancedef_class_accepted (kept ct1_)
- ail e2e bool_to_str_emits_true_branch (kept the rc-stats superset)
- ail loop_recur_str adt-leg guard (the standalone heap pin owns it;
  dropped the dangling header reference too)
- ailang-check over_strict_mode_silent_when_param_is_borrow (its
  assertion is subsumed by explicit_fn_with_no_uses_is_clean; its own
  doc claimed a "borrowing body" the Lit body never provided)

§4 — meta-guards that had gone partially blind re-sighted:
- spec_drift::spec_mentions_every_def_kind now pushes Class/Instance
  exemplars and asserts their `(class `/`(instance` anchors; the
  "wait for 22b.4" exclusion was stale (anchors shipped in e809f45).
- schema_coverage now tracks Term::New (VariantTag + EXPECTED +
  visitor insert); the new_*/raw_buf_* fixtures already exercise it,
  so the "no fixture emits new" exclusion was stale.
- prose doc_wrap_widow_control_skips_when_combined_too_long was
  tautological: its 32/32/42-char words gave combined=75<=80, so
  widow control actually fired. Rebuilt the fixture (short head + two
  40-char words → combined=81>80) so it hits the real skip branch,
  and added the missing "last line stays 1 word" assertion. The
  obvious 2-word fixture does NOT work — it skips via the
  prev_words<2 branch, not the combined-over-budget branch.

ailang-check 124->121, ailang-core 55->54, e2e 102->101,
loop_recur_str 4->3; spec_drift 8 green, schema_coverage green,
prose lib 63 green.
This commit is contained in:
2026-06-02 16:59:43 +02:00
parent 426ce88d2a
commit 72d2d9c806
8 changed files with 43 additions and 203 deletions
-34
View File
@@ -2638,40 +2638,6 @@ mod tests {
}
}
/// a qualified `InstanceDef.class` referencing a class in
/// an imported module is the canonical form post-canonical-class-form and is
/// accepted by `validate_canonical_type_names`. Symmetric to the canonical-form rule's
/// "qualified Type::Con resolves" positive path.
#[test]
fn mq1_qualified_instancedef_class_accepted() {
let a: Module = serde_json::from_value(serde_json::json!({
"schema": crate::SCHEMA,
"name": "A",
"imports": [],
"defs": [{
"kind": "class",
"name": "Show",
"param": "a",
"methods": []
}]
})).unwrap();
let b: Module = serde_json::from_value(serde_json::json!({
"schema": crate::SCHEMA,
"name": "B",
"imports": [{ "module": "A" }],
"defs": [{
"kind": "instance",
"class": "A.Show",
"type": { "k": "con", "name": "Int" },
"methods": []
}]
})).unwrap();
let mut modules = BTreeMap::new();
modules.insert("A".to_string(), a);
modules.insert("B".to_string(), b);
validate_canonical_type_names(&modules, &["prelude"]).expect("qualified A.Show must be accepted");
}
/// pd.1 Task 1: `load_modules_with` returns modules without injecting
/// prelude. The prelude inject is the caller's responsibility (the
/// shim `load_workspace_with` does it in pd.1; surface owns it from
+5 -7
View File
@@ -50,6 +50,7 @@ enum VariantTag {
TermReuseAs,
TermLoop,
TermRecur,
TermNew,
TermIntrinsic,
// Pattern
PatternWild,
@@ -97,6 +98,7 @@ const EXPECTED_VARIANTS: &[VariantTag] = &[
VariantTag::TermReuseAs,
VariantTag::TermLoop,
VariantTag::TermRecur,
VariantTag::TermNew,
VariantTag::TermIntrinsic,
VariantTag::PatternWild,
VariantTag::PatternVar,
@@ -248,13 +250,9 @@ fn visit_term(t: &Term, observed: &mut HashSet<VariantTag>) {
}
}
Term::New { args, .. } => {
// prep.2 (kernel-extension-mechanics): functional construction.
// The variant is intentionally NOT added to `VariantTag` /
// `EXPECTED_VARIANTS` in prep.2 — no .ail fixture in the
// current corpus emits `"t": "new"` (per the iter's
// out-of-scope note), so an EXPECTED entry would fail the
// coverage check. A future milestone that ships a Term::New
// fixture extends both the enum and the expected list.
// Functional construction. Exercised by the `new_*` /
// `raw_buf_*` fixtures under examples/.
observed.insert(VariantTag::TermNew);
for arg in args {
match arg {
NewArg::Type(t) => visit_type(t, observed),
+19 -7
View File
@@ -14,7 +14,8 @@
use std::collections::BTreeMap;
use ailang_core::ast::{
ConstDef, Ctor, Def, FnDef, Literal, NewArg, Pattern, Suppress, Term, Type, TypeDef,
ClassDef, ConstDef, Ctor, Def, FnDef, InstanceDef, Literal, NewArg, Pattern, Suppress, Term,
Type, TypeDef,
};
use ailang_core::FORM_A_SPEC;
@@ -293,10 +294,27 @@ fn spec_mentions_every_def_kind() {
drop_iterative: false,
param_in: BTreeMap::new(),
};
let class_def = ClassDef {
name: "C".into(),
param: "a".into(),
superclass: None,
methods: vec![],
doc: None,
};
let instance_def = InstanceDef {
class: "C".into(),
type_: Type::int(),
methods: vec![],
doc: None,
};
let exemplars: Vec<(&str, Def)> = vec![
("(fn ", Def::Fn(fn_def)),
("(const ", Def::Const(const_def)),
("(data ", Def::Type(type_def)),
// class/instance gained prose projection in e809f45 (form-a.tidy):
// FORM_A_SPEC now carries `(class ` / `(instance ` anchors.
("(class ", Def::Class(class_def)),
("(instance", Def::Instance(instance_def)),
];
for (anchor, def) in exemplars {
@@ -304,12 +322,6 @@ fn spec_mentions_every_def_kind() {
Def::Fn(_) => "fn",
Def::Const(_) => "const",
Def::Type(_) => "type",
// class/instance Def variants exist but are
// not yet anchored in the prose-spec block. Once 22b.4
// adds prose projection for them, the FORM_A_SPEC text
// gains `(class ` / `(instance ` anchors and this match
// will be exercised. For 22b.1 the exemplars list above
// does not produce these variants.
Def::Class(_) => "class",
Def::Instance(_) => "instance",
};