All checks were successful
release / build-release (push) Successful in 1m34s
internal/nav med resources/data/network.json (76 stationer, 11 linjer, Yamanote som ringlinje). Tåg bedöms från lineId + terminus mot banans station/to: rätt, fel håll, för långt bort (fler än 12 stationer) eller ingen trafik; correct räknas ut för nätkopplade banor, 1-4 rätta tåg. Tågresan visar linjens riktiga stationer. Nya förlustorsaker "Fel håll" och "För långt bort". Listläge (nästa tåg nere till vänster) och skyltläge (+50 % poäng) växlas med N på bankartan och sparas; -mode. Terminalen: biljettautomaten visar linjetavlan på nätbanor. Perronger P p Q q R r. Bana 006 Ikebukuro med fyra perronger. Banorna 001-005 kopplade till nätet. Skript: waitover och pick calm; poängraden radbryts; skärmdumpar uppdaterade. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
172 lines
5.7 KiB
Go
172 lines
5.7 KiB
Go
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)
|
||
}
|
||
}
|