From ed414184340875d908193f8f890a5685e7277711 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Mon, 1 Jun 2026 14:50:10 +0200 Subject: [PATCH] test(save): cover version mismatch + slug; clean up tmp on move failure Add loadRejectsIncompatibleVersion test asserting SaveException on schema version 999, assert derived slug in listReturnsSlotMetadata, and harden save() to delete the orphaned .tmp file when the non-atomic fallback move also fails before re-throwing. Co-Authored-By: Claude Sonnet 4.6 --- .../thb/jeanluc/adventure/save/SaveService.java | 7 ++++++- .../thb/jeanluc/adventure/save/SaveServiceTest.java | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/save/SaveService.java b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/save/SaveService.java index b4c5b9e..b5cf690 100644 --- a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/save/SaveService.java +++ b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/save/SaveService.java @@ -52,7 +52,12 @@ public class SaveService { try { Files.move(tmp, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); } catch (IOException atomicFailed) { - Files.move(tmp, target, StandardCopyOption.REPLACE_EXISTING); + try { + Files.move(tmp, target, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException fallbackFailed) { + Files.deleteIfExists(tmp); + throw fallbackFailed; + } } } catch (IOException e) { throw new SaveException("Could not write save '" + session.getSlotName() + "': " + e.getMessage(), e); diff --git a/Semesterprojekt/src/test/java/thb/jeanluc/adventure/save/SaveServiceTest.java b/Semesterprojekt/src/test/java/thb/jeanluc/adventure/save/SaveServiceTest.java index 9dcf54e..e321a87 100644 --- a/Semesterprojekt/src/test/java/thb/jeanluc/adventure/save/SaveServiceTest.java +++ b/Semesterprojekt/src/test/java/thb/jeanluc/adventure/save/SaveServiceTest.java @@ -45,6 +45,7 @@ class SaveServiceTest { List slots = svc.list(); assertThat(slots).hasSize(1); assertThat(slots.getFirst().slotName()).isEqualTo("Alpha Run"); + assertThat(slots.getFirst().slug()).isEqualTo("alpha_run"); assertThat(slots.getFirst().turn()).isEqualTo(3); } @@ -60,4 +61,16 @@ class SaveServiceTest { SaveService svc = new SaveService(dir); assertThrows(SaveException.class, () -> svc.load("bad")); } + + @Test + void loadRejectsIncompatibleVersion(@TempDir Path dir) throws Exception { + // a syntactically valid SaveData JSON but with a future schemaVersion + String json = "{\"schemaVersion\":999,\"worldTitle\":\"X\",\"slotName\":\"v\"," + + "\"savedAtEpochMillis\":0,\"turn\":0,\"currentRoomId\":\"k\"," + + "\"visitedRoomIds\":[],\"gold\":0,\"inventoryItemIds\":[],\"flags\":[]," + + "\"questStages\":{},\"questCompleted\":[],\"roomItemIds\":{},\"switchStates\":{}}"; + Files.writeString(dir.resolve("v.json"), json); + SaveService svc = new SaveService(dir); + assertThrows(SaveException.class, () -> svc.load("v")); + } }