package services import ( "reflect" "testing" ) func TestMapLitigationToFristenrechner(t *testing.T) { type tc struct { litigation, jurisdiction string wantCode string wantFlags []string wantOK bool } cases := []tc{ // Unambiguous UPC fold-ins. {"INF", "UPC", CodeUPCInfringement, nil, true}, {"REV", "UPC", CodeUPCRevocation, nil, true}, {"APP", "UPC", CodeUPCAppealMerits, nil, true}, {"APM", "UPC", CodeUPCPreliminary, nil, true}, // CCR + UPC = upc.inf.cfi with the with_ccr flag. {"CCR", "UPC", CodeUPCInfringement, []string{"with_ccr"}, true}, // AMD + UPC = upc.inf.cfi with the with_amend flag. {"AMD", "UPC", CodeUPCInfringement, []string{"with_amend"}, true}, // DE first-instance / Nichtigkeit mappings. {"INF", "DE", CodeDEInfringementLG, nil, true}, {"REV", "DE", CodeDENullityBPatG, nil, true}, {"CCR", "DE", CodeDENullityBPatG, nil, true}, // EPA opposition. {"OPP", "EPA", CodeEPAOpposition, nil, true}, // Ambiguous: APP+DE has both OLG and BGH analogues; project // model can't disambiguate, so degrade. {"APP", "DE", "", nil, false}, // No analogue: ZPO_CIVIL → nothing in fristenrechner. {"ZPO_CIVIL", "DE", "", nil, false}, // AMD only fires on UPC; DE has no analogue. {"AMD", "DE", "", nil, false}, // APM only fires on UPC. {"APM", "EPA", "", nil, false}, // Unknown codes / jurisdictions → ok=false. {"XXX", "UPC", "", nil, false}, {"INF", "ZZZ", "", nil, false}, {"", "", "", nil, false}, } for _, c := range cases { gotCode, gotFlags, gotOK := MapLitigationToFristenrechner(c.litigation, c.jurisdiction) if gotCode != c.wantCode || gotOK != c.wantOK || !reflect.DeepEqual(gotFlags, c.wantFlags) { t.Errorf("MapLitigationToFristenrechner(%q, %q) = (%q, %v, %v); want (%q, %v, %v)", c.litigation, c.jurisdiction, gotCode, gotFlags, gotOK, c.wantCode, c.wantFlags, c.wantOK) } } } func TestResolveCounterclaimRouting(t *testing.T) { t.Run("upc.ccr.cfi routes to upc.inf.cfi with with_ccr", func(t *testing.T) { gotCode, gotFlags, routed := ResolveCounterclaimRouting(CodeUPCCounterclaim) if gotCode != CodeUPCInfringement { t.Errorf("effective code = %q, want %q", gotCode, CodeUPCInfringement) } if !reflect.DeepEqual(gotFlags, []string{"with_ccr"}) { t.Errorf("default flags = %v, want [with_ccr]", gotFlags) } if !routed { t.Errorf("routed = false, want true") } }) t.Run("non-ccr code passes through unchanged", func(t *testing.T) { for _, code := range []string{CodeUPCInfringement, CodeUPCRevocation, CodeDEInfringementLG, "anything-else"} { gotCode, gotFlags, routed := ResolveCounterclaimRouting(code) if gotCode != code { t.Errorf("ResolveCounterclaimRouting(%q) returned %q, want pass-through", code, gotCode) } if gotFlags != nil { t.Errorf("ResolveCounterclaimRouting(%q) flags = %v, want nil", code, gotFlags) } if routed { t.Errorf("ResolveCounterclaimRouting(%q) routed = true, want false", code) } } }) } // TestSubTrackRoutings asserts the registry shape m/paliad#58 depends // on: every entry's Code matches its map key, has a non-empty // ParentCode + DefaultFlags + bilingual notes. Drift here silently // breaks the spawn-as-standalone renderer (a CCR pick would 404 or // render an empty timeline), so we pin the contract. func TestSubTrackRoutings(t *testing.T) { if len(SubTrackRoutings) == 0 { t.Fatal("SubTrackRoutings is empty — at minimum upc.ccr.cfi must be registered") } for key, route := range SubTrackRoutings { if route.Code != key { t.Errorf("SubTrackRoutings[%q].Code = %q, want %q (key/value mismatch)", key, route.Code, key) } if route.ParentCode == "" { t.Errorf("SubTrackRoutings[%q] has empty ParentCode", key) } if len(route.DefaultFlags) == 0 { t.Errorf("SubTrackRoutings[%q] has no DefaultFlags — sub-track routing without flags is a no-op", key) } if route.NoteDE == "" || route.NoteEN == "" { t.Errorf("SubTrackRoutings[%q] missing bilingual note: DE=%q EN=%q", key, route.NoteDE, route.NoteEN) } } // CCR is the canonical entry — assert its exact shape so a future // rename doesn't silently change semantics. ccr, ok := LookupSubTrackRouting(CodeUPCCounterclaim) if !ok { t.Fatal("LookupSubTrackRouting(upc.ccr.cfi) returned ok=false; entry must be registered") } if ccr.ParentCode != CodeUPCInfringement { t.Errorf("CCR.ParentCode = %q, want %q", ccr.ParentCode, CodeUPCInfringement) } if !reflect.DeepEqual(ccr.DefaultFlags, []string{"with_ccr"}) { t.Errorf("CCR.DefaultFlags = %v, want [with_ccr]", ccr.DefaultFlags) } if _, miss := LookupSubTrackRouting(CodeUPCInfringement); miss { t.Error("LookupSubTrackRouting(upc.inf.cfi) returned ok=true; non-sub-track codes must miss") } }