diff options
Diffstat (limited to 'internal/game/core_course_test.go')
| -rw-r--r-- | internal/game/core_course_test.go | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/internal/game/core_course_test.go b/internal/game/core_course_test.go new file mode 100644 index 0000000..3d9fdc2 --- /dev/null +++ b/internal/game/core_course_test.go @@ -0,0 +1,140 @@ +package game + +import ( + "os" + "path/filepath" + "testing" +) + +func TestResolvePhasesPrefersExplicitPhases(t *testing.T) { + obs := ObstacleDef{ + RoomID: 5, + Verb: "climb", + Phases: []ObstaclePhase{ + {Message: "start", Delay: 0}, + {Message: "middle", Delay: 2, FailCheck: true}, + {Message: "end", Delay: 1.5}, + }, + // Legacy fields set as a decoy; should be ignored when Phases present. + TicksPerPhase: 99, + Messages: []string{"ignored1", "ignored2", "ignored3"}, + } + got := resolvePhases(obs) + if len(got) != 3 { + t.Fatalf("expected 3 phases, got %d", len(got)) + } + if got[0].Message != "start" || got[0].Delay != 0 || got[0].FailCheck { + t.Errorf("phase 0 wrong: %+v", got[0]) + } + if got[1].Message != "middle" || got[1].Delay != 2 || !got[1].FailCheck { + t.Errorf("phase 1 (fail check) wrong: %+v", got[1]) + } + if got[2].Message != "end" || got[2].Delay != 1.5 { + t.Errorf("phase 2 wrong: %+v", got[2]) + } +} + +func TestResolvePhasesLegacyMigration(t *testing.T) { + obs := ObstacleDef{ + RoomID: 7, + Verb: "jump", + TicksPerPhase: 2, + Messages: []string{"a", "b", "c"}, + } + got := resolvePhases(obs) + if len(got) != 3 { + t.Fatalf("expected 3 legacy phases, got %d", len(got)) + } + if got[0].Message != "a" || got[0].Delay != 0 || got[0].FailCheck { + t.Errorf("legacy phase 0 wrong: %+v", got[0]) + } + if got[1].Message != "b" || got[1].Delay != 2 || !got[1].FailCheck { + t.Errorf("legacy phase 1 must carry fail_check at index 1: %+v", got[1]) + } + if got[2].Message != "c" || got[2].Delay != 2 || got[2].FailCheck { + t.Errorf("legacy phase 2 wrong: %+v", got[2]) + } +} + +func TestCourseStoreLoadsWithExplicitFailChance(t *testing.T) { + dir := t.TempDir() + coursesDir := filepath.Join(dir, "courses") + if err := os.MkdirAll(coursesDir, 0755); err != nil { + t.Fatal(err) + } + yaml := []byte(` +name: "Test Course" +required_level: 10 +start_room: 100 +completion_xp: 50 +obstacles: + - room_id: 101 + verb: climb + xp: 12 + fail_damage: [2, 5] + fail_chance: 0.20 + phases: + - message: "begin" + delay: 0 + - message: "mid" + delay: 2 + fail_check: true + - message: "done" + delay: 2 + - room_id: 102 + verb: jump + xp: 14 + fail_damage: [1, 3] + messages: ["p0", "p1", "p2"] + ticks_per_phase: 1 +`) + if err := os.WriteFile(filepath.Join(coursesDir, "testcourse.yaml"), yaml, 0644); err != nil { + t.Fatal(err) + } + + cs := NewCourseStore(dir) + cs.LoadAll() + + // Obstacle 1: explicit phases + explicit fail_chance + o1 := cs.GetObstacle(101) + if o1 == nil { + t.Fatal("expected obstacle for room 101") + } + if len(o1.Phases) != 3 || o1.Phases[1].FailCheck != true { + t.Errorf("obstacle 1 phases wrong: %+v", o1.Phases) + } + if o1.FailChance == nil || *o1.FailChance != 0.20 { + t.Errorf("expected explicit fail_chance 0.20, got %v", o1.FailChance) + } + if o1.ObstacleIndex != 0 || o1.TotalObstacles != 2 { + t.Errorf("index/total wrong: %d/%d", o1.ObstacleIndex, o1.TotalObstacles) + } + if o1.NextRoom != 102 { + t.Errorf("expected next room 102, got %d", o1.NextRoom) + } + if o1.CompletionXP != 0 { + t.Errorf("first obstacle should have no completion xp, got %d", o1.CompletionXP) + } + + // Obstacle 2: legacy migration, derived fail chance (nil) + o2 := cs.GetObstacle(102) + if o2 == nil { + t.Fatal("expected obstacle for room 102") + } + if len(o2.Phases) != 3 || !o2.Phases[1].FailCheck { + t.Errorf("legacy obstacle phases not migrated: %+v", o2.Phases) + } + if o2.FailChance != nil { + t.Errorf("legacy obstacle should have nil (derived) fail_chance, got %v", *o2.FailChance) + } + if o2.CompletionXP != 50 { + t.Errorf("last obstacle should carry completion_xp, got %d", o2.CompletionXP) + } + if o2.NextRoom != 0 { + t.Errorf("last obstacle should have next_room 0, got %d", o2.NextRoom) + } + + if cs.GetObstacle(999) != nil { + t.Error("expected nil for unrelated room") + } +}
\ No newline at end of file |
