Repository: FastLED/FastLED (C++)

Issue:
add tests for APA102HD algorithm
[__builtin_five_bit_hd_gamma_bitshift](https://github.com/FastLED/FastLED/blob/d5aaf65be19782f3e52b8b0fe38778f14376a293/src/five_bit_hd_gamma.cpp#L126) does some awesome and fairly complex math that would be good to unit test. I have [rewritten that code in Rust](https://github.com/smart-leds-rs/apa102-spi-rs/pull/15) and it would be very useful to have test values to validate that the translated code is correct.


Discussion:
Tests for the `five_bit_bitshift`, `brightness_bitshifter8`, and `brightness_bitshifter16` functions would be good too.
Can I assign this to you?
Sure
thank you



Patch:
diff --git a/src/five_bit_hd_gamma.cpp b/src/five_bit_hd_gamma.cpp
index 680fd1ac85..72092c622e 100644
--- a/src/five_bit_hd_gamma.cpp
+++ b/src/five_bit_hd_gamma.cpp
@@ -73,9 +73,14 @@ void five_bit_hd_gamma_function(CRGB rgb, uint16_t *r16, uint16_t *g16,
 
 uint8_t five_bit_bitshift(uint16_t r16, uint16_t g16, uint16_t b16,
                           uint8_t brightness, CRGB *out, uint8_t *out_power_5bit) {
-    if (!(r16 | g16 | b16) || brightness == 0) {
-        *out = CRGB(map16_to_8(r16), map16_to_8(g16), map16_to_8(b16));
-        *out_power_5bit = 31;
+    if (brightness == 0) {
+        *out = CRGB(0, 0, 0);
+        *out_power_5bit = 0;
+        return 0;
+    }
+    if (r16 == 0 && g16 == 0 && b16 == 0) {
+        *out = CRGB(0, 0, 0);
+        *out_power_5bit = (brightness <= 31) ? brightness : 31;
         return brightness;
     }
 


Test patch:
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index a19821b456..dd8f8bb317 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -78,6 +78,10 @@ set(COMMON_COMPILE_FLAGS
 
     # Not supported in gcc.
     # -Werror=infinite-recursion
+
+    -DFASTLED_FIVE_BIT_HD_GAMMA_FUNCTION_2_8
+    # ignore Arduino/PlatformIO-specific PROGMEM macro
+    -DPROGMEM=
 )
 
 set(UNIT_TEST_COMPILE_FLAGS
diff --git a/tests/test_apa102_hd.cpp b/tests/test_apa102_hd.cpp
index 2b7ff932ea..000b7964d0 100644
--- a/tests/test_apa102_hd.cpp
+++ b/tests/test_apa102_hd.cpp
@@ -19,6 +19,116 @@
 #include "fl/namespace.h"
 FASTLED_USING_NAMESPACE
 
+TEST_CASE("five_bit_bitshift") {
+  const uint16_t test_data[][2][4] = {
+    { // test case
+      //r g  b  brightness
+      {0, 0, 0, 0}, // input
+      {0, 0, 0, 0}, // output
+    },
+    { // 0 brightness brings all colors down to 0
+      {0xffff, 0xffff, 0xffff, 0},
+      {0,      0,      0,      0},
+    },
+    { // color values below 8 become 0 at max brightness
+      {8, 7, 0, 255},
+      {1, 0, 0, 1},
+    },
+    {
+      {0xffff, 0x00f0, 0x000f, 0x01},
+      {0x11,   0x00,   0x00,   0x01},
+    },
+    {
+      {0x0100, 0x00f0, 0x000f, 0xff},
+      {0x08,   0x08,   0x00,   0x03},
+    },
+    {
+      {0x2000, 0x1000, 0x0f00, 0x20},
+      {0x20,   0x10,   0x0f,   0x03},
+    },
+    {
+      {0xffff, 0x8000, 0x4000, 0x40},
+      {0x81,   0x41,   0x20,   0x0f},
+    },
+    {
+      {0xffff, 0x8000, 0x4000, 0x80},
+      {0x81,   0x41,   0x20,   0x1f},
+    },
+    {
+      {0xffff, 0xffff, 0xffff, 0xff},
+      {0xff,   0xff,   0xff,   0x1f},
+    },
+  };
+
+  for (const auto& data : test_data) {
+    CRGB out_color;
+    uint8_t out_brightness;
+    five_bit_bitshift(data[0][0], data[0][1], data[0][2], data[0][3], &out_color, &out_brightness);
+    INFO("input  red ", data[0][0], " green ", data[0][1], " blue ", data[0][2], " brightness ", data[0][3]);
+    INFO("output red ", out_color.r, " green ", out_color.g, " blue ", out_color.b, " brightness ", out_brightness);
+    CHECK_EQ(out_color.r, data[1][0]);
+    CHECK_EQ(out_color.g, data[1][1]);
+    CHECK_EQ(out_color.b, data[1][2]);
+    CHECK_EQ(out_brightness, data[1][3]);
+  }
+}
+
+TEST_CASE("__builtin_five_bit_hd_gamma_bitshift") {
+  // NOTE: FASTLED_FIVE_BIT_HD_GAMMA_FUNCTION_2_8 is defined for this test in CMakeLists.txt
+
+  const uint8_t test_data[][2][4] = {
+    { // test case
+      //r g  b  brightness
+      {0, 0, 0, 0}, // input
+      {0, 0, 0, 0}, // output
+    },
+    { // 0 brightness brings all colors down to 0
+      {255, 255, 255, 0},
+      {0,   0,   0,   0},
+    },
+    {
+      {16, 16, 16, 16},
+      {0,  0,  0,  1},
+    },
+    {
+      {64, 64, 64, 8},
+      {4,  4,  4,  1},
+    },
+    {
+      {255, 127, 43, 1},
+      {17,  3,   0,  1},
+    },
+    {
+      {255, 127, 43, 1},
+      {17,  3,   0,  1},
+    },
+    {
+      {255, 127, 43, 64},
+      {129, 21,  1,  15},
+    },
+    {
+      {255, 127, 43, 255},
+      {255, 42,  3,  31},
+    },
+    {
+      {255, 255, 255, 255},
+      {255, 255, 255, 31},
+    },
+  };
+
+  for (const auto& data : test_data) {
+    CRGB out_color;
+    uint8_t out_brightness;
+    __builtin_five_bit_hd_gamma_bitshift(CRGB(data[0][0], data[0][1], data[0][2]), CRGB(255, 255, 255), data[0][3], &out_color, &out_brightness);
+    INFO("input  red ", data[0][0], " green ", data[0][1], " blue ", data[0][2], " brightness ", data[0][3]);
+    INFO("output red ", out_color.r, " green ", out_color.g, " blue ", out_color.b, " brightness ", out_brightness);
+    CHECK_EQ(out_color.r, data[1][0]);
+    CHECK_EQ(out_color.g, data[1][1]);
+    CHECK_EQ(out_color.b, data[1][2]);
+    CHECK_EQ(out_brightness, data[1][3]);
+  }
+}
+
 #define CHECK_NEAR(a, b, c) CHECK_LT(abs(a - b), c)