package iace import ( "strings" "testing" ) // BuildArchitecture is the data-driven engine self-description rendered in the // "Architektur & Datenfluss" auditability tab. These tests pin its shape and, // crucially, that the library counts are LIVE (non-zero, drawn from the running // engine) — a zero count would mean the diagram silently drifted from reality. func TestBuildArchitecture_Shape(t *testing.T) { a := BuildArchitecture() if len(a.Stages) != 10 { t.Errorf("expected 10 pipeline stages, got %d", len(a.Stages)) } // Stage order is the audit narrative — first is the limits form, last the matrix. if len(a.Stages) > 0 && a.Stages[0].ID != "grenzen" { t.Errorf("first stage should be grenzen, got %q", a.Stages[0].ID) } if last := a.Stages[len(a.Stages)-1]; last.ID != "matrix" { t.Errorf("last stage should be matrix, got %q", last.ID) } for _, s := range a.Stages { if s.Title == "" || s.Summary == "" || s.Logic == "" || s.DataSource == "" { t.Errorf("stage %q has empty required prose: %+v", s.ID, s) } } if len(a.NormMatching) == 0 { t.Error("norm_matching explanation must not be empty") } if len(a.Evidence) == 0 { t.Error("evidence (ESAW citations) must not be empty") } } func TestBuildArchitecture_LiveLibraryCounts(t *testing.T) { a := BuildArchitecture() if len(a.Libraries) == 0 { t.Fatal("no libraries reported") } for _, l := range a.Libraries { if l.Name == "" || l.SourceFile == "" { t.Errorf("library missing name/source: %+v", l) } if l.Count <= 0 { t.Errorf("library %q has non-live count %d (expected >0 from running engine)", l.Name, l.Count) } } } func TestBuildArchitecture_DataSourcesIncludeExclusions(t *testing.T) { a := BuildArchitecture() var hasUsed, hasExcluded bool for _, d := range a.DataSources { switch d.Status { case "verwendet": hasUsed = true case "ausgeschlossen": hasExcluded = true default: t.Errorf("data source %q has unexpected status %q", d.Name, d.Status) } if d.License == "" { t.Errorf("data source %q missing license", d.Name) } } if !hasUsed { t.Error("expected at least one used data source") } // The copyright guardrail is auditable only if the EXCLUDED norm tables are // shown as deliberately not-reproduced — not silently omitted. if !hasExcluded { t.Error("expected DIN/Beuth norm tables to appear as an explicit exclusion") } // The licensing guardrail must be spelled out in the norm-matching prose: // norm tables are referenced, never reproduced. joined := strings.ToLower(strings.Join(a.NormMatching, " ")) if !strings.Contains(joined, "reproduziert") { t.Error("norm-matching prose should state norm tables are never reproduced") } }