feat: Add dummy game utility and enhance testing capabilities
- also improve argument handling
This commit is contained in:
15
Makefile
15
Makefile
@@ -17,11 +17,13 @@ ALL_LIBS := $(LIBS) $(SDL_LIBS) $(FFMPEG_LIBS) -lm
|
||||
|
||||
BUILD_DIR ?= build
|
||||
TARGET = $(BUILD_DIR)/gsplash
|
||||
DUMMY_TARGET = $(BUILD_DIR)/dummy_game
|
||||
SRC = src/gsplash.c
|
||||
DUMMY_SRC = src/dummy_game.c
|
||||
|
||||
.PHONY: all clean install uninstall check
|
||||
|
||||
all: $(TARGET)
|
||||
all: $(TARGET) $(DUMMY_TARGET)
|
||||
|
||||
$(BUILD_DIR):
|
||||
mkdir -p $(BUILD_DIR)
|
||||
@@ -29,11 +31,16 @@ $(BUILD_DIR):
|
||||
$(TARGET): $(BUILD_DIR) $(SRC)
|
||||
$(CC) $(ALL_CFLAGS) $(LDFLAGS) $(SRC) -o $@ $(ALL_LIBS)
|
||||
|
||||
$(DUMMY_TARGET): $(BUILD_DIR) $(DUMMY_SRC)
|
||||
$(CC) $(CFLAGS) $(SDL_CFLAGS) $(LDFLAGS) $(DUMMY_SRC) -o $@ $(SDL_LIBS)
|
||||
|
||||
# Lightweight smoke test (headless via SDL_VIDEODRIVER=dummy)
|
||||
check: $(TARGET)
|
||||
check: $(TARGET) $(DUMMY_TARGET)
|
||||
@echo "Running smoke test (headless)..."
|
||||
SDL_VIDEODRIVER=dummy $(TARGET) nonexistent.png /bin/true || true
|
||||
@echo "Smoke test finished"
|
||||
@echo "Running CLI test suite..."
|
||||
./tests/test_cli.sh
|
||||
@echo "All tests finished successfully"
|
||||
|
||||
install: $(TARGET)
|
||||
install -d "$(DESTDIR)$(bindir)"
|
||||
@@ -43,4 +50,4 @@ uninstall:
|
||||
rm -f "$(DESTDIR)$(bindir)/gsplash"
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET)
|
||||
rm -f $(TARGET) $(DUMMY_TARGET)
|
||||
|
||||
28
README.md
28
README.md
@@ -39,14 +39,38 @@ sudo make install
|
||||
DESTDIR=/some/staging/path make install
|
||||
```
|
||||
|
||||
## Smoke test (headless)
|
||||
## Testing
|
||||
|
||||
Run a lightweight headless smoke test that uses the dummy video driver so it doesn't require a display:
|
||||
Gsplash includes several testing utilities to ensure proper functionality without requiring a heavy game binary.
|
||||
|
||||
### Automated Testing
|
||||
|
||||
Run the automated test suite (which includes a headless smoke test and CLI argument validation) using:
|
||||
|
||||
```bash
|
||||
make check
|
||||
```
|
||||
|
||||
### Interactive Visual Testing
|
||||
|
||||
To physically test the splash screen rendering modes (`stretch`, `center`, `crop`) with a real image, use the interactive test script. It launches `gsplash` with each mode and prompts you to confirm if it displayed correctly:
|
||||
|
||||
```bash
|
||||
./tests/test_interactive.sh path/to/your/image.png
|
||||
```
|
||||
*(Tip: You can place your test images in the `tests/assets/` directory).*
|
||||
|
||||
### Dummy Game Utility
|
||||
|
||||
For manual testing, a `dummy_game` binary is built alongside `gsplash`. It mimics a real game by sleeping to simulate startup time, creating an SDL window to trigger `gsplash`'s focus loss detection and exiting cleanly.
|
||||
|
||||
```bash
|
||||
./build/gsplash path/to/image.png ./build/dummy_game
|
||||
|
||||
# Test with a custom 10 second simulated game load time
|
||||
./build/gsplash path/to/image.png ./build/dummy_game 10
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
|
||||
67
src/dummy_game.c
Normal file
67
src/dummy_game.c
Normal file
@@ -0,0 +1,67 @@
|
||||
#include <SDL2/SDL.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int delay_seconds = 5;
|
||||
if (argc > 1) {
|
||||
int parsed = atoi(argv[1]);
|
||||
if (parsed > 0) {
|
||||
delay_seconds = parsed;
|
||||
}
|
||||
}
|
||||
|
||||
printf("[dummy_game] Simulating engine startup for %d seconds...\n", delay_seconds);
|
||||
for (int i = 0; i < delay_seconds; i++) {
|
||||
sleep(1);
|
||||
printf("[dummy_game] Loading... %d/%d\n", i + 1, delay_seconds);
|
||||
}
|
||||
|
||||
printf("[dummy_game] Creating window to trigger focus-loss on splash screen...\n");
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||
fprintf(stderr, "[dummy_game] SDL Init Failed: %s\n", SDL_GetError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
SDL_Window *window = SDL_CreateWindow(
|
||||
"Dummy Game Window",
|
||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||
800, 600,
|
||||
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE
|
||||
);
|
||||
|
||||
if (!window) {
|
||||
fprintf(stderr, "[dummy_game] Window Creation Failed: %s\n", SDL_GetError());
|
||||
SDL_Quit();
|
||||
return 1;
|
||||
}
|
||||
|
||||
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
||||
if (renderer) {
|
||||
SDL_SetRenderDrawColor(renderer, 0, 120, 255, 255);
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
|
||||
printf("[dummy_game] Window created. Waiting 5 seconds before exiting...\n");
|
||||
|
||||
SDL_Event event;
|
||||
int running = 1;
|
||||
Uint32 start_time = SDL_GetTicks();
|
||||
|
||||
while (running && (SDL_GetTicks() - start_time < 5000)) {
|
||||
while (SDL_PollEvent(&event)) {
|
||||
if (event.type == SDL_QUIT) {
|
||||
running = 0;
|
||||
}
|
||||
}
|
||||
SDL_Delay(50);
|
||||
}
|
||||
|
||||
printf("[dummy_game] Exiting normally.\n");
|
||||
if (renderer) SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_Quit();
|
||||
return 0;
|
||||
}
|
||||
@@ -317,8 +317,14 @@ int main(int argc, char *argv[])
|
||||
render_mode = parse_render_mode(argv[1] + 7);
|
||||
arg_index += 1;
|
||||
}
|
||||
else if (argc >= 4 && strcmp(argv[1], "-m") == 0)
|
||||
else if (argc >= 2 && strcmp(argv[1], "-m") == 0)
|
||||
{
|
||||
if (argc < 4)
|
||||
{
|
||||
log_error("Usage: %s [--mode=stretch|center|crop] <image_path> <game_executable> [args...]", argv[0]);
|
||||
log_error(" %s -m stretch|center|crop <image_path> <game_executable> [args...]", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
render_mode = parse_render_mode(argv[2]);
|
||||
arg_index += 2;
|
||||
}
|
||||
@@ -333,7 +339,7 @@ int main(int argc, char *argv[])
|
||||
const char *image_path = argv[arg_index];
|
||||
const char *game_path = argv[arg_index + 1];
|
||||
|
||||
log_info("Starting splash: image='%s', game='%s'", image_path, game_path);
|
||||
log_info("Starting splash: image='%s', game='%s', mode=%d", image_path, game_path, render_mode);
|
||||
|
||||
// Initialize SDL2 Video subsystems
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0)
|
||||
|
||||
BIN
tests/assets/sample.jpg
Normal file
BIN
tests/assets/sample.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 652 KiB |
83
tests/test_cli.sh
Executable file
83
tests/test_cli.sh
Executable file
@@ -0,0 +1,83 @@
|
||||
#!/bin/bash
|
||||
|
||||
# A test suite for testing CLI argument permutations of gsplash
|
||||
|
||||
GSPLASH="./build/gsplash"
|
||||
GAME="/bin/true"
|
||||
IMAGE="nonexistent.png"
|
||||
|
||||
if [ ! -f "$GSPLASH" ]; then
|
||||
echo "Please run 'make' first to build gsplash."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export SDL_VIDEODRIVER=dummy
|
||||
|
||||
pass=0
|
||||
fail=0
|
||||
|
||||
run_test() {
|
||||
local expected_status=$1
|
||||
shift
|
||||
local expected_log="$1"
|
||||
shift
|
||||
local desc="$1"
|
||||
shift
|
||||
|
||||
printf "Test: %-45s " "$desc"
|
||||
|
||||
# Run the command and capture output
|
||||
local output
|
||||
output=$($GSPLASH "$@" 2>&1)
|
||||
local status=$?
|
||||
|
||||
local passed=true
|
||||
local error_msg=""
|
||||
|
||||
if [ $status -ne $expected_status ]; then
|
||||
passed=false
|
||||
error_msg="Expected status $expected_status, got $status"
|
||||
elif [ -n "$expected_log" ]; then
|
||||
if ! echo "$output" | grep -q "$expected_log"; then
|
||||
passed=false
|
||||
error_msg="Expected log missing: $expected_log"
|
||||
fi
|
||||
fi
|
||||
|
||||
if $passed; then
|
||||
echo "PASS"
|
||||
pass=$((pass+1))
|
||||
else
|
||||
echo "FAIL ($error_msg)"
|
||||
fail=$((fail+1))
|
||||
fi
|
||||
}
|
||||
|
||||
echo "=== Running CLI Argument Tests ==="
|
||||
|
||||
# Valid combinations (0=STRETCH, 1=CENTER, 2=CROP)
|
||||
run_test 0 "mode=1" "Basic invocation" $IMAGE $GAME
|
||||
run_test 0 "mode=0" "Long mode: stretch" --mode=stretch $IMAGE $GAME
|
||||
run_test 0 "mode=1" "Long mode: center" --mode=center $IMAGE $GAME
|
||||
run_test 0 "mode=2" "Long mode: crop" --mode=crop $IMAGE $GAME
|
||||
run_test 0 "mode=0" "Long mode: fallback to stretch" --mode=invalid $IMAGE $GAME
|
||||
run_test 0 "mode=0" "Short mode: stretch" -m stretch $IMAGE $GAME
|
||||
run_test 0 "mode=1" "Short mode: center" -m center $IMAGE $GAME
|
||||
run_test 0 "mode=2" "Short mode: crop" -m crop $IMAGE $GAME
|
||||
run_test 0 "mode=0" "Short mode: fallback to stretch" -m whatever $IMAGE $GAME
|
||||
run_test 0 "mode=1" "With game arguments" $IMAGE $GAME arg1 arg2
|
||||
run_test 0 "mode=2" "Mode and game arguments" -m crop $IMAGE $GAME arg1 arg2
|
||||
|
||||
# Invalid combinations (Usage errors, so we just check for status 1, no specific log needed)
|
||||
run_test 1 "" "No arguments"
|
||||
run_test 1 "" "Only image" $IMAGE
|
||||
run_test 1 "" "Missing arg for short mode (-m only)" -m $IMAGE
|
||||
run_test 1 "" "Missing game for short mode" -m stretch $IMAGE
|
||||
|
||||
echo "================================================="
|
||||
echo "Tests completed: $pass passed, $fail failed."
|
||||
|
||||
if [ $fail -gt 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
69
tests/test_interactive.sh
Executable file
69
tests/test_interactive.sh
Executable file
@@ -0,0 +1,69 @@
|
||||
#!/bin/bash
|
||||
|
||||
GSPLASH="./build/gsplash"
|
||||
DUMMY="./build/dummy_game"
|
||||
|
||||
if [ ! -f "$GSPLASH" ] || [ ! -f "$DUMMY" ]; then
|
||||
echo "Please run 'make' first to build gsplash and dummy_game."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <path_to_test_image_or_video>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IMAGE="$1"
|
||||
if [ ! -f "$IMAGE" ]; then
|
||||
echo "Error: File '$IMAGE' not found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== Interactive gsplash Visual Test ==="
|
||||
echo "This will physically display the splash screen using different modes."
|
||||
echo "You will be asked to confirm if it looked correct after each test."
|
||||
echo ""
|
||||
|
||||
pass=0
|
||||
fail=0
|
||||
|
||||
run_interactive_test() {
|
||||
local mode="$1"
|
||||
|
||||
echo "------------------------------------------------"
|
||||
echo "Testing mode: $mode"
|
||||
echo "Launching in 2 seconds (it will stay open for 3 seconds)..."
|
||||
sleep 2
|
||||
|
||||
# Run gsplash with a 3-second dummy game
|
||||
$GSPLASH --mode="$mode" "$IMAGE" "$DUMMY" 3
|
||||
|
||||
# Prompt the user interactively
|
||||
while true; do
|
||||
read -p "Did it display correctly for mode '$mode'? [y/N] " response
|
||||
case "$response" in
|
||||
[yY][eE][sS]|[yY])
|
||||
echo "=> PASS recorded."
|
||||
pass=$((pass+1))
|
||||
break
|
||||
;;
|
||||
[nN][oO]|[nN]|"")
|
||||
echo "=> FAIL recorded."
|
||||
fail=$((fail+1))
|
||||
break
|
||||
;;
|
||||
*)
|
||||
echo "Please answer y or n."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
run_interactive_test "stretch"
|
||||
run_interactive_test "center"
|
||||
run_interactive_test "crop"
|
||||
|
||||
echo "================================================"
|
||||
echo "Interactive Testing Complete!"
|
||||
echo "Passed: $pass"
|
||||
echo "Failed: $fail"
|
||||
Reference in New Issue
Block a user