// ============================================================================
// test/test_subghz_scanner/test_subghz_scanner.cpp
//
// Unity tests for src/subghz_scanner.{h,cpp} — real ExpressLRS-sourced
// control-link burst-rate plausibility check. subghz_is_plausible_rate()
// is pure (no radio access) and unconditionally compiled (not #ifdef
// ARDUINO-gated), so it is directly testable in the native env.
//
// Until this file, subghz_scanner had zero native test coverage (the
// entire module lived behind #ifdef ARDUINO with no radio-independent
// logic split out) -- unlike handset_fingerprint/rf_cataloger, which both
// have a pure, testable core. This closes that gap the same way
// rf_cataloger.cpp's rf_cataloger_classify() does.
//
// Run with:
//   pio test -e native -f test_subghz_scanner
// ============================================================================

#include <unity.h>
#include "../../src/subghz_scanner.cpp"

void setUp(void) {}
void tearDown(void) {}

void test_plausible_at_real_elrs_packet_rates(void) {
    // Real ExpressLRS-sourced packet rates, per subghz_scanner.h's design
    // notes -- all must classify as plausible. 25/50/100/200/250/1000 Hz
    // are the documented 900MHz-band rates (expresslrs.org/info/signal-
    // health/); 150 Hz is TBS Crossfire's real measured rate from
    // third-party RF reverse-engineering (g3gg0.de: 150 Hz / 6.666ms on
    // real captured traffic). 1000 Hz is the important one here: the band
    // used to cap at 600 Hz and would have rejected this real rate.
    TEST_ASSERT_TRUE(subghz_is_plausible_rate(25.0f));
    TEST_ASSERT_TRUE(subghz_is_plausible_rate(50.0f));
    TEST_ASSERT_TRUE(subghz_is_plausible_rate(100.0f));
    TEST_ASSERT_TRUE(subghz_is_plausible_rate(150.0f));
    TEST_ASSERT_TRUE(subghz_is_plausible_rate(200.0f));
    TEST_ASSERT_TRUE(subghz_is_plausible_rate(250.0f));
    TEST_ASSERT_TRUE(subghz_is_plausible_rate(500.0f));
    TEST_ASSERT_TRUE(subghz_is_plausible_rate(1000.0f));
}

void test_plausible_band_boundaries_inclusive(void) {
    TEST_ASSERT_TRUE(subghz_is_plausible_rate(20.0f));
    TEST_ASSERT_TRUE(subghz_is_plausible_rate(1200.0f));
}

void test_implausible_just_outside_boundaries(void) {
    TEST_ASSERT_FALSE(subghz_is_plausible_rate(19.9f));
    TEST_ASSERT_FALSE(subghz_is_plausible_rate(1200.1f));
}

void test_implausible_near_zero_looks_like_continuous_carrier(void) {
    // A continuous carrier never crosses back below threshold, so its
    // measured "rate" trends toward 0 -- must NOT be flagged plausible.
    TEST_ASSERT_FALSE(subghz_is_plausible_rate(0.0f));
    TEST_ASSERT_FALSE(subghz_is_plausible_rate(0.5f));
}

void test_implausible_very_high_rate_looks_like_noise(void) {
    TEST_ASSERT_FALSE(subghz_is_plausible_rate(5000.0f));
}

void test_implausible_negative_rate_safe(void) {
    // Defensive: crossings/dwell_s is derived from an unsigned count in
    // production so this should never actually go negative, but the check
    // must not misbehave if it ever does.
    TEST_ASSERT_FALSE(subghz_is_plausible_rate(-10.0f));
}

// Cross-module consistency: rf_cataloger.cpp's control-link band
// (RF_ACTIVITY_CONTROL_LINK_RATE, 20-1200 Hz) is documented to deliberately
// mirror this same band. This doesn't include rf_cataloger.cpp (avoiding a
// second main() collision), but pins the exact boundary values here so a
// future edit to one module's band without the other trips this test.
void test_boundaries_match_documented_rf_cataloger_band(void) {
    TEST_ASSERT_EQUAL_FLOAT(20.0f, SUBGHZ_MIN_PLAUSIBLE_HZ);
    TEST_ASSERT_EQUAL_FLOAT(1200.0f, SUBGHZ_MAX_PLAUSIBLE_HZ);
}

int main(int, char**) {
    UNITY_BEGIN();

    RUN_TEST(test_plausible_at_real_elrs_packet_rates);
    RUN_TEST(test_plausible_band_boundaries_inclusive);
    RUN_TEST(test_implausible_just_outside_boundaries);
    RUN_TEST(test_implausible_near_zero_looks_like_continuous_carrier);
    RUN_TEST(test_implausible_very_high_rate_looks_like_noise);
    RUN_TEST(test_implausible_negative_rate_safe);
    RUN_TEST(test_boundaries_match_documented_rf_cataloger_band);

    return UNITY_END();
}
