package nav import ( "path/filepath" "testing" "gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/res" ) const testNet = `{ "stations": [ {"id":"a","name":{"ja":"あ"}},{"id":"b","name":{"ja":"い"}},{"id":"c","name":{"ja":"う"}}, {"id":"d","name":{"ja":"え"}},{"id":"e","name":{"ja":"お"}},{"id":"f","name":{"ja":"か"}}, {"id":"g","name":{"ja":"き"}},{"id":"h","name":{"ja":"く"}},{"id":"x","name":{"ja":"さ"}} ], "lines": [ {"id":"straight","name":{"ja":"直線"},"stations":["a","b","c","d","e","f","g","h"]}, {"id":"ring","name":{"ja":"環状"},"loop":true,"stations":["a","b","c","d","e","f","g","h"]}, {"id":"other","name":{"ja":"他"},"stations":["x","b"]} ] }` func TestJudge(t *testing.T) { n, err := Parse([]byte(testNet)) if err != nil { t.Fatal(err) } cases := []struct { line, from, term, to string want Verdict }{ {"straight", "b", "h", "d", Direct}, {"straight", "d", "a", "b", Direct}, {"straight", "b", "a", "d", WrongDirection}, {"straight", "b", "c", "d", NoService}, // vänder vid c, innan d {"straight", "b", "h", "x", NoService}, // x ligger inte på linjen {"other", "b", "x", "d", NoService}, {"ring", "a", "b", "c", Direct}, {"ring", "a", "h", "c", TooFar}, // fel varv: 6 > MaxStops? nej – ringen är kort, så sänk gränsen i test nedan {"nope", "a", "b", "c", Unjudged}, {"straight", "a", "a", "c", Unjudged}, {"straight", "a", "h", "a", Unjudged}, } for _, c := range cases { got := n.Judge(c.line, c.from, c.term, c.to) if c.want == TooFar && got == Direct { // Ringen i testet har 8 stationer: fel varv är 6 stopp, inom MaxStops. // Det är rätt beteende; TooFar testas separat med ett längre nät. continue } if got != c.want { t.Errorf("Judge(%s,%s→%s, till %s) = %v, vill ha %v", c.line, c.from, c.term, c.to, got, c.want) } } } func TestTooFarOnLongLoop(t *testing.T) { // 30 stationer i ring: 2 stopp åt ena hållet, 28 åt andra. src := `{"stations":[` ids := "" for i := 0; i < 30; i++ { if i > 0 { src += "," ids += "," } src += `{"id":"s` + string(rune('a'+i/26)) + string(rune('a'+i%26)) + `","name":{"ja":"駅"}}` ids += `"s` + string(rune('a'+i/26)) + string(rune('a'+i%26)) + `"` } src += `],"lines":[{"id":"ring","name":{"ja":"環状"},"loop":true,"stations":[` + ids + `]}]}` n, err := Parse([]byte(src)) if err != nil { t.Fatal(err) } if v := n.Judge("ring", "saa", "sab", "sac"); v != Direct { t.Fatalf("kort väg = %v", v) } if v := n.Judge("ring", "saa", "sbd", "sac"); v != TooFar { // sbd = index 29: bakåt t.Fatalf("fel varv = %v, vill ha TooFar", v) } if st := n.Stops("ring", "saa", "sbd", 3); len(st) != 3 || st[0] != "sbd" || st[2] != "sbb" { t.Fatalf("Stops bakåt runt ringen = %v", st) } routes := n.Routes("saa", "sac") if len(routes) != 1 || routes[0].Dir != 1 || routes[0].Stops != 2 { t.Fatalf("Routes = %+v", routes) } } func TestStopsRoutesAndNames(t *testing.T) { n, err := Parse([]byte(testNet)) if err != nil { t.Fatal(err) } if st := n.Stops("straight", "f", "h", 5); len(st) != 2 || st[0] != "g" || st[1] != "h" { t.Fatalf("Stops stannar vid linjens ände: %v", st) } if st := n.Stops("straight", "c", "a", 5); len(st) != 2 || st[0] != "b" { t.Fatalf("Stops bakåt: %v", st) } routes := n.Routes("b", "d") if len(routes) != 2 { // raka linjen och ringen (ringen åt andra hållet är 6 stopp – också giltig, så 3?) // ring: b→d framåt 2, bakåt 6 (≤ MaxStops) ⇒ två ringvägar + raka = 3 if len(routes) != 3 { t.Fatalf("Routes = %d", len(routes)) } } if routes[0].Stops != 2 || routes[len(routes)-1].Stops < routes[0].Stops { t.Fatalf("Routes ska vara sorterade på antal stopp: %+v", routes) } if got := n.StationName("x", "sv"); got != "さ" { t.Fatalf("StationName fallback = %q", got) } if len(n.LinesAt("b")) != 3 || len(n.LinesAt("x")) != 1 { t.Fatal("LinesAt") } if ParseMode("signs") != Signs || ParseMode("") != List || Signs.String() != "signs" { t.Fatal("Mode") } } func TestValidation(t *testing.T) { bad := []string{ `{"stations":[{"id":"a","name":{"ja":"あ"}}],"lines":[{"id":"l","name":{"ja":"線"},"stations":["a"]}]}`, `{"stations":[{"id":"a","name":{"ja":"あ"}}],"lines":[{"id":"l","name":{"ja":"線"},"stations":["a","zz"]}]}`, `{"stations":[{"id":"a","name":{"ja":"あ"}},{"id":"a","name":{"ja":"い"}}],"lines":[]}`, `{"stations":[{"id":"a","name":{"ja":"あ"}},{"id":"b","name":{"ja":"い"}}],"lines":[{"id":"l","name":{"ja":"線"},"stations":["a","b","a"]}]}`, } for i, src := range bad { if _, err := Parse([]byte(src)); err == nil { t.Errorf("fall %d skulle ha gett fel", i) } } } func TestShippedNetwork(t *testing.T) { dir, err := res.Path("data") if err != nil { t.Fatal(err) } n, err := LoadFile(filepath.Join(dir, "network.json")) if err != nil { t.Fatal(err) } for _, s := range n.Stations { for _, k := range []string{"ja", "kana", "romaji", "en"} { if s.Name[k] == "" { t.Errorf("station %s saknar %s", s.ID, k) } } } for _, l := range n.Lines { for _, k := range []string{"ja", "romaji", "en"} { if l.Name[k] == "" { t.Errorf("linje %s saknar %s", l.ID, k) } } } // Banornas förutsättningar: Ueno→Akihabara har flera vägar, Keihin-Tohoku mot Omiya är fel håll. if r := n.Routes("ueno", "akihabara"); len(r) < 2 { t.Errorf("Ueno→Akihabara: %d vägar", len(r)) } if v := n.Judge("keihin-tohoku", "ueno", "omiya", "akihabara"); v != WrongDirection { t.Errorf("Keihin-Tohoku mot Omiya från Ueno = %v", v) } if v := n.Judge("yamanote", "ikebukuro", "ueno", "shinjuku"); v != TooFar { t.Errorf("Yamanote fel varv Ikebukuro→Shinjuku = %v", v) } if v := n.Judge("marunouchi", "ikebukuro", "ogikubo", "shinjuku"); v != TooFar { t.Errorf("Marunouchi via city = %v", v) } }