#include "unity.h"
#include "seq_validator.h"
#include "melody_validator.h"

TEST_CASE("seq accepts codes scanned in the expected order", "[seq]")
{
    const char *expected[] = {"qr3", "qr1", "qr4"};
    seq_validator_t v;
    seq_validator_init(&v, expected, 3);
    TEST_ASSERT_FALSE(seq_validator_feed(&v, "qr3"));   // 1/3
    TEST_ASSERT_FALSE(seq_validator_feed(&v, "qr1"));   // 2/3
    TEST_ASSERT_TRUE (seq_validator_feed(&v, "qr4"));   // complete
}

TEST_CASE("seq resets on a wrong scan", "[seq]")
{
    const char *expected[] = {"a", "b"};
    seq_validator_t v;
    seq_validator_init(&v, expected, 2);
    TEST_ASSERT_FALSE(seq_validator_feed(&v, "a"));     // 1/2
    TEST_ASSERT_FALSE(seq_validator_feed(&v, "x"));     // wrong -> reset
    TEST_ASSERT_FALSE(seq_validator_feed(&v, "a"));     // 1/2 again
    TEST_ASSERT_TRUE (seq_validator_feed(&v, "b"));     // complete
}

TEST_CASE("seq ignores a duplicate of the last correct scan", "[seq]")
{
    const char *expected[] = {"a", "b"};
    seq_validator_t v;
    seq_validator_init(&v, expected, 2);
    TEST_ASSERT_FALSE(seq_validator_feed(&v, "a"));
    TEST_ASSERT_FALSE(seq_validator_feed(&v, "a"));     // duplicate, no progress, no reset
    TEST_ASSERT_TRUE (seq_validator_feed(&v, "b"));
}

TEST_CASE("melody accepts the exact expected note sequence", "[melody]")
{
    const int expected[] = {60, 62, 64, 65};   // do re mi fa
    melody_validator_t m;
    melody_validator_init(&m, expected, 4, /*tolerance=*/1);
    TEST_ASSERT_FALSE(melody_validator_feed(&m, 60));
    TEST_ASSERT_FALSE(melody_validator_feed(&m, 62));
    TEST_ASSERT_FALSE(melody_validator_feed(&m, 64));
    TEST_ASSERT_TRUE (melody_validator_feed(&m, 65));
}

TEST_CASE("melody accepts notes within tolerance", "[melody]")
{
    const int expected[] = {60, 62};
    melody_validator_t m;
    melody_validator_init(&m, expected, 2, 1);
    TEST_ASSERT_FALSE(melody_validator_feed(&m, 61));   // 60 +/-1 ok
    TEST_ASSERT_TRUE (melody_validator_feed(&m, 62));
}

TEST_CASE("melody resets on an out-of-tolerance note", "[melody]")
{
    const int expected[] = {60, 62};
    melody_validator_t m;
    melody_validator_init(&m, expected, 2, 1);
    TEST_ASSERT_FALSE(melody_validator_feed(&m, 60));
    TEST_ASSERT_FALSE(melody_validator_feed(&m, 70));   // way off -> reset
    TEST_ASSERT_FALSE(melody_validator_feed(&m, 60));
    TEST_ASSERT_TRUE (melody_validator_feed(&m, 62));
}
