// 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. #if !defined(STRIP_ALL) // Test code only - zero size impact on final binary #include "effect_test_helpers.h" #include "webgpu_test_fixture.h" #include "gpu/demo_effects.h" #include "gpu/effect.h" #include #include #include #include #include // 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, 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(); 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.device(), fixture.queue(), fixture.format()); // Test each post-process effect std::vector>> effects = { {"FlashEffect", std::make_shared(fixture.device(), fixture.queue(), fixture.format())}, {"PassthroughEffect", std::make_shared(fixture.device(), fixture.queue(), fixture.format())}, {"GaussianBlurEffect", std::make_shared(fixture.device(), fixture.queue(), fixture.format())}, {"ChromaAberrationEffect", std::make_shared( fixture.device(), fixture.queue(), fixture.format())}, {"DistortEffect", std::make_shared(fixture.device(), fixture.queue(), fixture.format())}, {"SolarizeEffect", std::make_shared(fixture.device(), fixture.queue(), fixture.format())}, {"FadeEffect", std::make_shared(fixture.device(), fixture.queue(), fixture.format())}, {"ThemeModulationEffect", std::make_shared( fixture.device(), fixture.queue(), fixture.format())}, }; 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.device(), fixture.queue(), fixture.format()); // Test each scene effect std::vector>> effects = { {"HeptagonEffect", std::make_shared(fixture.device(), fixture.queue(), fixture.format())}, {"ParticlesEffect", std::make_shared(fixture.device(), fixture.queue(), fixture.format())}, {"ParticleSprayEffect", std::make_shared(fixture.device(), fixture.queue(), fixture.format())}, {"MovingEllipseEffect", std::make_shared(fixture.device(), fixture.queue(), fixture.format())}, {"FlashCubeEffect", std::make_shared(fixture.device(), fixture.queue(), fixture.format())}, {"Hybrid3DEffect", std::make_shared(fixture.device(), fixture.queue(), fixture.format())}, }; 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 and Hybrid3DEffect require full 3D pipeline (Renderer3D) const bool requires_3d = (strcmp(name, "FlashCubeEffect") == 0 || strcmp(name, "Hybrid3DEffect") == 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( fixture.device(), fixture.queue(), fixture.format()); assert(flash->is_post_process() && "FlashEffect should be post-process"); auto blur = std::make_shared( fixture.device(), fixture.queue(), fixture.format()); assert(blur->is_post_process() && "GaussianBlurEffect should be post-process"); // Scene effects should return false auto heptagon = std::make_shared( fixture.device(), fixture.queue(), fixture.format()); assert(!heptagon->is_post_process() && "HeptagonEffect should NOT be post-process"); auto particles = std::make_shared( fixture.device(), fixture.queue(), fixture.format()); 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"); test_post_process_effects(); test_scene_effects(); test_effect_type_classification(); fprintf(stdout, "=== All Demo Effects Tests Passed ===\n"); return 0; } #endif /* !defined(STRIP_ALL) */