summaryrefslogtreecommitdiff
path: root/src/tests/gpu/test_demo_effects.cc
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-09 20:27:04 +0100
committerskal <pascal.massimino@gmail.com>2026-02-09 20:27:04 +0100
commiteff8d43479e7704df65fae2a80eefa787213f502 (patch)
tree76f2fb8fe8d3db2c15179449df2cf12f7f54e0bf /src/tests/gpu/test_demo_effects.cc
parent12378b1b7e9091ba59895b4360b2fa959180a56a (diff)
refactor: Reorganize tests into subsystem subdirectories
Restructured test suite for better organization and targeted testing: **Structure:** - src/tests/audio/ - 15 audio system tests - src/tests/gpu/ - 12 GPU/shader tests - src/tests/3d/ - 6 3D rendering tests - src/tests/assets/ - 2 asset system tests - src/tests/util/ - 3 utility tests - src/tests/common/ - 3 shared test helpers - src/tests/scripts/ - 2 bash test scripts (moved conceptually, not physically) **CMake changes:** - Updated add_demo_test macro to accept LABEL parameter - Applied CTest labels to all 36 tests for subsystem filtering - Updated all test file paths in CMakeLists.txt - Fixed common helper paths (webgpu_test_fixture, etc.) - Added custom targets for subsystem testing: - run_audio_tests, run_gpu_tests, run_3d_tests - run_assets_tests, run_util_tests, run_all_tests **Include path updates:** - Fixed relative includes in GPU tests to reference ../common/ **Documentation:** - Updated doc/HOWTO.md with subsystem test commands - Updated doc/CONTRIBUTING.md with new test organization - Updated scripts/check_all.sh to reflect new structure **Verification:** - All 36 tests passing (100%) - ctest -L <subsystem> filters work correctly - make run_<subsystem>_tests targets functional - scripts/check_all.sh passes Backward compatible: make test and ctest continue to work unchanged. handoff(Gemini): Test reorganization complete. 36/36 tests passing.
Diffstat (limited to 'src/tests/gpu/test_demo_effects.cc')
-rw-r--r--src/tests/gpu/test_demo_effects.cc209
1 files changed, 209 insertions, 0 deletions
diff --git a/src/tests/gpu/test_demo_effects.cc b/src/tests/gpu/test_demo_effects.cc
new file mode 100644
index 0000000..8a7d8af
--- /dev/null
+++ b/src/tests/gpu/test_demo_effects.cc
@@ -0,0 +1,209 @@
+// This file is part of the 64k demo project.
+// It tests all demo effect classes for basic construction and initialization.
+// Validates that every effect can be instantiated and initialized without
+// crashes.
+//
+// MAINTENANCE REQUIREMENT: When adding a new effect to demo_effects.h:
+// 1. Add it to the appropriate test list (post_process_effects or
+// scene_effects)
+// 2. Run test to verify: ./build/test_demo_effects
+// 3. If the effect requires Renderer3D, add it to requires_3d check in
+// test_scene_effects()
+
+#include "../common/effect_test_helpers.h"
+#include "gpu/demo_effects.h"
+#include "gpu/effect.h"
+#include "../common/webgpu_test_fixture.h"
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+#include <memory>
+#include <vector>
+
+// Helper: Test effect construction and initialization
+// Returns: 0=failed, 1=passed, 2=skipped (requires full 3D setup)
+static int test_effect_smoke(const char* name, std::shared_ptr<Effect> effect,
+ MainSequence* main_seq, bool requires_3d = false) {
+ fprintf(stdout, " Testing %s...\n", name);
+
+ // Check construction
+ if (!effect) {
+ fprintf(stderr, " ✗ Construction failed\n");
+ return 0;
+ }
+
+ // Should not be initialized yet
+ if (effect->is_initialized) {
+ fprintf(stderr,
+ " ✗ Should not be initialized before Sequence::init()\n");
+ return 0;
+ }
+
+ // Add to sequence and initialize
+ auto seq = std::make_shared<Sequence>();
+ seq->add_effect(effect, 0.0f, 10.0f, 0);
+
+ // Some effects require full 3D pipeline setup (Renderer3D with shaders)
+ // These will fail in init_test() environment - skip them gracefully
+ if (requires_3d) {
+ fprintf(stdout, " ⚠ Skipped (requires full 3D pipeline setup)\n");
+ return 2; // Skipped
+ }
+
+ seq->init(main_seq);
+
+ // Should be initialized now
+ if (!effect->is_initialized) {
+ fprintf(stderr, " ✗ Should be initialized after Sequence::init()\n");
+ return 0;
+ }
+
+ fprintf(stdout, " ✓ %s construction and initialization OK\n", name);
+ return 1; // Passed
+}
+
+// Test 1: Post-process effects
+static void test_post_process_effects() {
+ fprintf(stdout, "Testing post-process effects...\n");
+
+ WebGPUTestFixture fixture;
+ if (!fixture.init()) {
+ fprintf(stdout, " ⚠ WebGPU unavailable - skipping test\n");
+ return;
+ }
+
+ MainSequence main_seq;
+ main_seq.init_test(fixture.ctx());
+
+ // Test each post-process effect
+ std::vector<std::pair<const char*, std::shared_ptr<Effect>>> effects = {
+ {"FlashEffect", std::make_shared<FlashEffect>(fixture.ctx())},
+ {"PassthroughEffect", std::make_shared<PassthroughEffect>(fixture.ctx())},
+ {"GaussianBlurEffect",
+ std::make_shared<GaussianBlurEffect>(fixture.ctx())},
+ {"ChromaAberrationEffect",
+ std::make_shared<ChromaAberrationEffect>(fixture.ctx())},
+ {"SolarizeEffect", std::make_shared<SolarizeEffect>(fixture.ctx())},
+ {"FadeEffect", std::make_shared<FadeEffect>(fixture.ctx())},
+ {"ThemeModulationEffect",
+ std::make_shared<ThemeModulationEffect>(fixture.ctx())},
+ {"VignetteEffect", std::make_shared<VignetteEffect>(fixture.ctx())},
+ };
+
+ int passed = 0;
+ for (const auto& [name, effect] : effects) {
+ // Verify it's marked as post-process
+ assert(effect->is_post_process() &&
+ "Post-process effect should return true for is_post_process()");
+
+ const int result = test_effect_smoke(name, effect, &main_seq, false);
+ if (result == 1) {
+ ++passed;
+ }
+ }
+
+ fprintf(stdout, " ✓ %d/%zu post-process effects tested\n", passed,
+ effects.size());
+}
+
+// Test 2: Scene effects
+static void test_scene_effects() {
+ fprintf(stdout, "Testing scene effects...\n");
+
+ WebGPUTestFixture fixture;
+ if (!fixture.init()) {
+ fprintf(stdout, " ⚠ WebGPU unavailable - skipping test\n");
+ return;
+ }
+
+ MainSequence main_seq;
+ main_seq.init_test(fixture.ctx());
+
+ // Test each scene effect
+ std::vector<std::pair<const char*, std::shared_ptr<Effect>>> effects = {
+ {"HeptagonEffect", std::make_shared<HeptagonEffect>(fixture.ctx())},
+ {"ParticlesEffect", std::make_shared<ParticlesEffect>(fixture.ctx())},
+ {"ParticleSprayEffect",
+ std::make_shared<ParticleSprayEffect>(fixture.ctx())},
+ {"MovingEllipseEffect",
+ std::make_shared<MovingEllipseEffect>(fixture.ctx())},
+ {"FlashCubeEffect", std::make_shared<FlashCubeEffect>(fixture.ctx())},
+ {"Hybrid3DEffect", std::make_shared<Hybrid3DEffect>(fixture.ctx())},
+ {"CircleMaskEffect", std::make_shared<CircleMaskEffect>(fixture.ctx())},
+ {"RotatingCubeEffect",
+ std::make_shared<RotatingCubeEffect>(fixture.ctx())},
+ };
+
+ int passed = 0;
+ int skipped = 0;
+ for (const auto& [name, effect] : effects) {
+ // Scene effects should NOT be marked as post-process
+ assert(!effect->is_post_process() &&
+ "Scene effect should return false for is_post_process()");
+
+ // FlashCubeEffect, Hybrid3DEffect, RotatingCubeEffect, and CircleMaskEffect
+ // require full 3D pipeline (Renderer3D) or auxiliary textures
+ const bool requires_3d = (strcmp(name, "FlashCubeEffect") == 0 ||
+ strcmp(name, "Hybrid3DEffect") == 0 ||
+ strcmp(name, "RotatingCubeEffect") == 0 ||
+ strcmp(name, "CircleMaskEffect") == 0);
+
+ const int result = test_effect_smoke(name, effect, &main_seq, requires_3d);
+ if (result == 1) {
+ ++passed;
+ } else if (result == 2) {
+ ++skipped;
+ }
+ }
+
+ fprintf(stdout, " ✓ %d/%zu scene effects tested (%d skipped)\n", passed,
+ effects.size(), skipped);
+}
+
+// Test 3: Effect type classification
+static void test_effect_type_classification() {
+ fprintf(stdout, "Testing effect type classification...\n");
+
+ WebGPUTestFixture fixture;
+ if (!fixture.init()) {
+ fprintf(stdout, " ⚠ WebGPU unavailable - skipping test\n");
+ return;
+ }
+
+ // Post-process effects should return true
+ auto flash = std::make_shared<FlashEffect>(fixture.ctx());
+ assert(flash->is_post_process() && "FlashEffect should be post-process");
+
+ auto blur = std::make_shared<GaussianBlurEffect>(fixture.ctx());
+ assert(blur->is_post_process() &&
+ "GaussianBlurEffect should be post-process");
+
+ auto vignette = std::make_shared<VignetteEffect>(fixture.ctx());
+ assert(vignette->is_post_process() &&
+ "VignetteEffect should be post-process");
+
+ // Scene effects should return false
+ auto heptagon = std::make_shared<HeptagonEffect>(fixture.ctx());
+ assert(!heptagon->is_post_process() &&
+ "HeptagonEffect should NOT be post-process");
+
+ auto particles = std::make_shared<ParticlesEffect>(fixture.ctx());
+ assert(!particles->is_post_process() &&
+ "ParticlesEffect should NOT be post-process");
+
+ fprintf(stdout, " ✓ Effect type classification correct\n");
+}
+
+int main() {
+ fprintf(stdout, "=== Demo Effects Tests ===\n");
+
+ extern void InitShaderComposer();
+ InitShaderComposer();
+
+ test_post_process_effects();
+ test_scene_effects();
+ test_effect_type_classification();
+
+ fprintf(stdout, "=== All Demo Effects Tests Passed ===\n");
+ return 0;
+} \ No newline at end of file