Add a real test suite for the save system (previously had none)
Covers save.c (device discovery/orchestration), savedevice.c (the generic device state machine and platform dispatch), and the Linux platform backend (path building, availability checks, JSON read/write, corrupt/missing-file handling), plus saveslot.c/savesettings.c JSON round-trips. 88 tests across 5 files, all run against the real Linux filesystem backend sandboxed to a temp $HOME (there's no mockable platform layer - the hooks are compile-time macros, not function pointers). Deliberately locks in two existing behaviors rather than working around them: saveSaveSettings() is a permanent no-op because nothing anywhere ever sets SAVE.settingsDirty = true, and saveUpdate() unconditionally rewrites settings back out the moment a device is found regardless of that same dirty flag. Both are pre-existing, not introduced here. Does not cover the SAVE_DEVICE_DATA_RAW blob codec (PSP/GameCube/Wii only) or GameCube's 2-device fallback chain - neither compiles into the Linux host test build. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
// nftw()/FTW_DEPTH/FTW_PHYS are glibc extensions gated behind this.
|
||||
#define _XOPEN_SOURCE 700
|
||||
|
||||
#include "savetestfixture.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
#include <ftw.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static char_t SAVE_TEST_FIXTURE_HOME[PATH_MAX];
|
||||
static char_t SAVE_TEST_FIXTURE_REAL_HOME[PATH_MAX];
|
||||
static bool_t SAVE_TEST_FIXTURE_HAD_REAL_HOME;
|
||||
|
||||
static int_t saveTestFixtureRemoveEntry(
|
||||
const char *path,
|
||||
const struct stat *statBuffer,
|
||||
int typeFlag,
|
||||
struct FTW *ftwBuffer
|
||||
) {
|
||||
return remove(path);
|
||||
}
|
||||
|
||||
int saveTestFixtureSetup(void **state) {
|
||||
const char_t *realHome = getenv("HOME");
|
||||
SAVE_TEST_FIXTURE_HAD_REAL_HOME = realHome != NULL;
|
||||
if(realHome != NULL) {
|
||||
stringCopy(
|
||||
SAVE_TEST_FIXTURE_REAL_HOME, realHome, sizeof(SAVE_TEST_FIXTURE_REAL_HOME) - 1
|
||||
);
|
||||
}
|
||||
|
||||
stringCopy(
|
||||
SAVE_TEST_FIXTURE_HOME, "/tmp/dusk-save-test-XXXXXX",
|
||||
sizeof(SAVE_TEST_FIXTURE_HOME) - 1
|
||||
);
|
||||
assertNotNull(mkdtemp(SAVE_TEST_FIXTURE_HOME), "Failed to create temp $HOME");
|
||||
|
||||
assertTrue(setenv("HOME", SAVE_TEST_FIXTURE_HOME, 1) == 0, "setenv failed");
|
||||
|
||||
errorret_t ret = saveInit();
|
||||
assertTrue(errorIsOk(ret), "saveInit failed in test fixture");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int saveTestFixtureTeardown(void **state) {
|
||||
nftw(SAVE_TEST_FIXTURE_HOME, saveTestFixtureRemoveEntry, 16, FTW_DEPTH | FTW_PHYS);
|
||||
|
||||
if(SAVE_TEST_FIXTURE_HAD_REAL_HOME) {
|
||||
setenv("HOME", SAVE_TEST_FIXTURE_REAL_HOME, 1);
|
||||
} else {
|
||||
unsetenv("HOME");
|
||||
}
|
||||
|
||||
memoryZero(&SAVE, sizeof(SAVE));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void saveTestFixtureBlockSaveDirectory(void) {
|
||||
const char_t *home = getenv("HOME");
|
||||
assertNotNull(home, "Fixture $HOME must be set before blocking it");
|
||||
|
||||
char_t path[PATH_MAX];
|
||||
stringFormat(path, sizeof(path), "%s/.dusk", home);
|
||||
|
||||
FILE *file = fopen(path, "w");
|
||||
assertNotNull(file, "Failed to create blocking file");
|
||||
fclose(file);
|
||||
}
|
||||
Reference in New Issue
Block a user