diff options
| author | historia <[not public]> | 2026-06-28 04:30:11 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-06-28 04:30:11 -0400 |
| commit | fffc132263ab7d3c402992bffbaae4790161f7a7 (patch) | |
| tree | 91151c29c93517dff15a91fec24f36ee98bc38bf /internal | |
| parent | 82c025b3f3e5cac82800ab9d7f11dcb4e3aa884b (diff) | |
| download | thehouseoficarus-fffc132263ab7d3c402992bffbaae4790161f7a7.tar.gz | |
feat: startup validation of opposite-direction exits between rooms
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/validate/checks.go | 47 | ||||
| -rw-r--r-- | internal/validate/local_test.go | 46 | ||||
| -rw-r--r-- | internal/validate/validate.go | 1 |
3 files changed, 94 insertions, 0 deletions
diff --git a/internal/validate/checks.go b/internal/validate/checks.go index 7da2e4a..87c078e 100644 --- a/internal/validate/checks.go +++ b/internal/validate/checks.go @@ -1087,9 +1087,56 @@ func validateTalkConfig(prefix string, cfg *behavior.TalkConfig, itemIDs map[str } } } + return issues } +func validateExitReciprocity(s Source) []Issue { + var issues []Issue + roomIndex := s.World.RoomIndex() + + for srcID := range roomIndex { + src, err := s.World.LoadRoom(srcID) + if err != nil { + continue + } + for dir, exit := range src.Exits { + if exit.Room <= 0 || !roomIndex[exit.Room] { + continue + } + if srcID >= exit.Room { + continue + } + dst, err := s.World.LoadRoom(exit.Room) + if err != nil { + continue + } + expected := world.OppositeExit[dir] + hasCorrect := false + var returnDirs []string + for retDir, retExit := range dst.Exits { + if retExit.Room == srcID { + if retDir == expected { + hasCorrect = true + break + } + returnDirs = append(returnDirs, string(retDir)) + } + } + if !hasCorrect && len(returnDirs) > 0 { + issues = append(issues, Issue{ + Level: "WARN", + Type: "integrity", + Message: fmt.Sprintf( + "Room %d: exit %q to room %d, but return exit(s) %s are not the expected opposite direction %q", + srcID, dir, exit.Room, returnDirs, expected), + }) + } + } + } + + return issues +} func validateUseConfig(prefix string, cfg *behavior.UseConfig, itemIDs map[string]bool) []Issue { var issues []Issue if cfg == nil { diff --git a/internal/validate/local_test.go b/internal/validate/local_test.go index 23bf8ca..d37838e 100644 --- a/internal/validate/local_test.go +++ b/internal/validate/local_test.go @@ -116,6 +116,52 @@ objects: } } +func TestValidateExitReciprocityOK(t *testing.T) { + dir := t.TempDir() + writeFile(t, filepath.Join(dir, "rooms", "1.yaml"), `name: Room One +exits: + north: 2 +`) + writeFile(t, filepath.Join(dir, "rooms", "2.yaml"), `name: Room Two +exits: + south: 1 +`) + issues := validateExitReciprocity(newSource(dir)) + if len(issues) != 0 { + t.Errorf("expected no issues for correct reciprocal exits, got: %+v", issues) + } +} + +func TestValidateExitReciprocityMismatch(t *testing.T) { + dir := t.TempDir() + writeFile(t, filepath.Join(dir, "rooms", "1.yaml"), `name: Room One +exits: + down: 2 +`) + writeFile(t, filepath.Join(dir, "rooms", "2.yaml"), `name: Room Two +exits: + south: 1 +`) + issues := validateExitReciprocity(newSource(dir)) + if !containsMsg(issues, "not the expected opposite direction") { + t.Errorf("expected mismatch warning, got: %+v", issues) + } +} + +func TestValidateExitReciprocityOneWay(t *testing.T) { + dir := t.TempDir() + writeFile(t, filepath.Join(dir, "rooms", "1.yaml"), `name: Room One +exits: + east: 2 +`) + writeFile(t, filepath.Join(dir, "rooms", "2.yaml"), `name: Room Two +`) + issues := validateExitReciprocity(newSource(dir)) + if len(issues) != 0 { + t.Errorf("expected no issues for one-way exit, got: %+v", issues) + } +} + func TestValidateRoomsPartialNameSiblingsOK(t *testing.T) { dir := t.TempDir() writeFile(t, filepath.Join(dir, "rooms", "1.yaml"), `name: Test Room diff --git a/internal/validate/validate.go b/internal/validate/validate.go index 56de6f1..6558216 100644 --- a/internal/validate/validate.go +++ b/internal/validate/validate.go @@ -81,6 +81,7 @@ func Run(s Source) []Issue { issues = append(issues, validateTechs(s)...) issues = append(issues, validateRoomWiring(s)...) issues = append(issues, validateRoomGrid(s)...) + issues = append(issues, validateExitReciprocity(s)...) return issues } |
