| 11 | #include "test.h" |
| 12 | |
| 13 | FL_TEST_FILE(FL_FILEPATH) { |
| 14 | |
| 15 | using namespace fl; |
| 16 | |
| 17 | FL_TEST_CASE("WaveSimulation2D_Real clamps speed to CFL bound [0, 0.5]") { |
| 18 | // 2D CFL bound for the 5-point stencil is C^2 <= 0.5. Pre-fix the |
| 19 | // setter accepted up to ~1.0, which is unstable and could overflow. |
| 20 | WaveSimulation2D_Real sim(8, 8, 0.16f, 6.0f); |
| 21 | sim.setSpeed(10.0f); |
| 22 | // Q15(0.5) = 16383 -> back to float -> 16383/32767 ~= 0.49999. |
| 23 | FL_CHECK_CLOSE(sim.getSpeed(), 0.5f, 0.001f); |
| 24 | |
| 25 | sim.setSpeed(-2.0f); |
| 26 | // Q15(0.0) = 0 -> 0.0f exactly. |
| 27 | FL_CHECK_CLOSE(sim.getSpeed(), 0.0f, 0.001f); |
| 28 | |
| 29 | sim.setSpeed(0.16f); |
| 30 | FL_CHECK_CLOSE(sim.getSpeed(), 0.16f, 0.001f); |
| 31 | } |
| 32 | |
| 33 | FL_TEST_CASE("WaveSimulation1D_Real clamps speed to CFL bound [0, 1.0]") { |
| 34 | // 1D CFL bound for the 5-point stencil is C^2 <= 1.0. |
| 35 | WaveSimulation1D_Real sim(16, 0.16f, 6); |
| 36 | sim.setSpeed(10.0f); |
| 37 | FL_CHECK_CLOSE(sim.getSpeed(), 1.0f, 0.001f); |
| 38 | |
| 39 | sim.setSpeed(-2.0f); |
| 40 | FL_CHECK_CLOSE(sim.getSpeed(), 0.0f, 0.001f); |
| 41 | |
| 42 | sim.setSpeed(0.42f); |
| 43 | FL_CHECK_CLOSE(sim.getSpeed(), 0.42f, 0.001f); |
| 44 | } |
| 45 | |
| 46 | FL_TEST_CASE("WaveSimulation2D_Real survives saturated checkerboard at max CFL") { |
| 47 | // Worst case for the inner-loop Q15 multiply: speed at the CFL bound |
| 48 | // (0.5) and every cell saturated alternating between +1.0 and -1.0 |
| 49 | // (Q15 values ~+/-32767). The laplacian magnitude approaches 262,140, |
| 50 | // which times Q15(0.5)=16383 is ~4.3e9 - well past i32 max. Pre-fix |
| 51 | // this overflowed; post-fix the i64 promote keeps the math correct |
| 52 | // and the clamp keeps the result in i16 range. |
| 53 | const u32 W = 16; |
| 54 | const u32 H = 16; |
| 55 | WaveSimulation2D_Real sim(W, H, 0.5f, 6.0f); |
| 56 | sim.setHalfDuplex(false); // keep negative values for the test |
| 57 | |
| 58 | for (u32 y = 0; y < H; ++y) { |
| 59 | for (u32 x = 0; x < W; ++x) { |
| 60 | const float v = ((x + y) & 1) ? -1.0f : 1.0f; |
| 61 | sim.setf(x, y, v); |
| 62 | } |
| 63 | } |
| 64 | sim.update(); |
| 65 | |
| 66 | // Every cell must remain in valid Q15 range (the clamp at the end of |
| 67 | // update() guarantees this; if the i32 multiply overflowed, the |
| 68 | // clamp would still execute but on a wrong-sign value). |
| 69 | bool any_nonzero = false; |
| 70 | for (u32 y = 0; y < H; ++y) { |
nothing calls this directly
no test coverage detected