This commit is contained in:
Willy-JL
2024-05-21 04:10:46 +01:00
80 changed files with 1512 additions and 746 deletions

View File

@@ -0,0 +1,742 @@
#include <furi.h>
#include "../test.h"
#include <bit_lib/bit_lib.h>
MU_TEST(test_bit_lib_increment_index) {
uint32_t index = 0;
// test increment
for(uint32_t i = 0; i < 31; ++i) {
bit_lib_increment_index(index, 32);
mu_assert_int_eq(i + 1, index);
}
// test wrap around
for(uint32_t i = 0; i < 512; ++i) {
bit_lib_increment_index(index, 32);
mu_assert_int_less_than(32, index);
}
}
MU_TEST(test_bit_lib_is_set) {
uint32_t value = 0x0000FFFF;
for(uint32_t i = 0; i < 16; ++i) {
mu_check(bit_lib_bit_is_set(value, i));
mu_check(!bit_lib_bit_is_not_set(value, i));
}
for(uint32_t i = 16; i < 32; ++i) {
mu_check(!bit_lib_bit_is_set(value, i));
mu_check(bit_lib_bit_is_not_set(value, i));
}
}
MU_TEST(test_bit_lib_push) {
#define TEST_BIT_LIB_PUSH_DATA_SIZE 4
uint8_t data[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0};
uint8_t expected_data_1[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0x00, 0x00, 0x0F, 0xFF};
uint8_t expected_data_2[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0x00, 0xFF, 0xF0, 0x00};
uint8_t expected_data_3[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0xFF, 0x00, 0x00, 0xFF};
uint8_t expected_data_4[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0xFF, 0xFF, 0xFF, 0xFF};
uint8_t expected_data_5[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0x00, 0x00, 0x00, 0x00};
uint8_t expected_data_6[TEST_BIT_LIB_PUSH_DATA_SIZE] = {0xCC, 0xCC, 0xCC, 0xCC};
for(uint32_t i = 0; i < 12; ++i) {
bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, true);
}
mu_assert_mem_eq(expected_data_1, data, TEST_BIT_LIB_PUSH_DATA_SIZE);
for(uint32_t i = 0; i < 12; ++i) {
bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, false);
}
mu_assert_mem_eq(expected_data_2, data, TEST_BIT_LIB_PUSH_DATA_SIZE);
for(uint32_t i = 0; i < 4; ++i) {
bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, false);
}
for(uint32_t i = 0; i < 8; ++i) {
bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, true);
}
mu_assert_mem_eq(expected_data_3, data, TEST_BIT_LIB_PUSH_DATA_SIZE);
for(uint32_t i = 0; i < TEST_BIT_LIB_PUSH_DATA_SIZE * 8; ++i) {
bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, true);
}
mu_assert_mem_eq(expected_data_4, data, TEST_BIT_LIB_PUSH_DATA_SIZE);
for(uint32_t i = 0; i < TEST_BIT_LIB_PUSH_DATA_SIZE * 8; ++i) {
bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, false);
}
mu_assert_mem_eq(expected_data_5, data, TEST_BIT_LIB_PUSH_DATA_SIZE);
for(uint32_t i = 0; i < TEST_BIT_LIB_PUSH_DATA_SIZE * 2; ++i) {
bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, true);
bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, true);
bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, false);
bit_lib_push_bit(data, TEST_BIT_LIB_PUSH_DATA_SIZE, false);
}
mu_assert_mem_eq(expected_data_6, data, TEST_BIT_LIB_PUSH_DATA_SIZE);
}
MU_TEST(test_bit_lib_set_bit) {
uint8_t value[2] = {0x00, 0xFF};
bit_lib_set_bit(value, 15, false);
mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xFE}), 2);
bit_lib_set_bit(value, 14, false);
mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xFC}), 2);
bit_lib_set_bit(value, 13, false);
mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xF8}), 2);
bit_lib_set_bit(value, 12, false);
mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xF0}), 2);
bit_lib_set_bit(value, 11, false);
mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xE0}), 2);
bit_lib_set_bit(value, 10, false);
mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0xC0}), 2);
bit_lib_set_bit(value, 9, false);
mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0x80}), 2);
bit_lib_set_bit(value, 8, false);
mu_assert_mem_eq(value, ((uint8_t[]){0x00, 0x00}), 2);
bit_lib_set_bit(value, 7, true);
mu_assert_mem_eq(value, ((uint8_t[]){0x01, 0x00}), 2);
bit_lib_set_bit(value, 6, true);
mu_assert_mem_eq(value, ((uint8_t[]){0x03, 0x00}), 2);
bit_lib_set_bit(value, 5, true);
mu_assert_mem_eq(value, ((uint8_t[]){0x07, 0x00}), 2);
bit_lib_set_bit(value, 4, true);
mu_assert_mem_eq(value, ((uint8_t[]){0x0F, 0x00}), 2);
bit_lib_set_bit(value, 3, true);
mu_assert_mem_eq(value, ((uint8_t[]){0x1F, 0x00}), 2);
bit_lib_set_bit(value, 2, true);
mu_assert_mem_eq(value, ((uint8_t[]){0x3F, 0x00}), 2);
bit_lib_set_bit(value, 1, true);
mu_assert_mem_eq(value, ((uint8_t[]){0x7F, 0x00}), 2);
bit_lib_set_bit(value, 0, true);
mu_assert_mem_eq(value, ((uint8_t[]){0xFF, 0x00}), 2);
}
MU_TEST(test_bit_lib_set_bits) {
uint8_t value[2] = {0b00000000, 0b11111111};
// set 4 bits to 0b0100 from 12 index
bit_lib_set_bits(value, 12, 0b0100, 4);
// [0100]
mu_assert_mem_eq(value, ((uint8_t[]){0b00000000, 0b11110100}), 2);
// set 2 bits to 0b11 from 11 index
bit_lib_set_bits(value, 11, 0b11, 2);
// [11]
mu_assert_mem_eq(value, ((uint8_t[]){0b00000000, 0b11111100}), 2);
// set 3 bits to 0b111 from 0 index
bit_lib_set_bits(value, 0, 0b111, 3);
// [111]
mu_assert_mem_eq(value, ((uint8_t[]){0b11100000, 0b11111100}), 2);
// set 8 bits to 0b11111000 from 3 index
bit_lib_set_bits(value, 3, 0b11111000, 8);
// [11111 000]
mu_assert_mem_eq(value, ((uint8_t[]){0b11111111, 0b00011100}), 2);
}
MU_TEST(test_bit_lib_get_bit) {
uint8_t value[2] = {0b00000000, 0b11111111};
for(uint32_t i = 0; i < 8; ++i) {
mu_check(bit_lib_get_bit(value, i) == false);
}
for(uint32_t i = 8; i < 16; ++i) {
mu_check(bit_lib_get_bit(value, i) == true);
}
}
MU_TEST(test_bit_lib_get_bits) {
uint8_t value[2] = {0b00000000, 0b11111111};
mu_assert_int_eq(0b00000000, bit_lib_get_bits(value, 0, 8));
mu_assert_int_eq(0b00000001, bit_lib_get_bits(value, 1, 8));
mu_assert_int_eq(0b00000011, bit_lib_get_bits(value, 2, 8));
mu_assert_int_eq(0b00000111, bit_lib_get_bits(value, 3, 8));
mu_assert_int_eq(0b00001111, bit_lib_get_bits(value, 4, 8));
mu_assert_int_eq(0b00011111, bit_lib_get_bits(value, 5, 8));
mu_assert_int_eq(0b00111111, bit_lib_get_bits(value, 6, 8));
mu_assert_int_eq(0b01111111, bit_lib_get_bits(value, 7, 8));
mu_assert_int_eq(0b11111111, bit_lib_get_bits(value, 8, 8));
}
MU_TEST(test_bit_lib_get_bits_16) {
uint8_t value[2] = {0b00001001, 0b10110001};
mu_assert_int_eq(0b0, bit_lib_get_bits_16(value, 0, 1));
mu_assert_int_eq(0b00, bit_lib_get_bits_16(value, 0, 2));
mu_assert_int_eq(0b000, bit_lib_get_bits_16(value, 0, 3));
mu_assert_int_eq(0b0000, bit_lib_get_bits_16(value, 0, 4));
mu_assert_int_eq(0b00001, bit_lib_get_bits_16(value, 0, 5));
mu_assert_int_eq(0b000010, bit_lib_get_bits_16(value, 0, 6));
mu_assert_int_eq(0b0000100, bit_lib_get_bits_16(value, 0, 7));
mu_assert_int_eq(0b00001001, bit_lib_get_bits_16(value, 0, 8));
mu_assert_int_eq(0b000010011, bit_lib_get_bits_16(value, 0, 9));
mu_assert_int_eq(0b0000100110, bit_lib_get_bits_16(value, 0, 10));
mu_assert_int_eq(0b00001001101, bit_lib_get_bits_16(value, 0, 11));
mu_assert_int_eq(0b000010011011, bit_lib_get_bits_16(value, 0, 12));
mu_assert_int_eq(0b0000100110110, bit_lib_get_bits_16(value, 0, 13));
mu_assert_int_eq(0b00001001101100, bit_lib_get_bits_16(value, 0, 14));
mu_assert_int_eq(0b000010011011000, bit_lib_get_bits_16(value, 0, 15));
mu_assert_int_eq(0b0000100110110001, bit_lib_get_bits_16(value, 0, 16));
}
MU_TEST(test_bit_lib_get_bits_32) {
uint8_t value[4] = {0b00001001, 0b10110001, 0b10001100, 0b01100010};
mu_assert_int_eq(0b0, bit_lib_get_bits_32(value, 0, 1));
mu_assert_int_eq(0b00, bit_lib_get_bits_32(value, 0, 2));
mu_assert_int_eq(0b000, bit_lib_get_bits_32(value, 0, 3));
mu_assert_int_eq(0b0000, bit_lib_get_bits_32(value, 0, 4));
mu_assert_int_eq(0b00001, bit_lib_get_bits_32(value, 0, 5));
mu_assert_int_eq(0b000010, bit_lib_get_bits_32(value, 0, 6));
mu_assert_int_eq(0b0000100, bit_lib_get_bits_32(value, 0, 7));
mu_assert_int_eq(0b00001001, bit_lib_get_bits_32(value, 0, 8));
mu_assert_int_eq(0b000010011, bit_lib_get_bits_32(value, 0, 9));
mu_assert_int_eq(0b0000100110, bit_lib_get_bits_32(value, 0, 10));
mu_assert_int_eq(0b00001001101, bit_lib_get_bits_32(value, 0, 11));
mu_assert_int_eq(0b000010011011, bit_lib_get_bits_32(value, 0, 12));
mu_assert_int_eq(0b0000100110110, bit_lib_get_bits_32(value, 0, 13));
mu_assert_int_eq(0b00001001101100, bit_lib_get_bits_32(value, 0, 14));
mu_assert_int_eq(0b000010011011000, bit_lib_get_bits_32(value, 0, 15));
mu_assert_int_eq(0b0000100110110001, bit_lib_get_bits_32(value, 0, 16));
mu_assert_int_eq(0b00001001101100011, bit_lib_get_bits_32(value, 0, 17));
mu_assert_int_eq(0b000010011011000110, bit_lib_get_bits_32(value, 0, 18));
mu_assert_int_eq(0b0000100110110001100, bit_lib_get_bits_32(value, 0, 19));
mu_assert_int_eq(0b00001001101100011000, bit_lib_get_bits_32(value, 0, 20));
mu_assert_int_eq(0b000010011011000110001, bit_lib_get_bits_32(value, 0, 21));
mu_assert_int_eq(0b0000100110110001100011, bit_lib_get_bits_32(value, 0, 22));
mu_assert_int_eq(0b00001001101100011000110, bit_lib_get_bits_32(value, 0, 23));
mu_assert_int_eq(0b000010011011000110001100, bit_lib_get_bits_32(value, 0, 24));
mu_assert_int_eq(0b0000100110110001100011000, bit_lib_get_bits_32(value, 0, 25));
mu_assert_int_eq(0b00001001101100011000110001, bit_lib_get_bits_32(value, 0, 26));
mu_assert_int_eq(0b000010011011000110001100011, bit_lib_get_bits_32(value, 0, 27));
mu_assert_int_eq(0b0000100110110001100011000110, bit_lib_get_bits_32(value, 0, 28));
mu_assert_int_eq(0b00001001101100011000110001100, bit_lib_get_bits_32(value, 0, 29));
mu_assert_int_eq(0b000010011011000110001100011000, bit_lib_get_bits_32(value, 0, 30));
mu_assert_int_eq(0b0000100110110001100011000110001, bit_lib_get_bits_32(value, 0, 31));
mu_assert_int_eq(0b00001001101100011000110001100010, bit_lib_get_bits_32(value, 0, 32));
}
MU_TEST(test_bit_lib_get_bits_64) {
uint8_t value[8] = {
0b00001001,
0b10110001,
0b10001100,
0b01100010,
0b00001001,
0b10110001,
0b10001100,
0b01100010};
mu_assert_int_eq(0b0, bit_lib_get_bits_64(value, 0, 1));
mu_assert_int_eq(0b00, bit_lib_get_bits_64(value, 0, 2));
mu_assert_int_eq(0b000, bit_lib_get_bits_64(value, 0, 3));
mu_assert_int_eq(0b0000, bit_lib_get_bits_64(value, 0, 4));
mu_assert_int_eq(0b00001, bit_lib_get_bits_64(value, 0, 5));
mu_assert_int_eq(0b000010, bit_lib_get_bits_64(value, 0, 6));
mu_assert_int_eq(0b0000100, bit_lib_get_bits_64(value, 0, 7));
mu_assert_int_eq(0b00001001, bit_lib_get_bits_64(value, 0, 8));
mu_assert_int_eq(0b000010011, bit_lib_get_bits_64(value, 0, 9));
mu_assert_int_eq(0b0000100110, bit_lib_get_bits_64(value, 0, 10));
mu_assert_int_eq(0b00001001101, bit_lib_get_bits_64(value, 0, 11));
mu_assert_int_eq(0b000010011011, bit_lib_get_bits_64(value, 0, 12));
mu_assert_int_eq(0b0000100110110, bit_lib_get_bits_64(value, 0, 13));
mu_assert_int_eq(0b00001001101100, bit_lib_get_bits_64(value, 0, 14));
mu_assert_int_eq(0b000010011011000, bit_lib_get_bits_64(value, 0, 15));
mu_assert_int_eq(0b0000100110110001, bit_lib_get_bits_64(value, 0, 16));
mu_assert_int_eq(0b00001001101100011, bit_lib_get_bits_64(value, 0, 17));
mu_assert_int_eq(0b000010011011000110, bit_lib_get_bits_64(value, 0, 18));
mu_assert_int_eq(0b0000100110110001100, bit_lib_get_bits_64(value, 0, 19));
mu_assert_int_eq(0b00001001101100011000, bit_lib_get_bits_64(value, 0, 20));
mu_assert_int_eq(0b000010011011000110001, bit_lib_get_bits_64(value, 0, 21));
mu_assert_int_eq(0b0000100110110001100011, bit_lib_get_bits_64(value, 0, 22));
mu_assert_int_eq(0b00001001101100011000110, bit_lib_get_bits_64(value, 0, 23));
mu_assert_int_eq(0b000010011011000110001100, bit_lib_get_bits_64(value, 0, 24));
mu_assert_int_eq(0b0000100110110001100011000, bit_lib_get_bits_64(value, 0, 25));
mu_assert_int_eq(0b00001001101100011000110001, bit_lib_get_bits_64(value, 0, 26));
mu_assert_int_eq(0b000010011011000110001100011, bit_lib_get_bits_64(value, 0, 27));
mu_assert_int_eq(0b0000100110110001100011000110, bit_lib_get_bits_64(value, 0, 28));
mu_assert_int_eq(0b00001001101100011000110001100, bit_lib_get_bits_64(value, 0, 29));
mu_assert_int_eq(0b000010011011000110001100011000, bit_lib_get_bits_64(value, 0, 30));
mu_assert_int_eq(0b0000100110110001100011000110001, bit_lib_get_bits_64(value, 0, 31));
mu_assert_int_eq(0b00001001101100011000110001100010, bit_lib_get_bits_64(value, 0, 32));
uint64_t res = bit_lib_get_bits_64(value, 0, 33);
uint64_t expected = 0b000010011011000110001100011000100;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 34);
expected = 0b0000100110110001100011000110001000;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 35);
expected = 0b00001001101100011000110001100010000;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 36);
expected = 0b000010011011000110001100011000100000;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 37);
expected = 0b0000100110110001100011000110001000001;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 38);
expected = 0b00001001101100011000110001100010000010;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 39);
expected = 0b000010011011000110001100011000100000100;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 40);
expected = 0b0000100110110001100011000110001000001001;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 41);
expected = 0b00001001101100011000110001100010000010011;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 42);
expected = 0b000010011011000110001100011000100000100110;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 43);
expected = 0b0000100110110001100011000110001000001001101;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 44);
expected = 0b00001001101100011000110001100010000010011011;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 45);
expected = 0b000010011011000110001100011000100000100110110;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 46);
expected = 0b0000100110110001100011000110001000001001101100;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 47);
expected = 0b00001001101100011000110001100010000010011011000;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 48);
expected = 0b000010011011000110001100011000100000100110110001;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 49);
expected = 0b0000100110110001100011000110001000001001101100011;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 50);
expected = 0b00001001101100011000110001100010000010011011000110;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 51);
expected = 0b000010011011000110001100011000100000100110110001100;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 52);
expected = 0b0000100110110001100011000110001000001001101100011000;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 53);
expected = 0b00001001101100011000110001100010000010011011000110001;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 54);
expected = 0b000010011011000110001100011000100000100110110001100011;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 55);
expected = 0b0000100110110001100011000110001000001001101100011000110;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 56);
expected = 0b00001001101100011000110001100010000010011011000110001100;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 57);
expected = 0b000010011011000110001100011000100000100110110001100011000;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 58);
expected = 0b0000100110110001100011000110001000001001101100011000110001;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 59);
expected = 0b00001001101100011000110001100010000010011011000110001100011;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 60);
expected = 0b000010011011000110001100011000100000100110110001100011000110;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 61);
expected = 0b0000100110110001100011000110001000001001101100011000110001100;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 62);
expected = 0b00001001101100011000110001100010000010011011000110001100011000;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 63);
expected = 0b000010011011000110001100011000100000100110110001100011000110001;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
res = bit_lib_get_bits_64(value, 0, 64);
expected = 0b0000100110110001100011000110001000001001101100011000110001100010;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
}
MU_TEST(test_bit_lib_test_parity_u32) {
// test even parity
mu_assert_int_eq(bit_lib_test_parity_32(0b00000000, BitLibParityEven), 0);
mu_assert_int_eq(bit_lib_test_parity_32(0b00000001, BitLibParityEven), 1);
mu_assert_int_eq(bit_lib_test_parity_32(0b00000010, BitLibParityEven), 1);
mu_assert_int_eq(bit_lib_test_parity_32(0b00000011, BitLibParityEven), 0);
mu_assert_int_eq(bit_lib_test_parity_32(0b00000100, BitLibParityEven), 1);
mu_assert_int_eq(bit_lib_test_parity_32(0b00000101, BitLibParityEven), 0);
mu_assert_int_eq(bit_lib_test_parity_32(0b00000110, BitLibParityEven), 0);
mu_assert_int_eq(bit_lib_test_parity_32(0b00000111, BitLibParityEven), 1);
mu_assert_int_eq(bit_lib_test_parity_32(0b00001000, BitLibParityEven), 1);
mu_assert_int_eq(bit_lib_test_parity_32(0b00001001, BitLibParityEven), 0);
mu_assert_int_eq(bit_lib_test_parity_32(0b00001010, BitLibParityEven), 0);
mu_assert_int_eq(bit_lib_test_parity_32(0b00001011, BitLibParityEven), 1);
mu_assert_int_eq(bit_lib_test_parity_32(0b00001100, BitLibParityEven), 0);
mu_assert_int_eq(bit_lib_test_parity_32(0b00001101, BitLibParityEven), 1);
mu_assert_int_eq(bit_lib_test_parity_32(0b00001110, BitLibParityEven), 1);
mu_assert_int_eq(bit_lib_test_parity_32(0b00001111, BitLibParityEven), 0);
mu_assert_int_eq(bit_lib_test_parity_32(0b00010000, BitLibParityEven), 1);
// test odd parity
mu_assert_int_eq(bit_lib_test_parity_32(0b00000000, BitLibParityOdd), 1);
mu_assert_int_eq(bit_lib_test_parity_32(0b00000001, BitLibParityOdd), 0);
mu_assert_int_eq(bit_lib_test_parity_32(0b00000010, BitLibParityOdd), 0);
mu_assert_int_eq(bit_lib_test_parity_32(0b00000011, BitLibParityOdd), 1);
mu_assert_int_eq(bit_lib_test_parity_32(0b00000100, BitLibParityOdd), 0);
mu_assert_int_eq(bit_lib_test_parity_32(0b00000101, BitLibParityOdd), 1);
mu_assert_int_eq(bit_lib_test_parity_32(0b00000110, BitLibParityOdd), 1);
mu_assert_int_eq(bit_lib_test_parity_32(0b00000111, BitLibParityOdd), 0);
mu_assert_int_eq(bit_lib_test_parity_32(0b00001000, BitLibParityOdd), 0);
mu_assert_int_eq(bit_lib_test_parity_32(0b00001001, BitLibParityOdd), 1);
mu_assert_int_eq(bit_lib_test_parity_32(0b00001010, BitLibParityOdd), 1);
mu_assert_int_eq(bit_lib_test_parity_32(0b00001011, BitLibParityOdd), 0);
mu_assert_int_eq(bit_lib_test_parity_32(0b00001100, BitLibParityOdd), 1);
mu_assert_int_eq(bit_lib_test_parity_32(0b00001101, BitLibParityOdd), 0);
mu_assert_int_eq(bit_lib_test_parity_32(0b00001110, BitLibParityOdd), 0);
mu_assert_int_eq(bit_lib_test_parity_32(0b00001111, BitLibParityOdd), 1);
mu_assert_int_eq(bit_lib_test_parity_32(0b00010000, BitLibParityOdd), 0);
}
MU_TEST(test_bit_lib_test_parity) {
// next data contains valid parity for 1-3 nibble and invalid for 4 nibble
uint8_t data_always_0_parity[2] = {0b11101110, 0b11101111};
uint8_t data_always_1_parity[2] = {0b00010001, 0b00010000};
uint8_t data_always_odd_parity[2] = {0b00000011, 0b11110111};
uint8_t data_always_even_parity[2] = {0b00010111, 0b10110011};
// test alawys 0 parity
mu_check(bit_lib_test_parity(data_always_0_parity, 0, 12, BitLibParityAlways0, 4));
mu_check(bit_lib_test_parity(data_always_0_parity, 4, 8, BitLibParityAlways0, 4));
mu_check(bit_lib_test_parity(data_always_0_parity, 8, 4, BitLibParityAlways0, 4));
mu_check(bit_lib_test_parity(data_always_1_parity, 12, 4, BitLibParityAlways0, 4));
mu_check(!bit_lib_test_parity(data_always_0_parity, 0, 16, BitLibParityAlways0, 4));
mu_check(!bit_lib_test_parity(data_always_0_parity, 4, 12, BitLibParityAlways0, 4));
mu_check(!bit_lib_test_parity(data_always_0_parity, 8, 8, BitLibParityAlways0, 4));
mu_check(!bit_lib_test_parity(data_always_0_parity, 12, 4, BitLibParityAlways0, 4));
// test alawys 1 parity
mu_check(bit_lib_test_parity(data_always_1_parity, 0, 12, BitLibParityAlways1, 4));
mu_check(bit_lib_test_parity(data_always_1_parity, 4, 8, BitLibParityAlways1, 4));
mu_check(bit_lib_test_parity(data_always_1_parity, 8, 4, BitLibParityAlways1, 4));
mu_check(bit_lib_test_parity(data_always_0_parity, 12, 4, BitLibParityAlways1, 4));
mu_check(!bit_lib_test_parity(data_always_1_parity, 0, 16, BitLibParityAlways1, 4));
mu_check(!bit_lib_test_parity(data_always_1_parity, 4, 12, BitLibParityAlways1, 4));
mu_check(!bit_lib_test_parity(data_always_1_parity, 8, 8, BitLibParityAlways1, 4));
mu_check(!bit_lib_test_parity(data_always_1_parity, 12, 4, BitLibParityAlways1, 4));
// test odd parity
mu_check(bit_lib_test_parity(data_always_odd_parity, 0, 12, BitLibParityOdd, 4));
mu_check(bit_lib_test_parity(data_always_odd_parity, 4, 8, BitLibParityOdd, 4));
mu_check(bit_lib_test_parity(data_always_odd_parity, 8, 4, BitLibParityOdd, 4));
mu_check(bit_lib_test_parity(data_always_even_parity, 12, 4, BitLibParityOdd, 4));
mu_check(!bit_lib_test_parity(data_always_odd_parity, 0, 16, BitLibParityOdd, 4));
mu_check(!bit_lib_test_parity(data_always_odd_parity, 4, 12, BitLibParityOdd, 4));
mu_check(!bit_lib_test_parity(data_always_odd_parity, 8, 8, BitLibParityOdd, 4));
mu_check(!bit_lib_test_parity(data_always_odd_parity, 12, 4, BitLibParityOdd, 4));
// test even parity
mu_check(bit_lib_test_parity(data_always_even_parity, 0, 12, BitLibParityEven, 4));
mu_check(bit_lib_test_parity(data_always_even_parity, 4, 8, BitLibParityEven, 4));
mu_check(bit_lib_test_parity(data_always_even_parity, 8, 4, BitLibParityEven, 4));
mu_check(bit_lib_test_parity(data_always_odd_parity, 12, 4, BitLibParityEven, 4));
mu_check(!bit_lib_test_parity(data_always_even_parity, 0, 16, BitLibParityEven, 4));
mu_check(!bit_lib_test_parity(data_always_even_parity, 4, 12, BitLibParityEven, 4));
mu_check(!bit_lib_test_parity(data_always_even_parity, 8, 8, BitLibParityEven, 4));
mu_check(!bit_lib_test_parity(data_always_even_parity, 12, 4, BitLibParityEven, 4));
}
MU_TEST(test_bit_lib_remove_bit_every_nth) {
// TODO FL-3494: more tests
uint8_t data_i[1] = {0b00001111};
uint8_t data_o[1] = {0b00011111};
size_t length;
length = bit_lib_remove_bit_every_nth(data_i, 0, 8, 3);
mu_assert_int_eq(6, length);
mu_assert_mem_eq(data_o, data_i, 1);
}
MU_TEST(test_bit_lib_reverse_bits) {
uint8_t data_1_i[2] = {0b11001010, 0b00011111};
uint8_t data_1_o[2] = {0b11111000, 0b01010011};
// reverse bits [0..15]
bit_lib_reverse_bits(data_1_i, 0, 16);
mu_assert_mem_eq(data_1_o, data_1_i, 2);
uint8_t data_2_i[2] = {0b11001010, 0b00011111};
uint8_t data_2_o[2] = {0b11001000, 0b01011111};
// reverse bits [4..11]
bit_lib_reverse_bits(data_2_i, 4, 8);
mu_assert_mem_eq(data_2_o, data_2_i, 2);
}
MU_TEST(test_bit_lib_copy_bits) {
uint8_t data_1_i[2] = {0b11001010, 0b00011111};
uint8_t data_1_o[2] = {0};
// data_1_o[0..15] = data_1_i[0..15]
bit_lib_copy_bits(data_1_o, 0, 16, data_1_i, 0);
mu_assert_mem_eq(data_1_i, data_1_o, 2);
memset(data_1_o, 0, 2);
// data_1_o[4..11] = data_1_i[0..7]
bit_lib_copy_bits(data_1_o, 4, 8, data_1_i, 0);
mu_assert_mem_eq(((uint8_t[]){0b00001100, 0b10100000}), data_1_o, 2);
}
MU_TEST(test_bit_lib_get_bit_count) {
mu_assert_int_eq(0, bit_lib_get_bit_count(0));
mu_assert_int_eq(1, bit_lib_get_bit_count(0b1));
mu_assert_int_eq(1, bit_lib_get_bit_count(0b10));
mu_assert_int_eq(2, bit_lib_get_bit_count(0b11));
mu_assert_int_eq(4, bit_lib_get_bit_count(0b11000011));
mu_assert_int_eq(6, bit_lib_get_bit_count(0b11000011000011));
mu_assert_int_eq(8, bit_lib_get_bit_count(0b11111111));
mu_assert_int_eq(16, bit_lib_get_bit_count(0b11111110000000000000000111111111));
mu_assert_int_eq(32, bit_lib_get_bit_count(0b11111111111111111111111111111111));
}
MU_TEST(test_bit_lib_reverse_16_fast) {
mu_assert_int_eq(0b0000000000000000, bit_lib_reverse_16_fast(0b0000000000000000));
mu_assert_int_eq(0b1000000000000000, bit_lib_reverse_16_fast(0b0000000000000001));
mu_assert_int_eq(0b1100000000000000, bit_lib_reverse_16_fast(0b0000000000000011));
mu_assert_int_eq(0b0000100000001001, bit_lib_reverse_16_fast(0b1001000000010000));
}
MU_TEST(test_bit_lib_crc16) {
uint8_t data[9] = {'1', '2', '3', '4', '5', '6', '7', '8', '9'};
uint8_t data_size = 9;
// Algorithm
// Check Poly Init RefIn RefOut XorOut
// CRC-16/CCITT-FALSE
// 0x29B1 0x1021 0xFFFF false false 0x0000
mu_assert_int_eq(0x29B1, bit_lib_crc16(data, data_size, 0x1021, 0xFFFF, false, false, 0x0000));
// CRC-16/ARC
// 0xBB3D 0x8005 0x0000 true true 0x0000
mu_assert_int_eq(0xBB3D, bit_lib_crc16(data, data_size, 0x8005, 0x0000, true, true, 0x0000));
// CRC-16/AUG-CCITT
// 0xE5CC 0x1021 0x1D0F false false 0x0000
mu_assert_int_eq(0xE5CC, bit_lib_crc16(data, data_size, 0x1021, 0x1D0F, false, false, 0x0000));
// CRC-16/BUYPASS
// 0xFEE8 0x8005 0x0000 false false 0x0000
mu_assert_int_eq(0xFEE8, bit_lib_crc16(data, data_size, 0x8005, 0x0000, false, false, 0x0000));
// CRC-16/CDMA2000
// 0x4C06 0xC867 0xFFFF false false 0x0000
mu_assert_int_eq(0x4C06, bit_lib_crc16(data, data_size, 0xC867, 0xFFFF, false, false, 0x0000));
// CRC-16/DDS-110
// 0x9ECF 0x8005 0x800D false false 0x0000
mu_assert_int_eq(0x9ECF, bit_lib_crc16(data, data_size, 0x8005, 0x800D, false, false, 0x0000));
// CRC-16/DECT-R
// 0x007E 0x0589 0x0000 false false 0x0001
mu_assert_int_eq(0x007E, bit_lib_crc16(data, data_size, 0x0589, 0x0000, false, false, 0x0001));
// CRC-16/DECT-X
// 0x007F 0x0589 0x0000 false false 0x0000
mu_assert_int_eq(0x007F, bit_lib_crc16(data, data_size, 0x0589, 0x0000, false, false, 0x0000));
// CRC-16/DNP
// 0xEA82 0x3D65 0x0000 true true 0xFFFF
mu_assert_int_eq(0xEA82, bit_lib_crc16(data, data_size, 0x3D65, 0x0000, true, true, 0xFFFF));
// CRC-16/EN-13757
// 0xC2B7 0x3D65 0x0000 false false 0xFFFF
mu_assert_int_eq(0xC2B7, bit_lib_crc16(data, data_size, 0x3D65, 0x0000, false, false, 0xFFFF));
// CRC-16/GENIBUS
// 0xD64E 0x1021 0xFFFF false false 0xFFFF
mu_assert_int_eq(0xD64E, bit_lib_crc16(data, data_size, 0x1021, 0xFFFF, false, false, 0xFFFF));
// CRC-16/MAXIM
// 0x44C2 0x8005 0x0000 true true 0xFFFF
mu_assert_int_eq(0x44C2, bit_lib_crc16(data, data_size, 0x8005, 0x0000, true, true, 0xFFFF));
// CRC-16/MCRF4XX
// 0x6F91 0x1021 0xFFFF true true 0x0000
mu_assert_int_eq(0x6F91, bit_lib_crc16(data, data_size, 0x1021, 0xFFFF, true, true, 0x0000));
// CRC-16/RIELLO
// 0x63D0 0x1021 0xB2AA true true 0x0000
mu_assert_int_eq(0x63D0, bit_lib_crc16(data, data_size, 0x1021, 0xB2AA, true, true, 0x0000));
// CRC-16/T10-DIF
// 0xD0DB 0x8BB7 0x0000 false false 0x0000
mu_assert_int_eq(0xD0DB, bit_lib_crc16(data, data_size, 0x8BB7, 0x0000, false, false, 0x0000));
// CRC-16/TELEDISK
// 0x0FB3 0xA097 0x0000 false false 0x0000
mu_assert_int_eq(0x0FB3, bit_lib_crc16(data, data_size, 0xA097, 0x0000, false, false, 0x0000));
// CRC-16/TMS37157
// 0x26B1 0x1021 0x89EC true true 0x0000
mu_assert_int_eq(0x26B1, bit_lib_crc16(data, data_size, 0x1021, 0x89EC, true, true, 0x0000));
// CRC-16/USB
// 0xB4C8 0x8005 0xFFFF true true 0xFFFF
mu_assert_int_eq(0xB4C8, bit_lib_crc16(data, data_size, 0x8005, 0xFFFF, true, true, 0xFFFF));
// CRC-A
// 0xBF05 0x1021 0xC6C6 true true 0x0000
mu_assert_int_eq(0xBF05, bit_lib_crc16(data, data_size, 0x1021, 0xC6C6, true, true, 0x0000));
// CRC-16/KERMIT
// 0x2189 0x1021 0x0000 true true 0x0000
mu_assert_int_eq(0x2189, bit_lib_crc16(data, data_size, 0x1021, 0x0000, true, true, 0x0000));
// CRC-16/MODBUS
// 0x4B37 0x8005 0xFFFF true true 0x0000
mu_assert_int_eq(0x4B37, bit_lib_crc16(data, data_size, 0x8005, 0xFFFF, true, true, 0x0000));
// CRC-16/X-25
// 0x906E 0x1021 0xFFFF true true 0xFFFF
mu_assert_int_eq(0x906E, bit_lib_crc16(data, data_size, 0x1021, 0xFFFF, true, true, 0xFFFF));
// CRC-16/XMODEM
// 0x31C3 0x1021 0x0000 false false 0x0000
mu_assert_int_eq(0x31C3, bit_lib_crc16(data, data_size, 0x1021, 0x0000, false, false, 0x0000));
}
MU_TEST(test_bit_lib_num_to_bytes_be) {
uint8_t src[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
uint8_t dest[8];
bit_lib_num_to_bytes_be(0x01, 1, dest);
mu_assert_mem_eq(src, dest, sizeof(src[0]));
bit_lib_num_to_bytes_be(0x0123456789ABCDEF, 4, dest);
mu_assert_mem_eq(src + 4, dest, 4 * sizeof(src[0]));
bit_lib_num_to_bytes_be(0x0123456789ABCDEF, 8, dest);
mu_assert_mem_eq(src, dest, 8 * sizeof(src[0]));
bit_lib_num_to_bytes_be(bit_lib_bytes_to_num_be(src, 8), 8, dest);
mu_assert_mem_eq(src, dest, 8 * sizeof(src[0]));
}
MU_TEST(test_bit_lib_num_to_bytes_le) {
uint8_t dest[8];
uint8_t n2b_le_expected_1[] = {0x01};
bit_lib_num_to_bytes_le(0x01, 1, dest);
mu_assert_mem_eq(n2b_le_expected_1, dest, sizeof(n2b_le_expected_1[0]));
uint8_t n2b_le_expected_2[] = {0xEF, 0xCD, 0xAB, 0x89};
bit_lib_num_to_bytes_le(0x0123456789ABCDEF, 4, dest);
mu_assert_mem_eq(n2b_le_expected_2, dest, 4 * sizeof(n2b_le_expected_2[0]));
uint8_t n2b_le_expected_3[] = {0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01};
bit_lib_num_to_bytes_le(0x0123456789ABCDEF, 8, dest);
mu_assert_mem_eq(n2b_le_expected_3, dest, 8 * sizeof(n2b_le_expected_3[0]));
bit_lib_num_to_bytes_le(bit_lib_bytes_to_num_le(n2b_le_expected_3, 8), 8, dest);
mu_assert_mem_eq(n2b_le_expected_3, dest, 8 * sizeof(n2b_le_expected_3[0]));
}
MU_TEST(test_bit_lib_bytes_to_num_be) {
uint8_t src[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
uint64_t res;
res = bit_lib_bytes_to_num_be(src, 1);
mu_assert_int_eq(0x01, res);
res = bit_lib_bytes_to_num_be(src, 4);
mu_assert_int_eq(0x01234567, res);
res = bit_lib_bytes_to_num_be(src, 8);
uint64_t expected = 0x0123456789ABCDEF;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
}
MU_TEST(test_bit_lib_bytes_to_num_le) {
uint8_t src[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
uint64_t res;
res = bit_lib_bytes_to_num_le(src, 1);
mu_assert_int_eq(0x01, res);
res = bit_lib_bytes_to_num_le(src, 4);
mu_assert_int_eq(0x67452301, res);
res = bit_lib_bytes_to_num_le(src, 8);
uint64_t expected = 0xEFCDAB8967452301;
mu_assert_mem_eq(&expected, &res, sizeof(expected));
}
MU_TEST(test_bit_lib_bytes_to_num_bcd) {
uint8_t src[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
uint64_t res;
bool is_bcd_res;
res = bit_lib_bytes_to_num_bcd(src, 1, &is_bcd_res);
mu_assert_int_eq(01, res);
mu_assert_int_eq(true, is_bcd_res);
res = bit_lib_bytes_to_num_bcd(src, 4, &is_bcd_res);
mu_assert_int_eq(1234567, res);
mu_assert_int_eq(true, is_bcd_res);
uint8_t digits[5] = {0x98, 0x76, 0x54, 0x32, 0x10};
uint64_t expected = 9876543210;
res = bit_lib_bytes_to_num_bcd(digits, 5, &is_bcd_res);
mu_assert_mem_eq(&expected, &res, sizeof(expected));
mu_assert_int_eq(true, is_bcd_res);
res = bit_lib_bytes_to_num_bcd(src, 8, &is_bcd_res);
mu_assert_int_eq(false, is_bcd_res);
}
MU_TEST_SUITE(test_bit_lib) {
MU_RUN_TEST(test_bit_lib_increment_index);
MU_RUN_TEST(test_bit_lib_is_set);
MU_RUN_TEST(test_bit_lib_push);
MU_RUN_TEST(test_bit_lib_set_bit);
MU_RUN_TEST(test_bit_lib_set_bits);
MU_RUN_TEST(test_bit_lib_get_bit);
MU_RUN_TEST(test_bit_lib_get_bits);
MU_RUN_TEST(test_bit_lib_get_bits_16);
MU_RUN_TEST(test_bit_lib_get_bits_32);
MU_RUN_TEST(test_bit_lib_get_bits_64);
MU_RUN_TEST(test_bit_lib_test_parity_u32);
MU_RUN_TEST(test_bit_lib_test_parity);
MU_RUN_TEST(test_bit_lib_remove_bit_every_nth);
MU_RUN_TEST(test_bit_lib_copy_bits);
MU_RUN_TEST(test_bit_lib_reverse_bits);
MU_RUN_TEST(test_bit_lib_get_bit_count);
MU_RUN_TEST(test_bit_lib_reverse_16_fast);
MU_RUN_TEST(test_bit_lib_crc16);
MU_RUN_TEST(test_bit_lib_num_to_bytes_be);
MU_RUN_TEST(test_bit_lib_num_to_bytes_le);
MU_RUN_TEST(test_bit_lib_bytes_to_num_be);
MU_RUN_TEST(test_bit_lib_bytes_to_num_le);
MU_RUN_TEST(test_bit_lib_bytes_to_num_bcd);
}
int run_minunit_test_bit_lib(void) {
MU_RUN_SUITE(test_bit_lib);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_bit_lib)

View File

@@ -0,0 +1,112 @@
#include <furi.h>
#include <furi_hal.h>
#include "../test.h"
#include <bt/bt_service/bt_keys_storage.h>
#include <storage/storage.h>
#define BT_TEST_KEY_STORAGE_FILE_PATH EXT_PATH("unit_tests/bt_test.keys")
#define BT_TEST_NVM_RAM_BUFF_SIZE (507 * 4) // The same as in ble NVM storage
typedef struct {
Storage* storage;
BtKeysStorage* bt_keys_storage;
uint8_t* nvm_ram_buff_dut;
uint8_t* nvm_ram_buff_ref;
} BtTest;
BtTest* bt_test = NULL;
void bt_test_alloc(void) {
bt_test = malloc(sizeof(BtTest));
bt_test->storage = furi_record_open(RECORD_STORAGE);
bt_test->nvm_ram_buff_dut = malloc(BT_TEST_NVM_RAM_BUFF_SIZE);
bt_test->nvm_ram_buff_ref = malloc(BT_TEST_NVM_RAM_BUFF_SIZE);
bt_test->bt_keys_storage = bt_keys_storage_alloc(BT_TEST_KEY_STORAGE_FILE_PATH);
bt_keys_storage_set_ram_params(
bt_test->bt_keys_storage, bt_test->nvm_ram_buff_dut, BT_TEST_NVM_RAM_BUFF_SIZE);
}
void bt_test_free(void) {
furi_check(bt_test);
free(bt_test->nvm_ram_buff_ref);
free(bt_test->nvm_ram_buff_dut);
bt_keys_storage_free(bt_test->bt_keys_storage);
furi_record_close(RECORD_STORAGE);
free(bt_test);
bt_test = NULL;
}
static void bt_test_keys_storage_profile(void) {
// Emulate nvm change on initial connection
const int nvm_change_size_on_connection = 88;
for(size_t i = 0; i < nvm_change_size_on_connection; i++) {
bt_test->nvm_ram_buff_dut[i] = rand();
bt_test->nvm_ram_buff_ref[i] = bt_test->nvm_ram_buff_dut[i];
}
// Emulate update storage on initial connect
mu_assert(
bt_keys_storage_update(
bt_test->bt_keys_storage, bt_test->nvm_ram_buff_dut, nvm_change_size_on_connection),
"Failed to update key storage on initial connect");
memset(bt_test->nvm_ram_buff_dut, 0, BT_TEST_NVM_RAM_BUFF_SIZE);
mu_assert(bt_keys_storage_load(bt_test->bt_keys_storage), "Failed to load NVM");
mu_assert(
memcmp(
bt_test->nvm_ram_buff_ref, bt_test->nvm_ram_buff_dut, nvm_change_size_on_connection) ==
0,
"Wrong buffer loaded");
const int nvm_disconnect_update_offset = 84;
const int nvm_disconnect_update_size = 324;
const int nvm_total_size = nvm_change_size_on_connection -
(nvm_change_size_on_connection - nvm_disconnect_update_offset) +
nvm_disconnect_update_size;
// Emulate update storage on initial disconnect
for(size_t i = nvm_disconnect_update_offset;
i < nvm_disconnect_update_offset + nvm_disconnect_update_size;
i++) {
bt_test->nvm_ram_buff_dut[i] = rand();
bt_test->nvm_ram_buff_ref[i] = bt_test->nvm_ram_buff_dut[i];
}
mu_assert(
bt_keys_storage_update(
bt_test->bt_keys_storage,
&bt_test->nvm_ram_buff_dut[nvm_disconnect_update_offset],
nvm_disconnect_update_size),
"Failed to update key storage on initial disconnect");
memset(bt_test->nvm_ram_buff_dut, 0, BT_TEST_NVM_RAM_BUFF_SIZE);
mu_assert(bt_keys_storage_load(bt_test->bt_keys_storage), "Failed to load NVM");
mu_assert(
memcmp(bt_test->nvm_ram_buff_ref, bt_test->nvm_ram_buff_dut, nvm_total_size) == 0,
"Wrong buffer loaded");
}
static void bt_test_keys_remove_test_file(void) {
mu_assert(
storage_simply_remove(bt_test->storage, BT_TEST_KEY_STORAGE_FILE_PATH),
"Can't remove test file");
}
MU_TEST(bt_test_keys_storage_serial_profile) {
furi_check(bt_test);
bt_test_keys_remove_test_file();
bt_test_keys_storage_profile();
bt_test_keys_remove_test_file();
}
MU_TEST_SUITE(test_bt) {
bt_test_alloc();
MU_RUN_TEST(bt_test_keys_storage_serial_profile);
bt_test_free();
}
int run_minunit_test_bt(void) {
MU_RUN_SUITE(test_bt);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_bt)

View File

@@ -0,0 +1,42 @@
#include "../test.h"
#include "../minunit_vars.h"
#include <furi.h>
void minunit_print_progress(void) {
static const char progress[] = {'\\', '|', '/', '-'};
static uint8_t progress_counter = 0;
static uint32_t last_tick = 0;
uint32_t current_tick = furi_get_tick();
if(current_tick - last_tick > 20) {
last_tick = current_tick;
printf("[%c]\033[3D", progress[++progress_counter % COUNT_OF(progress)]);
fflush(stdout);
}
}
void minunit_print_fail(const char* str) {
printf(_FURI_LOG_CLR_E "%s\r\n" _FURI_LOG_CLR_RESET, str);
}
void minunit_printf_warning(const char* format, ...) {
FuriString* str = furi_string_alloc();
va_list args;
va_start(args, format);
furi_string_vprintf(str, format, args);
va_end(args);
printf(_FURI_LOG_CLR_W "%s\r\n" _FURI_LOG_CLR_RESET, furi_string_get_cstr(str));
furi_string_free(str);
}
int get_minunit_run(void) {
return minunit_run;
}
int get_minunit_assert(void) {
return minunit_assert;
}
int get_minunit_status(void) {
return minunit_status;
}

View File

@@ -0,0 +1,159 @@
#include "../test.h"
#include <toolbox/compress.h>
#include <furi.h>
#include <furi_hal.h>
#include <furi_hal_random.h>
#include <storage/storage.h>
#include <stdint.h>
#define COMPRESS_UNIT_TESTS_PATH(path) EXT_PATH("unit_tests/compress/" path)
static void compress_test_reference_comp_decomp() {
Storage* storage = furi_record_open(RECORD_STORAGE);
File* compressed_file = storage_file_alloc(storage);
File* decompressed_file = storage_file_alloc(storage);
mu_assert(
storage_file_open(
compressed_file,
COMPRESS_UNIT_TESTS_PATH("compressed.bin"),
FSAM_READ,
FSOM_OPEN_EXISTING),
"Failed to open compressed file");
mu_assert(
storage_file_open(
decompressed_file,
COMPRESS_UNIT_TESTS_PATH("uncompressed.bin"),
FSAM_READ,
FSOM_OPEN_EXISTING),
"Failed to open decompressed file");
uint64_t compressed_ref_size = storage_file_size(compressed_file);
uint64_t decompressed_ref_size = storage_file_size(decompressed_file);
mu_assert(compressed_ref_size > 0 && decompressed_ref_size > 0, "Invalid file sizes");
uint8_t* compressed_ref_buff = malloc(compressed_ref_size);
uint8_t* decompressed_ref_buff = malloc(decompressed_ref_size);
mu_assert(
storage_file_read(compressed_file, compressed_ref_buff, compressed_ref_size) ==
compressed_ref_size,
"Failed to read compressed file");
mu_assert(
storage_file_read(decompressed_file, decompressed_ref_buff, decompressed_ref_size) ==
decompressed_ref_size,
"Failed to read decompressed file");
storage_file_free(compressed_file);
storage_file_free(decompressed_file);
furi_record_close(RECORD_STORAGE);
uint8_t* temp_buffer = malloc(1024);
Compress* comp = compress_alloc(1024);
size_t encoded_size = 0;
mu_assert(
compress_encode(
comp, decompressed_ref_buff, decompressed_ref_size, temp_buffer, 1024, &encoded_size),
"Compress failed");
mu_assert(encoded_size == compressed_ref_size, "Encoded size is not equal to reference size");
mu_assert(
memcmp(temp_buffer, compressed_ref_buff, compressed_ref_size) == 0,
"Encoded buffer is not equal to reference");
size_t decoded_size = 0;
mu_assert(
compress_decode(
comp, compressed_ref_buff, compressed_ref_size, temp_buffer, 1024, &decoded_size),
"Decompress failed");
mu_assert(
decoded_size == decompressed_ref_size, "Decoded size is not equal to reference size");
mu_assert(
memcmp(temp_buffer, decompressed_ref_buff, decompressed_ref_size) == 0,
"Decoded buffer is not equal to reference");
compress_free(comp);
free(temp_buffer);
free(compressed_ref_buff);
free(decompressed_ref_buff);
}
static void compress_test_random_comp_decomp() {
static const size_t src_buffer_size = 1024;
static const size_t encoded_buffer_size = 1024;
static const size_t small_buffer_size = src_buffer_size / 32;
// We only fill half of the buffer with random data, so if anything goes wrong, there's no overflow
static const size_t src_data_size = src_buffer_size / 2;
Compress* comp = compress_alloc(src_buffer_size);
uint8_t* src_buff = malloc(src_buffer_size);
uint8_t* encoded_buff = malloc(encoded_buffer_size);
uint8_t* decoded_buff = malloc(src_buffer_size);
uint8_t* small_buff = malloc(small_buffer_size);
furi_hal_random_fill_buf(src_buff, src_data_size);
size_t encoded_size = 0;
mu_assert(
compress_encode(
comp, src_buff, src_data_size, encoded_buff, encoded_buffer_size, &encoded_size),
"Compress failed");
mu_assert(encoded_size > 0, "Encoded size is zero");
size_t small_enc_dec_size = 0;
mu_assert(
compress_encode(
comp, src_buff, src_data_size, small_buff, small_buffer_size, &small_enc_dec_size) ==
false,
"Compress to small buffer failed");
size_t decoded_size = 0;
mu_assert(
compress_decode(
comp, encoded_buff, encoded_size, decoded_buff, src_buffer_size, &decoded_size),
"Decompress failed");
mu_assert(decoded_size == src_data_size, "Decoded size is not equal to source size");
mu_assert(
memcmp(src_buff, decoded_buff, src_data_size) == 0,
"Decoded buffer is not equal to source");
mu_assert(
compress_decode(
comp, encoded_buff, encoded_size, small_buff, small_buffer_size, &small_enc_dec_size) ==
false,
"Decompress to small buffer failed");
free(small_buff);
free(src_buff);
free(encoded_buff);
free(decoded_buff);
compress_free(comp);
}
MU_TEST_SUITE(test_compress) {
MU_RUN_TEST(compress_test_random_comp_decomp);
MU_RUN_TEST(compress_test_reference_comp_decomp);
}
int run_minunit_test_compress(void) {
MU_RUN_SUITE(test_compress);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_compress)

View File

@@ -0,0 +1,193 @@
#include <furi.h>
#include "../test.h"
#include <datetime/datetime.h>
MU_TEST(test_datetime_validate_datetime_correct_min) {
DateTime correct_min = {0, 0, 0, 1, 1, 2000, 1};
bool result = datetime_validate_datetime(&correct_min);
mu_assert_int_eq(true, result);
}
MU_TEST(test_datetime_validate_datetime_correct_max) {
DateTime correct_max = {23, 59, 59, 31, 12, 2099, 7};
bool result = datetime_validate_datetime(&correct_max);
mu_assert_int_eq(true, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_second) {
DateTime incorrect_sec = {0, 0, 60, 1, 1, 2000, 1};
bool result = datetime_validate_datetime(&incorrect_sec);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_minute) {
DateTime incorrect_min = {0, 60, 0, 1, 1, 2000, 1};
bool result = datetime_validate_datetime(&incorrect_min);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_hour) {
DateTime incorrect_hour = {24, 0, 0, 1, 1, 2000, 1};
bool result = datetime_validate_datetime(&incorrect_hour);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_day_min) {
DateTime incorrect_day_min = {0, 0, 0, 0, 1, 2000, 1};
bool result = datetime_validate_datetime(&incorrect_day_min);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_day_max) {
DateTime incorrect_day_max = {0, 0, 0, 32, 1, 2000, 1};
bool result = datetime_validate_datetime(&incorrect_day_max);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_month_min) {
DateTime incorrect_month_min = {0, 0, 0, 1, 0, 2000, 1};
bool result = datetime_validate_datetime(&incorrect_month_min);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_month_max) {
DateTime incorrect_month_max = {0, 0, 0, 1, 13, 2000, 1};
bool result = datetime_validate_datetime(&incorrect_month_max);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_year_min) {
DateTime incorrect_year_min = {0, 0, 0, 1, 1, 1999, 1};
bool result = datetime_validate_datetime(&incorrect_year_min);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_year_max) {
DateTime incorrect_year_max = {0, 0, 0, 1, 1, 2100, 1};
bool result = datetime_validate_datetime(&incorrect_year_max);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_weekday_min) {
DateTime incorrect_weekday_min = {0, 0, 0, 1, 1, 2000, 0};
bool result = datetime_validate_datetime(&incorrect_weekday_min);
mu_assert_int_eq(false, result);
}
MU_TEST(test_datetime_validate_datetime_incorrect_weekday_max) {
DateTime incorrect_weekday_max = {0, 0, 0, 1, 1, 2000, 8};
bool result = datetime_validate_datetime(&incorrect_weekday_max);
mu_assert_int_eq(false, result);
}
MU_TEST_SUITE(test_datetime_validate_datetime) {
MU_RUN_TEST(test_datetime_validate_datetime_correct_min);
MU_RUN_TEST(test_datetime_validate_datetime_correct_max);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_second);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_minute);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_hour);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_day_min);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_day_max);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_month_min);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_month_max);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_year_min);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_year_max);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_weekday_min);
MU_RUN_TEST(test_datetime_validate_datetime_incorrect_weekday_max);
}
MU_TEST(test_datetime_timestamp_to_datetime_min) {
uint32_t test_value = 0;
DateTime min_datetime_expected = {0, 0, 0, 1, 1, 1970, 4};
DateTime result = {0};
datetime_timestamp_to_datetime(test_value, &result);
mu_assert_mem_eq(&min_datetime_expected, &result, sizeof(result));
}
MU_TEST(test_datetime_timestamp_to_datetime_max) {
uint32_t test_value = UINT32_MAX;
DateTime max_datetime_expected = {6, 28, 15, 7, 2, 2106, 7};
DateTime result = {0};
datetime_timestamp_to_datetime(test_value, &result);
mu_assert_mem_eq(&max_datetime_expected, &result, sizeof(result));
}
MU_TEST(test_datetime_timestamp_to_datetime_to_timestamp) {
uint32_t test_value = random();
DateTime datetime = {0};
datetime_timestamp_to_datetime(test_value, &datetime);
uint32_t result = datetime_datetime_to_timestamp(&datetime);
mu_assert_int_eq(test_value, result);
}
MU_TEST(test_datetime_timestamp_to_datetime_weekday) {
uint32_t test_value = 1709748421; // Wed Mar 06 18:07:01 2024 UTC
DateTime datetime = {0};
datetime_timestamp_to_datetime(test_value, &datetime);
mu_assert_int_eq(datetime.hour, 18);
mu_assert_int_eq(datetime.minute, 7);
mu_assert_int_eq(datetime.second, 1);
mu_assert_int_eq(datetime.day, 6);
mu_assert_int_eq(datetime.month, 3);
mu_assert_int_eq(datetime.weekday, 3);
mu_assert_int_eq(datetime.year, 2024);
}
MU_TEST_SUITE(test_datetime_timestamp_to_datetime_suite) {
MU_RUN_TEST(test_datetime_timestamp_to_datetime_min);
MU_RUN_TEST(test_datetime_timestamp_to_datetime_max);
MU_RUN_TEST(test_datetime_timestamp_to_datetime_to_timestamp);
MU_RUN_TEST(test_datetime_timestamp_to_datetime_weekday);
}
MU_TEST(test_datetime_datetime_to_timestamp_min) {
DateTime min_datetime = {0, 0, 0, 1, 1, 1970, 0};
uint32_t result = datetime_datetime_to_timestamp(&min_datetime);
mu_assert_int_eq(0, result);
}
MU_TEST(test_datetime_datetime_to_timestamp_max) {
DateTime max_datetime = {6, 28, 15, 7, 2, 2106, 0};
uint32_t result = datetime_datetime_to_timestamp(&max_datetime);
mu_assert_int_eq(UINT32_MAX, result);
}
MU_TEST_SUITE(test_datetime_datetime_to_timestamp_suite) {
MU_RUN_TEST(test_datetime_datetime_to_timestamp_min);
MU_RUN_TEST(test_datetime_datetime_to_timestamp_max);
}
int run_minunit_test_datetime(void) {
MU_RUN_SUITE(test_datetime_timestamp_to_datetime_suite);
MU_RUN_SUITE(test_datetime_datetime_to_timestamp_suite);
MU_RUN_SUITE(test_datetime_validate_datetime);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_datetime)

View File

@@ -0,0 +1,34 @@
#include <dialogs/dialogs.h>
#include "../test.h"
MU_TEST(test_dialog_file_browser_set_basic_options_should_init_all_fields) {
mu_assert(
sizeof(DialogsFileBrowserOptions) == 28,
"Changes to `DialogsFileBrowserOptions` should also be reflected in `dialog_file_browser_set_basic_options`");
DialogsFileBrowserOptions options;
dialog_file_browser_set_basic_options(&options, ".fap", NULL);
// note: this assertions can safely be changed, their primary purpose is to remind the maintainer
// to update `dialog_file_browser_set_basic_options` by including all structure fields in it
mu_assert_string_eq(".fap", options.extension);
mu_assert_null(options.base_path);
mu_assert(options.skip_assets, "`skip_assets` should default to `true");
mu_assert(options.hide_dot_files, "`hide_dot_files` should default to `true");
mu_assert_null(options.icon);
mu_assert(options.hide_ext, "`hide_ext` should default to `true");
mu_assert_null(options.item_loader_callback);
mu_assert_null(options.item_loader_context);
}
MU_TEST_SUITE(dialogs_file_browser_options) {
MU_RUN_TEST(test_dialog_file_browser_set_basic_options_should_init_all_fields);
}
int run_minunit_test_dialogs_file_browser_options(void) {
MU_RUN_SUITE(dialogs_file_browser_options);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_dialogs_file_browser_options)

View File

@@ -0,0 +1,274 @@
#include "../test.h"
#include <furi.h>
#include <m-dict.h>
#include <toolbox/dir_walk.h>
static const char* const storage_test_dirwalk_paths[] = {
"1",
"11",
"111",
"1/2",
"1/22",
"1/222",
"11/2",
"111/2",
"111/22",
"111/22/33",
};
static const char* const storage_test_dirwalk_files[] = {
"file1.test",
"file2.test",
"file3.ext_test",
"1/file1.test",
"111/22/33/file1.test",
"111/22/33/file2.test",
"111/22/33/file3.ext_test",
"111/22/33/file4.ext_test",
};
typedef struct {
const char* const path;
bool is_dir;
} StorageTestPathDesc;
const StorageTestPathDesc storage_test_dirwalk_full[] = {
{.path = "1", .is_dir = true},
{.path = "11", .is_dir = true},
{.path = "111", .is_dir = true},
{.path = "1/2", .is_dir = true},
{.path = "1/22", .is_dir = true},
{.path = "1/222", .is_dir = true},
{.path = "11/2", .is_dir = true},
{.path = "111/2", .is_dir = true},
{.path = "111/22", .is_dir = true},
{.path = "111/22/33", .is_dir = true},
{.path = "file1.test", .is_dir = false},
{.path = "file2.test", .is_dir = false},
{.path = "file3.ext_test", .is_dir = false},
{.path = "1/file1.test", .is_dir = false},
{.path = "111/22/33/file1.test", .is_dir = false},
{.path = "111/22/33/file2.test", .is_dir = false},
{.path = "111/22/33/file3.ext_test", .is_dir = false},
{.path = "111/22/33/file4.ext_test", .is_dir = false},
};
const StorageTestPathDesc storage_test_dirwalk_no_recursive[] = {
{.path = "1", .is_dir = true},
{.path = "11", .is_dir = true},
{.path = "111", .is_dir = true},
{.path = "file1.test", .is_dir = false},
{.path = "file2.test", .is_dir = false},
{.path = "file3.ext_test", .is_dir = false},
};
const StorageTestPathDesc storage_test_dirwalk_filter[] = {
{.path = "file1.test", .is_dir = false},
{.path = "file2.test", .is_dir = false},
{.path = "1/file1.test", .is_dir = false},
{.path = "111/22/33/file1.test", .is_dir = false},
{.path = "111/22/33/file2.test", .is_dir = false},
};
typedef struct {
bool is_dir;
bool visited;
} StorageTestPath;
DICT_DEF2(StorageTestPathDict, FuriString*, FURI_STRING_OPLIST, StorageTestPath, M_POD_OPLIST)
static StorageTestPathDict_t*
storage_test_paths_alloc(const StorageTestPathDesc paths[], size_t paths_count) {
StorageTestPathDict_t* data = malloc(sizeof(StorageTestPathDict_t));
StorageTestPathDict_init(*data);
for(size_t i = 0; i < paths_count; i++) {
FuriString* key;
key = furi_string_alloc_set(paths[i].path);
StorageTestPath value = {
.is_dir = paths[i].is_dir,
.visited = false,
};
StorageTestPathDict_set_at(*data, key, value);
furi_string_free(key);
}
return data;
}
static void storage_test_paths_free(StorageTestPathDict_t* data) {
StorageTestPathDict_clear(*data);
free(data);
}
static bool storage_test_paths_mark(StorageTestPathDict_t* data, FuriString* path, bool is_dir) {
bool found = false;
StorageTestPath* record = StorageTestPathDict_get(*data, path);
if(record) {
if(is_dir == record->is_dir) {
if(record->visited == false) {
record->visited = true;
found = true;
}
}
}
return found;
}
static bool storage_test_paths_check(StorageTestPathDict_t* data) {
bool error = false;
StorageTestPathDict_it_t it;
for(StorageTestPathDict_it(it, *data); !StorageTestPathDict_end_p(it);
StorageTestPathDict_next(it)) {
const StorageTestPathDict_itref_t* itref = StorageTestPathDict_cref(it);
if(itref->value.visited == false) {
error = true;
break;
}
}
return error;
}
static bool write_file_13DA(Storage* storage, const char* path) {
File* file = storage_file_alloc(storage);
bool result = false;
if(storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
result = (storage_file_write(file, "13DA", 4) == 4);
}
storage_file_close(file);
storage_file_free(file);
return result;
}
static void storage_dirs_create(Storage* storage, const char* base) {
FuriString* path;
path = furi_string_alloc();
storage_common_mkdir(storage, base);
for(size_t i = 0; i < COUNT_OF(storage_test_dirwalk_paths); i++) {
furi_string_printf(path, "%s/%s", base, storage_test_dirwalk_paths[i]);
storage_common_mkdir(storage, furi_string_get_cstr(path));
}
for(size_t i = 0; i < COUNT_OF(storage_test_dirwalk_files); i++) {
furi_string_printf(path, "%s/%s", base, storage_test_dirwalk_files[i]);
write_file_13DA(storage, furi_string_get_cstr(path));
}
furi_string_free(path);
}
MU_TEST_1(test_dirwalk_full, Storage* storage) {
FuriString* path;
path = furi_string_alloc();
FileInfo fileinfo;
StorageTestPathDict_t* paths =
storage_test_paths_alloc(storage_test_dirwalk_full, COUNT_OF(storage_test_dirwalk_full));
DirWalk* dir_walk = dir_walk_alloc(storage);
mu_check(dir_walk_open(dir_walk, EXT_PATH("dirwalk")));
while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) {
furi_string_right(path, strlen(EXT_PATH("dirwalk/")));
mu_check(storage_test_paths_mark(paths, path, file_info_is_dir(&fileinfo)));
}
dir_walk_free(dir_walk);
furi_string_free(path);
mu_check(storage_test_paths_check(paths) == false);
storage_test_paths_free(paths);
}
MU_TEST_1(test_dirwalk_no_recursive, Storage* storage) {
FuriString* path;
path = furi_string_alloc();
FileInfo fileinfo;
StorageTestPathDict_t* paths = storage_test_paths_alloc(
storage_test_dirwalk_no_recursive, COUNT_OF(storage_test_dirwalk_no_recursive));
DirWalk* dir_walk = dir_walk_alloc(storage);
dir_walk_set_recursive(dir_walk, false);
mu_check(dir_walk_open(dir_walk, EXT_PATH("dirwalk")));
while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) {
furi_string_right(path, strlen(EXT_PATH("dirwalk/")));
mu_check(storage_test_paths_mark(paths, path, file_info_is_dir(&fileinfo)));
}
dir_walk_free(dir_walk);
furi_string_free(path);
mu_check(storage_test_paths_check(paths) == false);
storage_test_paths_free(paths);
}
static bool test_dirwalk_filter_no_folder_ext(const char* name, FileInfo* fileinfo, void* ctx) {
UNUSED(ctx);
// only files
if(!file_info_is_dir(fileinfo)) {
// with ".test" in name
if(strstr(name, ".test") != NULL) {
return true;
}
}
return false;
}
MU_TEST_1(test_dirwalk_filter, Storage* storage) {
FuriString* path;
path = furi_string_alloc();
FileInfo fileinfo;
StorageTestPathDict_t* paths = storage_test_paths_alloc(
storage_test_dirwalk_filter, COUNT_OF(storage_test_dirwalk_filter));
DirWalk* dir_walk = dir_walk_alloc(storage);
dir_walk_set_filter_cb(dir_walk, test_dirwalk_filter_no_folder_ext, NULL);
mu_check(dir_walk_open(dir_walk, EXT_PATH("dirwalk")));
while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) {
furi_string_right(path, strlen(EXT_PATH("dirwalk/")));
mu_check(storage_test_paths_mark(paths, path, file_info_is_dir(&fileinfo)));
}
dir_walk_free(dir_walk);
furi_string_free(path);
mu_check(storage_test_paths_check(paths) == false);
storage_test_paths_free(paths);
}
MU_TEST_SUITE(test_dirwalk_suite) {
Storage* storage = furi_record_open(RECORD_STORAGE);
storage_dirs_create(storage, EXT_PATH("dirwalk"));
MU_RUN_TEST_1(test_dirwalk_full, storage);
MU_RUN_TEST_1(test_dirwalk_no_recursive, storage);
MU_RUN_TEST_1(test_dirwalk_filter, storage);
storage_simply_remove_recursive(storage, EXT_PATH("dirwalk"));
furi_record_close(RECORD_STORAGE);
}
int run_minunit_test_dirwalk(void) {
MU_RUN_SUITE(test_dirwalk_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_dirwalk)

View File

@@ -0,0 +1,202 @@
#include "../test.h"
#include <furi.h>
#include <furi_hal_random.h>
#include <expansion/expansion_protocol.h>
#define EXPANSION_TEST_GARBAGE_MAGIC (0xB19AF)
#define EXPANSION_TEST_GARBAGE_BUF_SIZE (0x100U)
#define EXPANSION_TEST_GARBAGE_ITERATIONS (100U)
MU_TEST(test_expansion_encoded_size) {
ExpansionFrame frame = {};
frame.header.type = ExpansionFrameTypeHeartbeat;
mu_assert_int_eq(1, expansion_frame_get_encoded_size(&frame));
frame.header.type = ExpansionFrameTypeStatus;
mu_assert_int_eq(2, expansion_frame_get_encoded_size(&frame));
frame.header.type = ExpansionFrameTypeBaudRate;
mu_assert_int_eq(5, expansion_frame_get_encoded_size(&frame));
frame.header.type = ExpansionFrameTypeControl;
mu_assert_int_eq(2, expansion_frame_get_encoded_size(&frame));
frame.header.type = ExpansionFrameTypeData;
for(size_t i = 0; i <= EXPANSION_PROTOCOL_MAX_DATA_SIZE; ++i) {
frame.content.data.size = i;
mu_assert_int_eq(i + 2, expansion_frame_get_encoded_size(&frame));
}
}
MU_TEST(test_expansion_remaining_size) {
ExpansionFrame frame = {};
size_t remaining_size;
mu_check(expansion_frame_get_remaining_size(&frame, 0, &remaining_size));
mu_assert_int_eq(1, remaining_size);
frame.header.type = ExpansionFrameTypeHeartbeat;
mu_check(expansion_frame_get_remaining_size(&frame, 0, &remaining_size));
mu_assert_int_eq(1, remaining_size);
mu_check(expansion_frame_get_remaining_size(&frame, 1, &remaining_size));
mu_assert_int_eq(0, remaining_size);
mu_check(expansion_frame_get_remaining_size(&frame, 100, &remaining_size));
mu_assert_int_eq(0, remaining_size);
frame.header.type = ExpansionFrameTypeStatus;
mu_check(expansion_frame_get_remaining_size(&frame, 0, &remaining_size));
mu_assert_int_eq(1, remaining_size);
mu_check(expansion_frame_get_remaining_size(&frame, 1, &remaining_size));
mu_assert_int_eq(1, remaining_size);
mu_check(expansion_frame_get_remaining_size(&frame, 2, &remaining_size));
mu_assert_int_eq(0, remaining_size);
mu_check(expansion_frame_get_remaining_size(&frame, 100, &remaining_size));
mu_assert_int_eq(0, remaining_size);
frame.header.type = ExpansionFrameTypeBaudRate;
mu_check(expansion_frame_get_remaining_size(&frame, 0, &remaining_size));
mu_assert_int_eq(1, remaining_size);
mu_check(expansion_frame_get_remaining_size(&frame, 1, &remaining_size));
mu_assert_int_eq(4, remaining_size);
mu_check(expansion_frame_get_remaining_size(&frame, 5, &remaining_size));
mu_assert_int_eq(0, remaining_size);
mu_check(expansion_frame_get_remaining_size(&frame, 100, &remaining_size));
mu_assert_int_eq(0, remaining_size);
frame.header.type = ExpansionFrameTypeControl;
mu_check(expansion_frame_get_remaining_size(&frame, 0, &remaining_size));
mu_assert_int_eq(1, remaining_size);
mu_check(expansion_frame_get_remaining_size(&frame, 1, &remaining_size));
mu_assert_int_eq(1, remaining_size);
mu_check(expansion_frame_get_remaining_size(&frame, 2, &remaining_size));
mu_assert_int_eq(0, remaining_size);
mu_check(expansion_frame_get_remaining_size(&frame, 100, &remaining_size));
mu_assert_int_eq(0, remaining_size);
frame.header.type = ExpansionFrameTypeData;
frame.content.data.size = EXPANSION_PROTOCOL_MAX_DATA_SIZE;
mu_check(expansion_frame_get_remaining_size(&frame, 0, &remaining_size));
mu_assert_int_eq(1, remaining_size);
mu_check(expansion_frame_get_remaining_size(&frame, 1, &remaining_size));
mu_assert_int_eq(1, remaining_size);
mu_check(expansion_frame_get_remaining_size(&frame, 2, &remaining_size));
mu_assert_int_eq(EXPANSION_PROTOCOL_MAX_DATA_SIZE, remaining_size);
for(size_t i = 0; i <= EXPANSION_PROTOCOL_MAX_DATA_SIZE; ++i) {
mu_check(expansion_frame_get_remaining_size(&frame, i + 2, &remaining_size));
mu_assert_int_eq(EXPANSION_PROTOCOL_MAX_DATA_SIZE - i, remaining_size);
}
mu_check(expansion_frame_get_remaining_size(&frame, 100, &remaining_size));
mu_assert_int_eq(0, remaining_size);
}
typedef struct {
void* data_out;
size_t size_available;
size_t size_sent;
} TestExpansionSendStream;
static size_t test_expansion_send_callback(const uint8_t* data, size_t data_size, void* context) {
TestExpansionSendStream* stream = context;
const size_t size_sent = MIN(data_size, stream->size_available);
memcpy(stream->data_out + stream->size_sent, data, size_sent);
stream->size_available -= size_sent;
stream->size_sent += size_sent;
return size_sent;
}
typedef struct {
const void* data_in;
size_t size_available;
size_t size_received;
} TestExpansionReceiveStream;
static size_t test_expansion_receive_callback(uint8_t* data, size_t data_size, void* context) {
TestExpansionReceiveStream* stream = context;
const size_t size_received = MIN(data_size, stream->size_available);
memcpy(data, stream->data_in + stream->size_received, size_received);
stream->size_available -= size_received;
stream->size_received += size_received;
return size_received;
}
MU_TEST(test_expansion_encode_decode_frame) {
const ExpansionFrame frame_in = {
.header.type = ExpansionFrameTypeData,
.content.data.size = 8,
.content.data.bytes = {0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xca, 0xfe},
};
uint8_t encoded_data[sizeof(ExpansionFrame) + sizeof(ExpansionFrameChecksum)];
memset(encoded_data, 0, sizeof(encoded_data));
TestExpansionSendStream send_stream = {
.data_out = &encoded_data,
.size_available = sizeof(encoded_data),
.size_sent = 0,
};
const size_t encoded_size = expansion_frame_get_encoded_size(&frame_in);
mu_assert_int_eq(
expansion_protocol_encode(&frame_in, test_expansion_send_callback, &send_stream),
ExpansionProtocolStatusOk);
mu_assert_int_eq(encoded_size + sizeof(ExpansionFrameChecksum), send_stream.size_sent);
mu_assert_int_eq(
expansion_protocol_get_checksum((const uint8_t*)&frame_in, encoded_size),
encoded_data[encoded_size]);
mu_assert_mem_eq(&frame_in, &encoded_data, encoded_size);
TestExpansionReceiveStream stream = {
.data_in = encoded_data,
.size_available = send_stream.size_sent,
.size_received = 0,
};
ExpansionFrame frame_out;
mu_assert_int_eq(
expansion_protocol_decode(&frame_out, test_expansion_receive_callback, &stream),
ExpansionProtocolStatusOk);
mu_assert_int_eq(encoded_size + sizeof(ExpansionFrameChecksum), stream.size_received);
mu_assert_mem_eq(&frame_in, &frame_out, encoded_size);
}
MU_TEST(test_expansion_garbage_input) {
uint8_t garbage_data[EXPANSION_TEST_GARBAGE_BUF_SIZE];
for(uint32_t i = 0; i < EXPANSION_TEST_GARBAGE_ITERATIONS; ++i) {
furi_hal_random_fill_buf(garbage_data, sizeof(garbage_data));
size_t remaining_size = EXPANSION_TEST_GARBAGE_MAGIC;
if(expansion_frame_get_remaining_size(
(ExpansionFrame*)garbage_data, sizeof(garbage_data), &remaining_size)) {
// If by chance the garbage data is a valid frame, then the result
// must be 0 because the amount of data provided is more than enough
mu_assert_int_eq(0, remaining_size);
} else {
// If the frame is invalid, the remaining_size parameter should be untouched
mu_assert_int_eq(EXPANSION_TEST_GARBAGE_MAGIC, remaining_size);
}
}
}
MU_TEST_SUITE(test_expansion_suite) {
MU_RUN_TEST(test_expansion_encoded_size);
MU_RUN_TEST(test_expansion_remaining_size);
MU_RUN_TEST(test_expansion_encode_decode_frame);
MU_RUN_TEST(test_expansion_garbage_input);
}
int run_minunit_test_expansion(void) {
MU_RUN_SUITE(test_expansion_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_expansion)

View File

@@ -0,0 +1,553 @@
#include <furi.h>
#include <flipper_format/flipper_format.h>
#include <flipper_format/flipper_format_i.h>
#include <toolbox/stream/stream.h>
#include "../test.h"
#define TEST_DIR TEST_DIR_NAME "/"
#define TEST_DIR_NAME EXT_PATH("unit_tests_tmp")
static const char* test_filetype = "Flipper File test";
static const uint32_t test_version = 666;
static const char* test_string_key = "String data";
static const char* test_string_data = "String";
static const char* test_string_updated_data = "New string";
static const char* test_int_key = "Int32 data";
static const int32_t test_int_data[] = {1234, -6345, 7813, 0};
static const int32_t test_int_updated_data[] = {-1337, 69};
static const char* test_uint_key = "Uint32 data";
static const uint32_t test_uint_data[] = {1234, 0, 5678, 9098, 7654321};
static const uint32_t test_uint_updated_data[] = {8, 800, 555, 35, 35};
static const char* test_float_key = "Float data";
static const float test_float_data[] = {1.5f, 1000.0f};
static const float test_float_updated_data[] = {1.2f};
static const char* test_bool_key = "Bool data";
static const bool test_bool_data[] = {true, false};
static const bool test_bool_updated_data[] = {false, true, true};
static const char* test_hex_key = "Hex data";
static const uint8_t test_hex_data[] = {0xDE, 0xAD, 0xBE};
static const uint8_t test_hex_updated_data[] = {0xFE, 0xCA};
#define READ_TEST_NIX "ff_nix.test"
static const char* test_data_nix = "Filetype: Flipper File test\n"
"Version: 666\n"
"# This is comment\n"
"String data: String\n"
"Int32 data: 1234 -6345 7813 0\n"
"Uint32 data: 1234 0 5678 9098 7654321\n"
"Float data: 1.5 1000.0\n"
"Bool data: true false\n"
"Hex data: DE AD BE";
#define READ_TEST_WIN "ff_win.test"
static const char* test_data_win = "Filetype: Flipper File test\r\n"
"Version: 666\r\n"
"# This is comment\r\n"
"String data: String\r\n"
"Int32 data: 1234 -6345 7813 0\r\n"
"Uint32 data: 1234 0 5678 9098 7654321\r\n"
"Float data: 1.5 1000.0\r\n"
"Bool data: true false\r\n"
"Hex data: DE AD BE";
#define READ_TEST_FLP "ff_flp.test"
#define READ_TEST_ODD "ff_oddities.test"
static const char* test_data_odd = "Filetype: Flipper File test\n"
// Tabs before newline
"Version: 666\t\t\n"
"# This is comment\n"
// Windows newline in a UNIX file
"String data: String\r\n"
// Trailing whitespace
"Int32 data: 1234 -6345 7813 0 \n"
// Extra whitespace
"Uint32 data: 1234 0 5678 9098 7654321 \n"
// Mixed whitespace
"Float data: 1.5\t \t1000.0\n"
// Leading tabs after key
"Bool data:\t\ttrue false\n"
// Mixed trailing whitespace
"Hex data: DE AD BE\t ";
// data created by user on linux machine
static const char* test_file_linux = TEST_DIR READ_TEST_NIX;
// data created by user on windows machine
static const char* test_file_windows = TEST_DIR READ_TEST_WIN;
// data created by flipper itself
static const char* test_file_flipper = TEST_DIR READ_TEST_FLP;
// data containing odd user input
static const char* test_file_oddities = TEST_DIR READ_TEST_ODD;
static bool storage_write_string(const char* path, const char* data) {
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);
bool result = false;
do {
if(!storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) break;
if(storage_file_write(file, data, strlen(data)) != strlen(data)) break;
result = true;
} while(false);
storage_file_close(file);
storage_file_free(file);
furi_record_close(RECORD_STORAGE);
return result;
}
static void tests_setup(void) {
Storage* storage = furi_record_open(RECORD_STORAGE);
mu_assert(storage_simply_remove_recursive(storage, TEST_DIR_NAME), "Cannot clean data");
mu_assert(storage_simply_mkdir(storage, TEST_DIR_NAME), "Cannot create dir");
furi_record_close(RECORD_STORAGE);
}
static void tests_teardown(void) {
Storage* storage = furi_record_open(RECORD_STORAGE);
mu_assert(storage_simply_remove_recursive(storage, TEST_DIR_NAME), "Cannot clean data");
furi_record_close(RECORD_STORAGE);
}
static bool test_read(const char* file_name) {
Storage* storage = furi_record_open(RECORD_STORAGE);
bool result = false;
FlipperFormat* file = flipper_format_file_alloc(storage);
FuriString* string_value;
string_value = furi_string_alloc();
uint32_t uint32_value;
void* scratchpad = malloc(512);
do {
if(!flipper_format_file_open_existing(file, file_name)) break;
if(!flipper_format_read_header(file, string_value, &uint32_value)) break;
if(furi_string_cmp_str(string_value, test_filetype) != 0) break;
if(uint32_value != test_version) break;
if(!flipper_format_read_string(file, test_string_key, string_value)) break;
if(furi_string_cmp_str(string_value, test_string_data) != 0) break;
if(!flipper_format_get_value_count(file, test_int_key, &uint32_value)) break;
if(uint32_value != COUNT_OF(test_int_data)) break;
if(!flipper_format_read_int32(file, test_int_key, scratchpad, uint32_value)) break;
if(memcmp(scratchpad, test_int_data, sizeof(int32_t) * COUNT_OF(test_int_data)) != 0)
break;
if(!flipper_format_get_value_count(file, test_uint_key, &uint32_value)) break;
if(uint32_value != COUNT_OF(test_uint_data)) break;
if(!flipper_format_read_uint32(file, test_uint_key, scratchpad, uint32_value)) break;
if(memcmp(scratchpad, test_uint_data, sizeof(uint32_t) * COUNT_OF(test_uint_data)) != 0)
break;
if(!flipper_format_get_value_count(file, test_float_key, &uint32_value)) break;
if(uint32_value != COUNT_OF(test_float_data)) break;
if(!flipper_format_read_float(file, test_float_key, scratchpad, uint32_value)) break;
if(memcmp(scratchpad, test_float_data, sizeof(float) * COUNT_OF(test_float_data)) != 0)
break;
if(!flipper_format_get_value_count(file, test_bool_key, &uint32_value)) break;
if(uint32_value != COUNT_OF(test_bool_data)) break;
if(!flipper_format_read_bool(file, test_bool_key, scratchpad, uint32_value)) break;
if(memcmp(scratchpad, test_bool_data, sizeof(bool) * COUNT_OF(test_bool_data)) != 0) break;
if(!flipper_format_get_value_count(file, test_hex_key, &uint32_value)) break;
if(uint32_value != COUNT_OF(test_hex_data)) break;
if(!flipper_format_read_hex(file, test_hex_key, scratchpad, uint32_value)) break;
if(memcmp(scratchpad, test_hex_data, sizeof(uint8_t) * COUNT_OF(test_hex_data)) != 0)
break;
result = true;
} while(false);
free(scratchpad);
furi_string_free(string_value);
flipper_format_free(file);
furi_record_close(RECORD_STORAGE);
return result;
}
static bool test_read_updated(const char* file_name) {
Storage* storage = furi_record_open(RECORD_STORAGE);
bool result = false;
FlipperFormat* file = flipper_format_file_alloc(storage);
FuriString* string_value;
string_value = furi_string_alloc();
uint32_t uint32_value;
void* scratchpad = malloc(512);
do {
if(!flipper_format_file_open_existing(file, file_name)) break;
if(!flipper_format_read_header(file, string_value, &uint32_value)) break;
if(furi_string_cmp_str(string_value, test_filetype) != 0) break;
if(uint32_value != test_version) break;
if(!flipper_format_read_string(file, test_string_key, string_value)) break;
if(furi_string_cmp_str(string_value, test_string_updated_data) != 0) break;
if(!flipper_format_get_value_count(file, test_int_key, &uint32_value)) break;
if(uint32_value != COUNT_OF(test_int_updated_data)) break;
if(!flipper_format_read_int32(file, test_int_key, scratchpad, uint32_value)) break;
if(memcmp(
scratchpad,
test_int_updated_data,
sizeof(int32_t) * COUNT_OF(test_int_updated_data)) != 0)
break;
if(!flipper_format_get_value_count(file, test_uint_key, &uint32_value)) break;
if(uint32_value != COUNT_OF(test_uint_updated_data)) break;
if(!flipper_format_read_uint32(file, test_uint_key, scratchpad, uint32_value)) break;
if(memcmp(
scratchpad,
test_uint_updated_data,
sizeof(uint32_t) * COUNT_OF(test_uint_updated_data)) != 0)
break;
if(!flipper_format_get_value_count(file, test_float_key, &uint32_value)) break;
if(uint32_value != COUNT_OF(test_float_updated_data)) break;
if(!flipper_format_read_float(file, test_float_key, scratchpad, uint32_value)) break;
if(memcmp(
scratchpad,
test_float_updated_data,
sizeof(float) * COUNT_OF(test_float_updated_data)) != 0)
break;
if(!flipper_format_get_value_count(file, test_bool_key, &uint32_value)) break;
if(uint32_value != COUNT_OF(test_bool_updated_data)) break;
if(!flipper_format_read_bool(file, test_bool_key, scratchpad, uint32_value)) break;
if(memcmp(
scratchpad,
test_bool_updated_data,
sizeof(bool) * COUNT_OF(test_bool_updated_data)) != 0)
break;
if(!flipper_format_get_value_count(file, test_hex_key, &uint32_value)) break;
if(uint32_value != COUNT_OF(test_hex_updated_data)) break;
if(!flipper_format_read_hex(file, test_hex_key, scratchpad, uint32_value)) break;
if(memcmp(
scratchpad,
test_hex_updated_data,
sizeof(uint8_t) * COUNT_OF(test_hex_updated_data)) != 0)
break;
result = true;
} while(false);
free(scratchpad);
furi_string_free(string_value);
flipper_format_free(file);
furi_record_close(RECORD_STORAGE);
return result;
}
static bool test_write(const char* file_name) {
Storage* storage = furi_record_open(RECORD_STORAGE);
bool result = false;
FlipperFormat* file = flipper_format_file_alloc(storage);
do {
if(!flipper_format_file_open_always(file, file_name)) break;
if(!flipper_format_write_header_cstr(file, test_filetype, test_version)) break;
if(!flipper_format_write_comment_cstr(file, "This is comment")) break;
if(!flipper_format_write_string_cstr(file, test_string_key, test_string_data)) break;
if(!flipper_format_write_int32(file, test_int_key, test_int_data, COUNT_OF(test_int_data)))
break;
if(!flipper_format_write_uint32(
file, test_uint_key, test_uint_data, COUNT_OF(test_uint_data)))
break;
if(!flipper_format_write_float(
file, test_float_key, test_float_data, COUNT_OF(test_float_data)))
break;
if(!flipper_format_write_bool(
file, test_bool_key, test_bool_data, COUNT_OF(test_bool_data)))
break;
if(!flipper_format_write_hex(file, test_hex_key, test_hex_data, COUNT_OF(test_hex_data)))
break;
result = true;
} while(false);
flipper_format_free(file);
furi_record_close(RECORD_STORAGE);
return result;
}
static bool test_delete_last_key(const char* file_name) {
Storage* storage = furi_record_open(RECORD_STORAGE);
bool result = false;
FlipperFormat* file = flipper_format_file_alloc(storage);
do {
if(!flipper_format_file_open_existing(file, file_name)) break;
if(!flipper_format_delete_key(file, test_hex_key)) break;
result = true;
} while(false);
flipper_format_free(file);
furi_record_close(RECORD_STORAGE);
return result;
}
static bool test_append_key(const char* file_name) {
Storage* storage = furi_record_open(RECORD_STORAGE);
bool result = false;
FlipperFormat* file = flipper_format_file_alloc(storage);
do {
if(!flipper_format_file_open_append(file, file_name)) break;
if(!flipper_format_write_hex(file, test_hex_key, test_hex_data, COUNT_OF(test_hex_data)))
break;
result = true;
} while(false);
flipper_format_free(file);
furi_record_close(RECORD_STORAGE);
return result;
}
static bool test_update(const char* file_name) {
Storage* storage = furi_record_open(RECORD_STORAGE);
bool result = false;
FlipperFormat* file = flipper_format_file_alloc(storage);
do {
if(!flipper_format_file_open_existing(file, file_name)) break;
if(!flipper_format_update_string_cstr(file, test_string_key, test_string_updated_data))
break;
if(!flipper_format_update_int32(
file, test_int_key, test_int_updated_data, COUNT_OF(test_int_updated_data)))
break;
if(!flipper_format_update_uint32(
file, test_uint_key, test_uint_updated_data, COUNT_OF(test_uint_updated_data)))
break;
if(!flipper_format_update_float(
file, test_float_key, test_float_updated_data, COUNT_OF(test_float_updated_data)))
break;
if(!flipper_format_update_bool(
file, test_bool_key, test_bool_updated_data, COUNT_OF(test_bool_updated_data)))
break;
if(!flipper_format_update_hex(
file, test_hex_key, test_hex_updated_data, COUNT_OF(test_hex_updated_data)))
break;
result = true;
} while(false);
flipper_format_free(file);
furi_record_close(RECORD_STORAGE);
return result;
}
static bool test_update_backward(const char* file_name) {
Storage* storage = furi_record_open(RECORD_STORAGE);
bool result = false;
FlipperFormat* file = flipper_format_file_alloc(storage);
do {
if(!flipper_format_file_open_existing(file, file_name)) break;
if(!flipper_format_update_string_cstr(file, test_string_key, test_string_data)) break;
if(!flipper_format_update_int32(file, test_int_key, test_int_data, COUNT_OF(test_int_data)))
break;
if(!flipper_format_update_uint32(
file, test_uint_key, test_uint_data, COUNT_OF(test_uint_data)))
break;
if(!flipper_format_update_float(
file, test_float_key, test_float_data, COUNT_OF(test_float_data)))
break;
if(!flipper_format_update_bool(
file, test_bool_key, test_bool_data, COUNT_OF(test_bool_data)))
break;
if(!flipper_format_update_hex(file, test_hex_key, test_hex_data, COUNT_OF(test_hex_data)))
break;
result = true;
} while(false);
flipper_format_free(file);
furi_record_close(RECORD_STORAGE);
return result;
}
static bool test_write_multikey(const char* file_name) {
Storage* storage = furi_record_open(RECORD_STORAGE);
bool result = false;
FlipperFormat* file = flipper_format_file_alloc(storage);
do {
if(!flipper_format_file_open_always(file, file_name)) break;
if(!flipper_format_write_header_cstr(file, test_filetype, test_version)) break;
bool error = false;
for(uint8_t index = 0; index < 100; index++) {
if(!flipper_format_write_hex(file, test_hex_key, &index, 1)) {
error = true;
break;
}
}
if(error) break;
result = true;
} while(false);
flipper_format_free(file);
furi_record_close(RECORD_STORAGE);
return result;
}
static bool test_read_multikey(const char* file_name) {
Storage* storage = furi_record_open(RECORD_STORAGE);
bool result = false;
FlipperFormat* file = flipper_format_file_alloc(storage);
FuriString* string_value;
string_value = furi_string_alloc();
uint32_t uint32_value;
do {
if(!flipper_format_file_open_existing(file, file_name)) break;
if(!flipper_format_read_header(file, string_value, &uint32_value)) break;
if(furi_string_cmp_str(string_value, test_filetype) != 0) break;
if(uint32_value != test_version) break;
bool error = false;
uint8_t uint8_value;
for(uint8_t index = 0; index < 100; index++) {
if(!flipper_format_read_hex(file, test_hex_key, &uint8_value, 1)) {
error = true;
break;
}
if(uint8_value != index) {
error = true;
break;
}
}
if(error) break;
result = true;
} while(false);
furi_string_free(string_value);
flipper_format_free(file);
furi_record_close(RECORD_STORAGE);
return result;
}
MU_TEST(flipper_format_write_test) {
mu_assert(storage_write_string(test_file_linux, test_data_nix), "Write test error [Linux]");
mu_assert(
storage_write_string(test_file_windows, test_data_win), "Write test error [Windows]");
mu_assert(test_write(test_file_flipper), "Write test error [Flipper]");
}
MU_TEST(flipper_format_read_test) {
mu_assert(test_read(test_file_linux), "Read test error [Linux]");
mu_assert(test_read(test_file_windows), "Read test error [Windows]");
mu_assert(test_read(test_file_flipper), "Read test error [Flipper]");
}
MU_TEST(flipper_format_delete_test) {
mu_assert(test_delete_last_key(test_file_linux), "Cannot delete key [Linux]");
mu_assert(test_delete_last_key(test_file_windows), "Cannot delete key [Windows]");
mu_assert(test_delete_last_key(test_file_flipper), "Cannot delete key [Flipper]");
}
MU_TEST(flipper_format_delete_result_test) {
mu_assert(!test_read(test_file_linux), "Key deleted incorrectly [Linux]");
mu_assert(!test_read(test_file_windows), "Key deleted incorrectly [Windows]");
mu_assert(!test_read(test_file_flipper), "Key deleted incorrectly [Flipper]");
}
MU_TEST(flipper_format_append_test) {
mu_assert(test_append_key(test_file_linux), "Cannot append data [Linux]");
mu_assert(test_append_key(test_file_windows), "Cannot append data [Windows]");
mu_assert(test_append_key(test_file_flipper), "Cannot append data [Flipper]");
}
MU_TEST(flipper_format_append_result_test) {
mu_assert(test_read(test_file_linux), "Data appended incorrectly [Linux]");
mu_assert(test_read(test_file_windows), "Data appended incorrectly [Windows]");
mu_assert(test_read(test_file_flipper), "Data appended incorrectly [Flipper]");
}
MU_TEST(flipper_format_update_1_test) {
mu_assert(test_update(test_file_linux), "Cannot update data #1 [Linux]");
mu_assert(test_update(test_file_windows), "Cannot update data #1 [Windows]");
mu_assert(test_update(test_file_flipper), "Cannot update data #1 [Flipper]");
}
MU_TEST(flipper_format_update_1_result_test) {
mu_assert(test_read_updated(test_file_linux), "Data #1 updated incorrectly [Linux]");
mu_assert(test_read_updated(test_file_windows), "Data #1 updated incorrectly [Windows]");
mu_assert(test_read_updated(test_file_flipper), "Data #1 updated incorrectly [Flipper]");
}
MU_TEST(flipper_format_update_2_test) {
mu_assert(test_update_backward(test_file_linux), "Cannot update data #2 [Linux]");
mu_assert(test_update_backward(test_file_windows), "Cannot update data #2 [Windows]");
mu_assert(test_update_backward(test_file_flipper), "Cannot update data #2 [Flipper]");
}
MU_TEST(flipper_format_update_2_result_test) {
mu_assert(test_read(test_file_linux), "Data #2 updated incorrectly [Linux]");
mu_assert(test_read(test_file_windows), "Data #2 updated incorrectly [Windows]");
mu_assert(test_read(test_file_flipper), "Data #2 updated incorrectly [Flipper]");
}
MU_TEST(flipper_format_multikey_test) {
mu_assert(test_write_multikey(TEST_DIR "ff_multiline.test"), "Multikey write test error");
mu_assert(test_read_multikey(TEST_DIR "ff_multiline.test"), "Multikey read test error");
}
MU_TEST(flipper_format_oddities_test) {
mu_assert(
storage_write_string(test_file_oddities, test_data_odd), "Write test error [Oddities]");
mu_assert(test_read(test_file_linux), "Read test error [Oddities]");
}
MU_TEST_SUITE(flipper_format) {
tests_setup();
MU_RUN_TEST(flipper_format_write_test);
MU_RUN_TEST(flipper_format_read_test);
MU_RUN_TEST(flipper_format_delete_test);
MU_RUN_TEST(flipper_format_delete_result_test);
MU_RUN_TEST(flipper_format_append_test);
MU_RUN_TEST(flipper_format_append_result_test);
MU_RUN_TEST(flipper_format_update_1_test);
MU_RUN_TEST(flipper_format_update_1_result_test);
MU_RUN_TEST(flipper_format_update_2_test);
MU_RUN_TEST(flipper_format_update_2_result_test);
MU_RUN_TEST(flipper_format_multikey_test);
MU_RUN_TEST(flipper_format_oddities_test);
tests_teardown();
}
int run_minunit_test_flipper_format(void) {
MU_RUN_SUITE(flipper_format);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_flipper_format)

View File

@@ -0,0 +1,339 @@
#include <furi.h>
#include <flipper_format/flipper_format.h>
#include <flipper_format/flipper_format_i.h>
#include <toolbox/stream/stream.h>
#include <storage/storage.h>
#include "../test.h"
static const char* test_filetype = "Flipper Format test";
static const uint32_t test_version = 666;
static const char* test_string_key = "String data";
static const char* test_string_data = "String";
static const char* test_string_updated_data = "New string";
static const char* test_string_updated_2_data = "And some more";
static const char* test_int_key = "Int32 data";
static const int32_t test_int_data[] = {1234, -6345, 7813, 0};
static const int32_t test_int_updated_data[] = {-1337, 69};
static const int32_t test_int_updated_2_data[] = {-3, -2, -1, 0, 1, 2, 3};
static const char* test_uint_key = "Uint32 data";
static const uint32_t test_uint_data[] = {1234, 0, 5678, 9098, 7654321};
static const uint32_t test_uint_updated_data[] = {8, 800, 555, 35, 35};
static const uint32_t test_uint_updated_2_data[] = {20, 21};
static const char* test_float_key = "Float data";
static const float test_float_data[] = {1.5f, 1000.0f};
static const float test_float_updated_data[] = {1.2f};
static const float test_float_updated_2_data[] = {0.01f, 0.0f, -51.6f};
static const char* test_hex_key = "Hex data";
static const uint8_t test_hex_data[] = {0xDE, 0xAD, 0xBE};
static const uint8_t test_hex_updated_data[] = {0xFE, 0xCA};
static const uint8_t test_hex_updated_2_data[] = {0xCA, 0xCA, 0x05};
static const char* test_hex_new_key = "New Hex data";
static const uint8_t test_hex_new_data[] = {0xFF, 0x6A, 0x91};
static const char* test_data_nix = "Filetype: Flipper Format test\n"
"Version: 666\n"
"# This is comment\n"
"String data: String\n"
"Int32 data: 1234 -6345 7813 0\n"
"Uint32 data: 1234 0 5678 9098 7654321\n"
"Float data: 1.5 1000.0\n"
"Hex data: DE AD BE";
static const char* test_data_win = "Filetype: Flipper Format test\r\n"
"Version: 666\r\n"
"# This is comment\r\n"
"String data: String\r\n"
"Int32 data: 1234 -6345 7813 0\r\n"
"Uint32 data: 1234 0 5678 9098 7654321\r\n"
"Float data: 1.5 1000.0\r\n"
"Hex data: DE AD BE";
#define ARRAY_W_COUNT(x) (x), (COUNT_OF(x))
#define ARRAY_W_BSIZE(x) (x), (sizeof(x))
MU_TEST_1(flipper_format_read_and_update_test, FlipperFormat* flipper_format) {
FuriString* tmpstr;
uint32_t version;
uint32_t uint32_data[COUNT_OF(test_uint_data)];
int32_t int32_data[COUNT_OF(test_int_data)];
float float_data[COUNT_OF(test_float_data)];
uint8_t hex_data[COUNT_OF(test_hex_data)];
uint32_t count;
// key exist test
size_t position_before = stream_tell(flipper_format_get_raw_stream(flipper_format));
mu_check(flipper_format_key_exist(flipper_format, test_hex_key));
mu_assert_int_eq(position_before, stream_tell(flipper_format_get_raw_stream(flipper_format)));
mu_check(!flipper_format_key_exist(flipper_format, "invalid key"));
mu_assert_int_eq(position_before, stream_tell(flipper_format_get_raw_stream(flipper_format)));
// stream seek to end test
mu_check(flipper_format_seek_to_end(flipper_format));
mu_assert_int_eq(
stream_size(flipper_format_get_raw_stream(flipper_format)),
stream_tell(flipper_format_get_raw_stream(flipper_format)));
// key exist test
position_before = stream_tell(flipper_format_get_raw_stream(flipper_format));
mu_check(flipper_format_key_exist(flipper_format, test_hex_key));
mu_assert_int_eq(position_before, stream_tell(flipper_format_get_raw_stream(flipper_format)));
mu_check(!flipper_format_key_exist(flipper_format, "invalid key"));
mu_assert_int_eq(position_before, stream_tell(flipper_format_get_raw_stream(flipper_format)));
// rewind
mu_check(flipper_format_rewind(flipper_format));
// key exist test
position_before = stream_tell(flipper_format_get_raw_stream(flipper_format));
mu_check(flipper_format_key_exist(flipper_format, test_hex_key));
mu_assert_int_eq(position_before, stream_tell(flipper_format_get_raw_stream(flipper_format)));
mu_check(!flipper_format_key_exist(flipper_format, "invalid key"));
mu_assert_int_eq(position_before, stream_tell(flipper_format_get_raw_stream(flipper_format)));
// read test
tmpstr = furi_string_alloc();
mu_check(flipper_format_read_header(flipper_format, tmpstr, &version));
mu_assert_string_eq(test_filetype, furi_string_get_cstr(tmpstr));
mu_assert_int_eq(test_version, version);
mu_check(flipper_format_read_string(flipper_format, test_string_key, tmpstr));
mu_assert_string_eq(test_string_data, furi_string_get_cstr(tmpstr));
mu_check(flipper_format_get_value_count(flipper_format, test_int_key, &count));
mu_assert_int_eq(COUNT_OF(test_int_data), count);
mu_check(flipper_format_read_int32(flipper_format, test_int_key, ARRAY_W_COUNT(int32_data)));
mu_check(memcmp(test_int_data, ARRAY_W_BSIZE(int32_data)) == 0);
mu_check(flipper_format_get_value_count(flipper_format, test_uint_key, &count));
mu_assert_int_eq(COUNT_OF(test_uint_data), count);
mu_check(
flipper_format_read_uint32(flipper_format, test_uint_key, ARRAY_W_COUNT(uint32_data)));
mu_check(memcmp(test_uint_data, ARRAY_W_BSIZE(uint32_data)) == 0);
mu_check(flipper_format_get_value_count(flipper_format, test_float_key, &count));
mu_assert_int_eq(COUNT_OF(test_float_data), count);
mu_check(flipper_format_read_float(flipper_format, test_float_key, ARRAY_W_COUNT(float_data)));
mu_check(memcmp(test_float_data, ARRAY_W_BSIZE(float_data)) == 0);
mu_check(flipper_format_get_value_count(flipper_format, test_hex_key, &count));
mu_assert_int_eq(COUNT_OF(test_hex_data), count);
mu_check(flipper_format_read_hex(flipper_format, test_hex_key, ARRAY_W_COUNT(hex_data)));
mu_check(memcmp(test_hex_data, ARRAY_W_BSIZE(hex_data)) == 0);
mu_check(!flipper_format_read_string(flipper_format, "Key that doesn't exist", tmpstr));
furi_string_free(tmpstr);
// update data
mu_check(flipper_format_rewind(flipper_format));
mu_check(flipper_format_update_string_cstr(
flipper_format, test_string_key, test_string_updated_data));
mu_check(flipper_format_update_int32(
flipper_format, test_int_key, ARRAY_W_COUNT(test_int_updated_data)));
mu_check(flipper_format_update_uint32(
flipper_format, test_uint_key, ARRAY_W_COUNT(test_uint_updated_data)));
mu_check(flipper_format_update_float(
flipper_format, test_float_key, ARRAY_W_COUNT(test_float_updated_data)));
mu_check(flipper_format_update_hex(
flipper_format, test_hex_key, ARRAY_W_COUNT(test_hex_updated_data)));
// read updated data test
uint32_t uint32_updated_data[COUNT_OF(test_uint_updated_data)];
int32_t int32_updated_data[COUNT_OF(test_int_updated_data)];
float float_updated_data[COUNT_OF(test_float_updated_data)];
uint8_t hex_updated_data[COUNT_OF(test_hex_updated_data)];
mu_check(flipper_format_rewind(flipper_format));
tmpstr = furi_string_alloc();
mu_check(flipper_format_read_header(flipper_format, tmpstr, &version));
mu_assert_string_eq(test_filetype, furi_string_get_cstr(tmpstr));
mu_assert_int_eq(test_version, version);
mu_check(flipper_format_read_string(flipper_format, test_string_key, tmpstr));
mu_assert_string_eq(test_string_updated_data, furi_string_get_cstr(tmpstr));
mu_check(flipper_format_get_value_count(flipper_format, test_int_key, &count));
mu_assert_int_eq(COUNT_OF(test_int_updated_data), count);
mu_check(flipper_format_read_int32(
flipper_format, test_int_key, ARRAY_W_COUNT(int32_updated_data)));
mu_check(memcmp(test_int_updated_data, ARRAY_W_BSIZE(int32_updated_data)) == 0);
mu_check(flipper_format_get_value_count(flipper_format, test_uint_key, &count));
mu_assert_int_eq(COUNT_OF(test_uint_updated_data), count);
mu_check(flipper_format_read_uint32(
flipper_format, test_uint_key, ARRAY_W_COUNT(uint32_updated_data)));
mu_check(memcmp(test_uint_updated_data, ARRAY_W_BSIZE(uint32_updated_data)) == 0);
mu_check(flipper_format_get_value_count(flipper_format, test_float_key, &count));
mu_assert_int_eq(COUNT_OF(test_float_updated_data), count);
mu_check(flipper_format_read_float(
flipper_format, test_float_key, ARRAY_W_COUNT(float_updated_data)));
mu_check(memcmp(test_float_updated_data, ARRAY_W_BSIZE(float_updated_data)) == 0);
mu_check(flipper_format_get_value_count(flipper_format, test_hex_key, &count));
mu_assert_int_eq(COUNT_OF(test_hex_updated_data), count);
mu_check(
flipper_format_read_hex(flipper_format, test_hex_key, ARRAY_W_COUNT(hex_updated_data)));
mu_check(memcmp(test_hex_updated_data, ARRAY_W_BSIZE(hex_updated_data)) == 0);
mu_check(!flipper_format_read_string(flipper_format, "Key that doesn't exist", tmpstr));
furi_string_free(tmpstr);
// update data
mu_check(flipper_format_rewind(flipper_format));
mu_check(flipper_format_insert_or_update_string_cstr(
flipper_format, test_string_key, test_string_updated_2_data));
mu_check(flipper_format_insert_or_update_int32(
flipper_format, test_int_key, ARRAY_W_COUNT(test_int_updated_2_data)));
mu_check(flipper_format_insert_or_update_uint32(
flipper_format, test_uint_key, ARRAY_W_COUNT(test_uint_updated_2_data)));
mu_check(flipper_format_insert_or_update_float(
flipper_format, test_float_key, ARRAY_W_COUNT(test_float_updated_2_data)));
mu_check(flipper_format_insert_or_update_hex(
flipper_format, test_hex_key, ARRAY_W_COUNT(test_hex_updated_2_data)));
mu_check(flipper_format_insert_or_update_hex(
flipper_format, test_hex_new_key, ARRAY_W_COUNT(test_hex_new_data)));
uint32_t uint32_updated_2_data[COUNT_OF(test_uint_updated_2_data)];
int32_t int32_updated_2_data[COUNT_OF(test_int_updated_2_data)];
float float_updated_2_data[COUNT_OF(test_float_updated_2_data)];
uint8_t hex_updated_2_data[COUNT_OF(test_hex_updated_2_data)];
uint8_t hex_new_data[COUNT_OF(test_hex_new_data)];
mu_check(flipper_format_rewind(flipper_format));
tmpstr = furi_string_alloc();
mu_check(flipper_format_read_header(flipper_format, tmpstr, &version));
mu_assert_string_eq(test_filetype, furi_string_get_cstr(tmpstr));
mu_assert_int_eq(test_version, version);
mu_check(flipper_format_read_string(flipper_format, test_string_key, tmpstr));
mu_assert_string_eq(test_string_updated_2_data, furi_string_get_cstr(tmpstr));
mu_check(flipper_format_get_value_count(flipper_format, test_int_key, &count));
mu_assert_int_eq(COUNT_OF(test_int_updated_2_data), count);
mu_check(flipper_format_read_int32(
flipper_format, test_int_key, ARRAY_W_COUNT(int32_updated_2_data)));
mu_check(memcmp(test_int_updated_2_data, ARRAY_W_BSIZE(int32_updated_2_data)) == 0);
mu_check(flipper_format_get_value_count(flipper_format, test_uint_key, &count));
mu_assert_int_eq(COUNT_OF(test_uint_updated_2_data), count);
mu_check(flipper_format_read_uint32(
flipper_format, test_uint_key, ARRAY_W_COUNT(uint32_updated_2_data)));
mu_check(memcmp(test_uint_updated_2_data, ARRAY_W_BSIZE(uint32_updated_2_data)) == 0);
mu_check(flipper_format_get_value_count(flipper_format, test_float_key, &count));
mu_assert_int_eq(COUNT_OF(test_float_updated_2_data), count);
mu_check(flipper_format_read_float(
flipper_format, test_float_key, ARRAY_W_COUNT(float_updated_2_data)));
mu_check(memcmp(test_float_updated_2_data, ARRAY_W_BSIZE(float_updated_2_data)) == 0);
mu_check(flipper_format_get_value_count(flipper_format, test_hex_key, &count));
mu_assert_int_eq(COUNT_OF(test_hex_updated_2_data), count);
mu_check(
flipper_format_read_hex(flipper_format, test_hex_key, ARRAY_W_COUNT(hex_updated_2_data)));
mu_check(memcmp(test_hex_updated_2_data, ARRAY_W_BSIZE(hex_updated_2_data)) == 0);
mu_check(flipper_format_get_value_count(flipper_format, test_hex_new_key, &count));
mu_assert_int_eq(COUNT_OF(test_hex_new_data), count);
mu_check(
flipper_format_read_hex(flipper_format, test_hex_new_key, ARRAY_W_COUNT(hex_new_data)));
mu_check(memcmp(test_hex_new_data, ARRAY_W_BSIZE(hex_new_data)) == 0);
mu_check(!flipper_format_read_string(flipper_format, "Key that doesn't exist", tmpstr));
furi_string_free(tmpstr);
// delete key test
mu_check(flipper_format_rewind(flipper_format));
mu_check(flipper_format_delete_key(flipper_format, test_uint_key));
// deleted key read test
mu_check(flipper_format_rewind(flipper_format));
mu_check(!flipper_format_read_uint32(
flipper_format, test_uint_key, ARRAY_W_COUNT(uint32_updated_data)));
}
MU_TEST(flipper_format_string_test) {
FlipperFormat* flipper_format = flipper_format_string_alloc();
Stream* stream = flipper_format_get_raw_stream(flipper_format);
mu_check(flipper_format_write_header_cstr(flipper_format, test_filetype, test_version));
mu_check(flipper_format_write_comment_cstr(flipper_format, "This is comment"));
mu_check(flipper_format_write_string_cstr(flipper_format, test_string_key, test_string_data));
mu_check(
flipper_format_write_int32(flipper_format, test_int_key, ARRAY_W_COUNT(test_int_data)));
mu_check(
flipper_format_write_uint32(flipper_format, test_uint_key, ARRAY_W_COUNT(test_uint_data)));
mu_check(flipper_format_write_float(
flipper_format, test_float_key, ARRAY_W_COUNT(test_float_data)));
mu_check(flipper_format_write_hex(flipper_format, test_hex_key, ARRAY_W_COUNT(test_hex_data)));
MU_RUN_TEST_1(flipper_format_read_and_update_test, flipper_format);
stream_clean(stream);
stream_write_cstring(stream, test_data_nix);
MU_RUN_TEST_1(flipper_format_read_and_update_test, flipper_format);
stream_clean(stream);
stream_write_cstring(stream, test_data_win);
MU_RUN_TEST_1(flipper_format_read_and_update_test, flipper_format);
flipper_format_free(flipper_format);
}
MU_TEST(flipper_format_file_test) {
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* flipper_format = flipper_format_file_alloc(storage);
mu_check(flipper_format_file_open_always(flipper_format, EXT_PATH("flipper.fff")));
Stream* stream = flipper_format_get_raw_stream(flipper_format);
mu_check(flipper_format_write_header_cstr(flipper_format, test_filetype, test_version));
mu_check(flipper_format_write_comment_cstr(flipper_format, "This is comment"));
mu_check(flipper_format_write_string_cstr(flipper_format, test_string_key, test_string_data));
mu_check(
flipper_format_write_int32(flipper_format, test_int_key, ARRAY_W_COUNT(test_int_data)));
mu_check(
flipper_format_write_uint32(flipper_format, test_uint_key, ARRAY_W_COUNT(test_uint_data)));
mu_check(flipper_format_write_float(
flipper_format, test_float_key, ARRAY_W_COUNT(test_float_data)));
mu_check(flipper_format_write_hex(flipper_format, test_hex_key, ARRAY_W_COUNT(test_hex_data)));
MU_RUN_TEST_1(flipper_format_read_and_update_test, flipper_format);
stream_clean(stream);
stream_write_cstring(stream, test_data_nix);
MU_RUN_TEST_1(flipper_format_read_and_update_test, flipper_format);
stream_clean(stream);
stream_write_cstring(stream, test_data_win);
MU_RUN_TEST_1(flipper_format_read_and_update_test, flipper_format);
flipper_format_free(flipper_format);
furi_record_close(RECORD_STORAGE);
}
MU_TEST_SUITE(flipper_format_string_suite) {
MU_RUN_TEST(flipper_format_string_test);
MU_RUN_TEST(flipper_format_file_test);
}
int run_minunit_test_flipper_format_string(void) {
MU_RUN_SUITE(flipper_format_string_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_flipper_format_string)

View File

@@ -0,0 +1,62 @@
#include <float.h>
#include <float_tools.h>
#include "../test.h"
MU_TEST(float_tools_equal_test) {
mu_check(float_is_equal(FLT_MAX, FLT_MAX));
mu_check(float_is_equal(FLT_MIN, FLT_MIN));
mu_check(float_is_equal(-FLT_MAX, -FLT_MAX));
mu_check(float_is_equal(-FLT_MIN, -FLT_MIN));
mu_check(!float_is_equal(FLT_MIN, FLT_MAX));
mu_check(!float_is_equal(-FLT_MIN, FLT_MAX));
mu_check(!float_is_equal(FLT_MIN, -FLT_MAX));
mu_check(!float_is_equal(-FLT_MIN, -FLT_MAX));
const float pi = 3.14159f;
mu_check(float_is_equal(pi, pi));
mu_check(float_is_equal(-pi, -pi));
mu_check(!float_is_equal(pi, -pi));
mu_check(!float_is_equal(-pi, pi));
const float one_third = 1.f / 3.f;
const float one_third_dec = 0.3333333f;
mu_check(one_third != one_third_dec);
mu_check(float_is_equal(one_third, one_third_dec));
const float big_num = 1.e12f;
const float med_num = 95.389f;
const float smol_num = 1.e-12f;
mu_check(float_is_equal(big_num, big_num));
mu_check(float_is_equal(med_num, med_num));
mu_check(float_is_equal(smol_num, smol_num));
mu_check(!float_is_equal(smol_num, big_num));
mu_check(!float_is_equal(med_num, smol_num));
mu_check(!float_is_equal(big_num, med_num));
const float more_than_one = 1.f + FLT_EPSILON;
const float less_than_one = 1.f - FLT_EPSILON;
mu_check(!float_is_equal(more_than_one, less_than_one));
mu_check(!float_is_equal(more_than_one, -less_than_one));
mu_check(!float_is_equal(-more_than_one, less_than_one));
mu_check(!float_is_equal(-more_than_one, -less_than_one));
const float slightly_more_than_one = 1.f + FLT_EPSILON / 2.f;
const float slightly_less_than_one = 1.f - FLT_EPSILON / 2.f;
mu_check(float_is_equal(slightly_more_than_one, slightly_less_than_one));
mu_check(float_is_equal(-slightly_more_than_one, -slightly_less_than_one));
mu_check(!float_is_equal(slightly_more_than_one, -slightly_less_than_one));
mu_check(!float_is_equal(-slightly_more_than_one, slightly_less_than_one));
}
MU_TEST_SUITE(float_tools_suite) {
MU_RUN_TEST(float_tools_equal_test);
}
int run_minunit_test_float_tools(void) {
MU_RUN_SUITE(float_tools_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_float_tools)

View File

@@ -0,0 +1,45 @@
#include <stdio.h>
#include <string.h>
#include <furi.h>
#include "../test.h"
const uint32_t context_value = 0xdeadbeef;
const uint32_t notify_value_0 = 0x12345678;
const uint32_t notify_value_1 = 0x11223344;
uint32_t pubsub_value = 0;
uint32_t pubsub_context_value = 0;
void test_pubsub_handler(const void* arg, void* ctx) {
pubsub_value = *(uint32_t*)arg;
pubsub_context_value = *(uint32_t*)ctx;
}
void test_furi_pubsub(void) {
FuriPubSub* test_pubsub = NULL;
FuriPubSubSubscription* test_pubsub_subscription = NULL;
// init pubsub case
test_pubsub = furi_pubsub_alloc();
mu_assert_pointers_not_eq(test_pubsub, NULL);
// subscribe pubsub case
test_pubsub_subscription =
furi_pubsub_subscribe(test_pubsub, test_pubsub_handler, (void*)&context_value);
mu_assert_pointers_not_eq(test_pubsub_subscription, NULL);
/// notify pubsub case
furi_pubsub_publish(test_pubsub, (void*)&notify_value_0);
mu_assert_int_eq(pubsub_value, notify_value_0);
mu_assert_int_eq(pubsub_context_value, context_value);
// unsubscribe pubsub case
furi_pubsub_unsubscribe(test_pubsub, test_pubsub_subscription);
/// notify unsubscribed pubsub case
furi_pubsub_publish(test_pubsub, (void*)&notify_value_1);
mu_assert_int_not_eq(pubsub_value, notify_value_1);
// delete pubsub case
furi_pubsub_free(test_pubsub);
}

View File

@@ -0,0 +1,31 @@
#include <stdio.h>
#include <string.h>
#include <furi.h>
#include "../test.h"
#define TEST_RECORD_NAME "test/holding"
void test_furi_create_open(void) {
// Test that record does not exist
mu_check(furi_record_exists(TEST_RECORD_NAME) == false);
// Create record
uint8_t test_data = 0;
furi_record_create(TEST_RECORD_NAME, (void*)&test_data);
// Test that record exists
mu_check(furi_record_exists(TEST_RECORD_NAME) == true);
// Open it
void* record = furi_record_open(TEST_RECORD_NAME);
mu_assert_pointers_eq(record, &test_data);
// Close it
furi_record_close(TEST_RECORD_NAME);
// Clean up
furi_record_destroy(TEST_RECORD_NAME);
// Test that record does not exist
mu_check(furi_record_exists(TEST_RECORD_NAME) == false);
}

View File

@@ -0,0 +1,61 @@
#include <stdio.h>
#include <furi.h>
#include <furi_hal.h>
#include "../test.h"
// v2 tests
void test_furi_create_open(void);
void test_furi_concurrent_access(void);
void test_furi_pubsub(void);
void test_furi_memmgr(void);
void test_furi_memmgr_advanced(void);
static int foo = 0;
void test_setup(void) {
foo = 7;
}
void test_teardown(void) {
/* Nothing */
}
MU_TEST(test_check) {
mu_check(foo != 6);
}
// v2 tests
MU_TEST(mu_test_furi_create_open) {
test_furi_create_open();
}
MU_TEST(mu_test_furi_pubsub) {
test_furi_pubsub();
}
MU_TEST(mu_test_furi_memmgr) {
// this test is not accurate, but gives a basic understanding
// that memory management is working fine
test_furi_memmgr();
test_furi_memmgr_advanced();
}
MU_TEST_SUITE(test_suite) {
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
MU_RUN_TEST(test_check);
// v2 tests
MU_RUN_TEST(mu_test_furi_create_open);
MU_RUN_TEST(mu_test_furi_pubsub);
MU_RUN_TEST(mu_test_furi_memmgr);
}
int run_minunit_test_furi(void) {
MU_RUN_SUITE(test_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_furi)

View File

@@ -0,0 +1,236 @@
#include "furi_hal_rtc.h"
#include <stdint.h>
#include <stdio.h>
#include <furi.h>
#include <furi_hal.h>
#include <lp5562_reg.h>
#include "../test.h"
#include <stdlib.h>
#define DATA_SIZE 4
#define EEPROM_ADDRESS 0b10101000
#define EEPROM_ADDRESS_HIGH (EEPROM_ADDRESS | 0b10)
#define EEPROM_SIZE 512
#define EEPROM_PAGE_SIZE 16
#define EEPROM_WRITE_DELAY_MS 6
static void furi_hal_i2c_int_setup(void) {
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
}
static void furi_hal_i2c_int_teardown(void) {
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
static void furi_hal_i2c_ext_setup(void) {
furi_hal_i2c_acquire(&furi_hal_i2c_handle_external);
}
static void furi_hal_i2c_ext_teardown(void) {
furi_hal_i2c_release(&furi_hal_i2c_handle_external);
}
MU_TEST(furi_hal_i2c_int_1b) {
bool ret = false;
uint8_t data_one = 0;
// 1 byte: read, write, read
ret = furi_hal_i2c_read_reg_8(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS,
LP5562_CHANNEL_BLUE_CURRENT_REGISTER,
&data_one,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "0 read_reg_8 failed");
mu_assert(data_one != 0, "0 invalid data");
ret = furi_hal_i2c_write_reg_8(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS,
LP5562_CHANNEL_BLUE_CURRENT_REGISTER,
data_one,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "1 write_reg_8 failed");
ret = furi_hal_i2c_read_reg_8(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS,
LP5562_CHANNEL_BLUE_CURRENT_REGISTER,
&data_one,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "2 read_reg_8 failed");
mu_assert(data_one != 0, "2 invalid data");
}
MU_TEST(furi_hal_i2c_int_3b) {
bool ret = false;
uint8_t data_many[DATA_SIZE] = {0};
// 3 byte: read, write, read
data_many[0] = LP5562_CHANNEL_BLUE_CURRENT_REGISTER;
ret = furi_hal_i2c_tx(
&furi_hal_i2c_handle_power, LP5562_ADDRESS, data_many, 1, LP5562_I2C_TIMEOUT);
mu_assert(ret, "3 tx failed");
ret = furi_hal_i2c_rx(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS,
data_many + 1,
DATA_SIZE - 1,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "4 rx failed");
for(size_t i = 0; i < DATA_SIZE; i++) mu_assert(data_many[i] != 0, "4 invalid data_many");
ret = furi_hal_i2c_tx(
&furi_hal_i2c_handle_power, LP5562_ADDRESS, data_many, DATA_SIZE, LP5562_I2C_TIMEOUT);
mu_assert(ret, "5 tx failed");
ret = furi_hal_i2c_tx(
&furi_hal_i2c_handle_power, LP5562_ADDRESS, data_many, 1, LP5562_I2C_TIMEOUT);
mu_assert(ret, "6 tx failed");
ret = furi_hal_i2c_rx(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS,
data_many + 1,
DATA_SIZE - 1,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "7 rx failed");
for(size_t i = 0; i < DATA_SIZE; i++) mu_assert(data_many[i] != 0, "7 invalid data_many");
}
MU_TEST(furi_hal_i2c_int_1b_fail) {
bool ret = false;
uint8_t data_one = 0;
// 1 byte: fail, read, fail, write, fail, read
data_one = 0;
ret = furi_hal_i2c_read_reg_8(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS + 0x10,
LP5562_CHANNEL_BLUE_CURRENT_REGISTER,
&data_one,
LP5562_I2C_TIMEOUT);
mu_assert(!ret, "8 read_reg_8 failed");
mu_assert(data_one == 0, "8 invalid data");
ret = furi_hal_i2c_read_reg_8(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS,
LP5562_CHANNEL_BLUE_CURRENT_REGISTER,
&data_one,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "9 read_reg_8 failed");
mu_assert(data_one != 0, "9 invalid data");
}
MU_TEST(furi_hal_i2c_int_ext_3b) {
bool ret = false;
uint8_t data_many[DATA_SIZE] = {0};
// 3 byte: read
data_many[0] = LP5562_CHANNEL_BLUE_CURRENT_REGISTER;
ret = furi_hal_i2c_tx_ext(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS,
false,
data_many,
1,
FuriHalI2cBeginStart,
FuriHalI2cEndAwaitRestart,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "3 tx failed");
// Send a RESTART condition, then read the 3 bytes one after the other
ret = furi_hal_i2c_rx_ext(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS,
false,
data_many + 1,
1,
FuriHalI2cBeginRestart,
FuriHalI2cEndPause,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "4 rx failed");
mu_assert(data_many[1] != 0, "4 invalid data");
ret = furi_hal_i2c_rx_ext(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS,
false,
data_many + 2,
1,
FuriHalI2cBeginResume,
FuriHalI2cEndPause,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "5 rx failed");
mu_assert(data_many[2] != 0, "5 invalid data");
ret = furi_hal_i2c_rx_ext(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS,
false,
data_many + 3,
1,
FuriHalI2cBeginResume,
FuriHalI2cEndStop,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "6 rx failed");
mu_assert(data_many[3] != 0, "6 invalid data");
}
MU_TEST(furi_hal_i2c_ext_eeprom) {
if(!furi_hal_i2c_is_device_ready(&furi_hal_i2c_handle_external, EEPROM_ADDRESS, 100)) {
printf("no device connected, skipping\r\n");
return;
}
bool ret = false;
uint8_t buffer[EEPROM_SIZE] = {0};
for(size_t page = 0; page < (EEPROM_SIZE / EEPROM_PAGE_SIZE); ++page) {
// Fill page buffer
for(size_t page_byte = 0; page_byte < EEPROM_PAGE_SIZE; ++page_byte) {
// Each byte is its position in the EEPROM modulo 256
uint8_t byte = ((page * EEPROM_PAGE_SIZE) + page_byte) % 256;
buffer[page_byte] = byte;
}
uint8_t address = (page < 16) ? EEPROM_ADDRESS : EEPROM_ADDRESS_HIGH;
ret = furi_hal_i2c_write_mem(
&furi_hal_i2c_handle_external,
address,
page * EEPROM_PAGE_SIZE,
buffer,
EEPROM_PAGE_SIZE,
20);
mu_assert(ret, "EEPROM write failed");
furi_delay_ms(EEPROM_WRITE_DELAY_MS);
}
ret = furi_hal_i2c_read_mem(
&furi_hal_i2c_handle_external, EEPROM_ADDRESS, 0, buffer, EEPROM_SIZE, 100);
mu_assert(ret, "EEPROM read failed");
for(size_t pos = 0; pos < EEPROM_SIZE; ++pos) {
mu_assert_int_eq(pos % 256, buffer[pos]);
}
}
MU_TEST_SUITE(furi_hal_i2c_int_suite) {
MU_SUITE_CONFIGURE(&furi_hal_i2c_int_setup, &furi_hal_i2c_int_teardown);
MU_RUN_TEST(furi_hal_i2c_int_1b);
MU_RUN_TEST(furi_hal_i2c_int_3b);
MU_RUN_TEST(furi_hal_i2c_int_ext_3b);
MU_RUN_TEST(furi_hal_i2c_int_1b_fail);
}
MU_TEST_SUITE(furi_hal_i2c_ext_suite) {
MU_SUITE_CONFIGURE(&furi_hal_i2c_ext_setup, &furi_hal_i2c_ext_teardown);
MU_RUN_TEST(furi_hal_i2c_ext_eeprom);
}
int run_minunit_test_furi_hal(void) {
MU_RUN_SUITE(furi_hal_i2c_int_suite);
MU_RUN_SUITE(furi_hal_i2c_ext_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_furi_hal)

View File

@@ -0,0 +1,604 @@
#include <stdio.h>
#include <furi.h>
#include <furi_hal.h>
#include "../test.h"
static const uint8_t key_ctr_1[32] = {
0x77, 0x6B, 0xEF, 0xF2, 0x85, 0x1D, 0xB0, 0x6F, 0x4C, 0x8A, 0x05, 0x42, 0xC8, 0x69, 0x6F, 0x6C,
0x6A, 0x81, 0xAF, 0x1E, 0xEC, 0x96, 0xB4, 0xD3, 0x7F, 0xC1, 0xD6, 0x89, 0xE6, 0xC1, 0xC1, 0x04,
};
static const uint8_t iv_ctr_1[16] = {
0x00,
0x00,
0x00,
0x60,
0xDB,
0x56,
0x72,
0xC9,
0x7A,
0xA8,
0xF0,
0xB2,
0x00,
0x00,
0x00,
0x01,
};
static const uint8_t pt_ctr_1[16] = {
0x53,
0x69,
0x6E,
0x67,
0x6C,
0x65,
0x20,
0x62,
0x6C,
0x6F,
0x63,
0x6B,
0x20,
0x6D,
0x73,
0x67,
};
static const uint8_t tv_ctr_ct_1[16] = {
0x14,
0x5A,
0xD0,
0x1D,
0xBF,
0x82,
0x4E,
0xC7,
0x56,
0x08,
0x63,
0xDC,
0x71,
0xE3,
0xE0,
0xC0,
};
static const uint8_t key_ctr_2[32] = {
0x77, 0x6B, 0xEF, 0xF2, 0x85, 0x1D, 0xB0, 0x6F, 0x4C, 0x8A, 0x05, 0x42, 0xC8, 0x69, 0x6F, 0x6C,
0x6A, 0x81, 0xAF, 0x1E, 0xEC, 0x96, 0xB4, 0xD3, 0x7F, 0xC1, 0xD6, 0x89, 0xE6, 0xC1, 0xC1, 0x04,
};
static const uint8_t iv_ctr_2[16] = {
0x00,
0x00,
0x00,
0x60,
0xDB,
0x56,
0x72,
0xC9,
0x7A,
0xA8,
0xF0,
0xB2,
0x00,
0x00,
0x00,
0x01,
};
static const uint8_t pt_ctr_2[0] = {};
//static const uint8_t tv_ctr_ct_2[0] = {};
static const uint8_t key_ctr_3[32] = {
0xF6, 0xD6, 0x6D, 0x6B, 0xD5, 0x2D, 0x59, 0xBB, 0x07, 0x96, 0x36, 0x58, 0x79, 0xEF, 0xF8, 0x86,
0xC6, 0x6D, 0xD5, 0x1A, 0x5B, 0x6A, 0x99, 0x74, 0x4B, 0x50, 0x59, 0x0C, 0x87, 0xA2, 0x38, 0x84,
};
static const uint8_t iv_ctr_3[16] = {
0x00,
0xFA,
0xAC,
0x24,
0xC1,
0x58,
0x5E,
0xF1,
0x5A,
0x43,
0xD8,
0x75,
0x00,
0x00,
0x00,
0x01,
};
static const uint8_t pt_ctr_3[32] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
};
static const uint8_t tv_ctr_ct_3[32] = {
0xF0, 0x5E, 0x23, 0x1B, 0x38, 0x94, 0x61, 0x2C, 0x49, 0xEE, 0x00, 0x0B, 0x80, 0x4E, 0xB2, 0xA9,
0xB8, 0x30, 0x6B, 0x50, 0x8F, 0x83, 0x9D, 0x6A, 0x55, 0x30, 0x83, 0x1D, 0x93, 0x44, 0xAF, 0x1C,
};
static const uint8_t key_ctr_4[32] = {
0xFF, 0x7A, 0x61, 0x7C, 0xE6, 0x91, 0x48, 0xE4, 0xF1, 0x72, 0x6E, 0x2F, 0x43, 0x58, 0x1D, 0xE2,
0xAA, 0x62, 0xD9, 0xF8, 0x05, 0x53, 0x2E, 0xDF, 0xF1, 0xEE, 0xD6, 0x87, 0xFB, 0x54, 0x15, 0x3D,
};
static const uint8_t iv_ctr_4[16] = {
0x00,
0x1C,
0xC5,
0xB7,
0x51,
0xA5,
0x1D,
0x70,
0xA1,
0xC1,
0x11,
0x48,
0x00,
0x00,
0x00,
0x01,
};
static const uint8_t pt_ctr_4[36] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23,
};
static const uint8_t tv_ctr_ct_4[36] = {
0xEB, 0x6C, 0x52, 0x82, 0x1D, 0x0B, 0xBB, 0xF7, 0xCE, 0x75, 0x94, 0x46,
0x2A, 0xCA, 0x4F, 0xAA, 0xB4, 0x07, 0xDF, 0x86, 0x65, 0x69, 0xFD, 0x07,
0xF4, 0x8C, 0xC0, 0xB5, 0x83, 0xD6, 0x07, 0x1F, 0x1E, 0xC0, 0xE6, 0xB8,
};
static const uint8_t key_ctr_5[32] = {
0xFF, 0x7A, 0x61, 0x7C, 0xE6, 0x91, 0x48, 0xE4, 0xF1, 0x72, 0x6E, 0x2F, 0x43, 0x58, 0x1D, 0xE2,
0xAA, 0x62, 0xD9, 0xF8, 0x05, 0x53, 0x2E, 0xDF, 0xF1, 0xEE, 0xD6, 0x87, 0xFB, 0x54, 0x15, 0x3D,
};
static const uint8_t iv_ctr_5[16] = {
0x00,
0x1C,
0xC5,
0xB7,
0x51,
0xA5,
0x1D,
0x70,
0xA1,
0xC1,
0x11,
0x48,
0x00,
0x00,
0x00,
0x01,
};
static const uint8_t pt_ctr_5[0] = {};
//static const uint8_t tv_ctr_ct_5[0] = {};
static const uint8_t key_gcm_1[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const uint8_t iv_gcm_1[16] = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
static const uint8_t pt_gcm_1[0] = {};
//static const uint8_t tv_gcm_ct_1[0] = {};
static const uint8_t aad_gcm_1[0] = {};
static const uint8_t tv_gcm_tag_1[16] = {
0x53,
0x0F,
0x8A,
0xFB,
0xC7,
0x45,
0x36,
0xB9,
0xA9,
0x63,
0xB4,
0xF1,
0xC4,
0xCB,
0x73,
0x8B,
};
static const uint8_t key_gcm_2[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const uint8_t iv_gcm_2[16] = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
static const uint8_t pt_gcm_2[16] = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
static const uint8_t tv_gcm_ct_2[16] = {
0xCE,
0xA7,
0x40,
0x3D,
0x4D,
0x60,
0x6B,
0x6E,
0x07,
0x4E,
0xC5,
0xD3,
0xBA,
0xF3,
0x9D,
0x18,
};
static const uint8_t aad_gcm_2[0] = {};
static const uint8_t tv_gcm_tag_2[16] = {
0xD0,
0xD1,
0xC8,
0xA7,
0x99,
0x99,
0x6B,
0xF0,
0x26,
0x5B,
0x98,
0xB5,
0xD4,
0x8A,
0xB9,
0x19,
};
static const uint8_t key_gcm_3[32] = {
0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08,
0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08,
};
static const uint8_t iv_gcm_3[16] = {
0xCA,
0xFE,
0xBA,
0xBE,
0xFA,
0xCE,
0xDB,
0xAD,
0xDE,
0xCA,
0xF8,
0x88,
0x00,
0x00,
0x00,
0x00,
};
static const uint8_t pt_gcm_3[64] = {
0xD9, 0x31, 0x32, 0x25, 0xF8, 0x84, 0x06, 0xE5, 0xA5, 0x59, 0x09, 0xC5, 0xAF, 0xF5, 0x26, 0x9A,
0x86, 0xA7, 0xA9, 0x53, 0x15, 0x34, 0xF7, 0xDA, 0x2E, 0x4C, 0x30, 0x3D, 0x8A, 0x31, 0x8A, 0x72,
0x1C, 0x3C, 0x0C, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2F, 0xCF, 0x0E, 0x24, 0x49, 0xA6, 0xB5, 0x25,
0xB1, 0x6A, 0xED, 0xF5, 0xAA, 0x0D, 0xE6, 0x57, 0xBA, 0x63, 0x7B, 0x39, 0x1A, 0xAF, 0xD2, 0x55,
};
static const uint8_t tv_gcm_ct_3[64] = {
0x52, 0x2D, 0xC1, 0xF0, 0x99, 0x56, 0x7D, 0x07, 0xF4, 0x7F, 0x37, 0xA3, 0x2A, 0x84, 0x42, 0x7D,
0x64, 0x3A, 0x8C, 0xDC, 0xBF, 0xE5, 0xC0, 0xC9, 0x75, 0x98, 0xA2, 0xBD, 0x25, 0x55, 0xD1, 0xAA,
0x8C, 0xB0, 0x8E, 0x48, 0x59, 0x0D, 0xBB, 0x3D, 0xA7, 0xB0, 0x8B, 0x10, 0x56, 0x82, 0x88, 0x38,
0xC5, 0xF6, 0x1E, 0x63, 0x93, 0xBA, 0x7A, 0x0A, 0xBC, 0xC9, 0xF6, 0x62, 0x89, 0x80, 0x15, 0xAD,
};
static const uint8_t aad_gcm_3[0] = {};
static const uint8_t tv_gcm_tag_3[16] = {
0xB0,
0x94,
0xDA,
0xC5,
0xD9,
0x34,
0x71,
0xBD,
0xEC,
0x1A,
0x50,
0x22,
0x70,
0xE3,
0xCC,
0x6C,
};
static const uint8_t key_gcm_4[32] = {
0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08,
0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08,
};
static const uint8_t iv_gcm_4[16] = {
0xCA,
0xFE,
0xBA,
0xBE,
0xFA,
0xCE,
0xDB,
0xAD,
0xDE,
0xCA,
0xF8,
0x88,
0x00,
0x00,
0x00,
0x00,
};
static const uint8_t pt_gcm_4[60] = {
0xD9, 0x31, 0x32, 0x25, 0xF8, 0x84, 0x06, 0xE5, 0xA5, 0x59, 0x09, 0xC5, 0xAF, 0xF5, 0x26,
0x9A, 0x86, 0xA7, 0xA9, 0x53, 0x15, 0x34, 0xF7, 0xDA, 0x2E, 0x4C, 0x30, 0x3D, 0x8A, 0x31,
0x8A, 0x72, 0x1C, 0x3C, 0x0C, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2F, 0xCF, 0x0E, 0x24, 0x49,
0xA6, 0xB5, 0x25, 0xB1, 0x6A, 0xED, 0xF5, 0xAA, 0x0D, 0xE6, 0x57, 0xBA, 0x63, 0x7B, 0x39,
};
static const uint8_t tv_gcm_ct_4[60] = {
0x52, 0x2D, 0xC1, 0xF0, 0x99, 0x56, 0x7D, 0x07, 0xF4, 0x7F, 0x37, 0xA3, 0x2A, 0x84, 0x42,
0x7D, 0x64, 0x3A, 0x8C, 0xDC, 0xBF, 0xE5, 0xC0, 0xC9, 0x75, 0x98, 0xA2, 0xBD, 0x25, 0x55,
0xD1, 0xAA, 0x8C, 0xB0, 0x8E, 0x48, 0x59, 0x0D, 0xBB, 0x3D, 0xA7, 0xB0, 0x8B, 0x10, 0x56,
0x82, 0x88, 0x38, 0xC5, 0xF6, 0x1E, 0x63, 0x93, 0xBA, 0x7A, 0x0A, 0xBC, 0xC9, 0xF6, 0x62,
};
static const uint8_t aad_gcm_4[20] = {
0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED,
0xFA, 0xCE, 0xDE, 0xAD, 0xBE, 0xEF, 0xAB, 0xAD, 0xDA, 0xD2,
};
static const uint8_t tv_gcm_tag_4[16] = {
0x76,
0xFC,
0x6E,
0xCE,
0x0F,
0x4E,
0x17,
0x68,
0xCD,
0xDF,
0x88,
0x53,
0xBB,
0x2D,
0x55,
0x1B,
};
static void furi_hal_crypto_ctr_setup(void) {
}
static void furi_hal_crypto_ctr_teardown(void) {
}
static void furi_hal_crypto_gcm_setup(void) {
}
static void furi_hal_crypto_gcm_teardown(void) {
}
MU_TEST(furi_hal_crypto_ctr_1) {
bool ret = false;
uint8_t ct[sizeof(pt_ctr_1)];
ret = furi_hal_crypto_ctr(key_ctr_1, iv_ctr_1, pt_ctr_1, ct, sizeof(pt_ctr_1));
mu_assert(ret, "CTR 1 failed");
mu_assert_mem_eq(tv_ctr_ct_1, ct, sizeof(pt_ctr_1));
}
MU_TEST(furi_hal_crypto_ctr_2) {
bool ret = false;
uint8_t ct[sizeof(pt_ctr_2)];
ret = furi_hal_crypto_ctr(key_ctr_2, iv_ctr_2, pt_ctr_2, ct, sizeof(pt_ctr_2));
mu_assert(ret, "CTR 2 failed");
//mu_assert_mem_eq(tv_ctr_ct_2, ct, sizeof(pt_ctr_2));
}
MU_TEST(furi_hal_crypto_ctr_3) {
bool ret = false;
uint8_t ct[sizeof(pt_ctr_3)];
ret = furi_hal_crypto_ctr(key_ctr_3, iv_ctr_3, pt_ctr_3, ct, sizeof(pt_ctr_3));
mu_assert(ret, "CTR 3 failed");
mu_assert_mem_eq(tv_ctr_ct_3, ct, sizeof(pt_ctr_3));
}
MU_TEST(furi_hal_crypto_ctr_4) {
bool ret = false;
uint8_t ct[sizeof(pt_ctr_4)];
ret = furi_hal_crypto_ctr(key_ctr_4, iv_ctr_4, pt_ctr_4, ct, sizeof(pt_ctr_4));
mu_assert(ret, "CTR 4 failed");
mu_assert_mem_eq(tv_ctr_ct_4, ct, sizeof(pt_ctr_4));
}
MU_TEST(furi_hal_crypto_ctr_5) {
bool ret = false;
uint8_t ct[sizeof(pt_ctr_5)];
ret = furi_hal_crypto_ctr(key_ctr_5, iv_ctr_5, pt_ctr_5, ct, sizeof(pt_ctr_5));
mu_assert(ret, "CTR 5 failed");
//mu_assert_mem_eq(tv_ctr_ct_5, ct, sizeof(pt_ctr_5));
}
MU_TEST(furi_hal_crypto_gcm_1) {
bool ret = false;
uint8_t pt[sizeof(pt_gcm_1)];
uint8_t ct[sizeof(pt_gcm_1)];
uint8_t tag_enc[16];
uint8_t tag_dec[16];
ret = furi_hal_crypto_gcm(
key_gcm_1,
iv_gcm_1,
aad_gcm_1,
sizeof(aad_gcm_1),
pt_gcm_1,
ct,
sizeof(pt_gcm_1),
tag_enc,
false);
mu_assert(ret, "GCM 1 encryption failed");
//mu_assert_mem_eq(tv_gcm_ct_1, ct, sizeof(pt_gcm_1));
mu_assert_mem_eq(tv_gcm_tag_1, tag_enc, 16);
ret = furi_hal_crypto_gcm(
key_gcm_1, iv_gcm_1, aad_gcm_1, sizeof(aad_gcm_1), ct, pt, sizeof(pt_gcm_1), tag_dec, true);
mu_assert(ret, "GCM 1 decryption failed");
//mu_assert_mem_eq(pt_gcm_1, pt, sizeof(pt_gcm_1));
mu_assert_mem_eq(tv_gcm_tag_1, tag_dec, 16);
}
MU_TEST(furi_hal_crypto_gcm_2) {
bool ret = false;
uint8_t pt[sizeof(pt_gcm_2)];
uint8_t ct[sizeof(pt_gcm_2)];
uint8_t tag_enc[16];
uint8_t tag_dec[16];
ret = furi_hal_crypto_gcm(
key_gcm_2,
iv_gcm_2,
aad_gcm_2,
sizeof(aad_gcm_2),
pt_gcm_2,
ct,
sizeof(pt_gcm_2),
tag_enc,
false);
mu_assert(ret, "GCM 2 encryption failed");
mu_assert_mem_eq(tv_gcm_ct_2, ct, sizeof(pt_gcm_2));
mu_assert_mem_eq(tv_gcm_tag_2, tag_enc, 16);
ret = furi_hal_crypto_gcm(
key_gcm_2, iv_gcm_2, aad_gcm_2, sizeof(aad_gcm_2), ct, pt, sizeof(pt_gcm_2), tag_dec, true);
mu_assert(ret, "GCM 2 decryption failed");
mu_assert_mem_eq(pt_gcm_2, pt, sizeof(pt_gcm_2));
mu_assert_mem_eq(tv_gcm_tag_2, tag_dec, 16);
}
MU_TEST(furi_hal_crypto_gcm_3) {
bool ret = false;
uint8_t pt[sizeof(pt_gcm_3)];
uint8_t ct[sizeof(pt_gcm_3)];
uint8_t tag_enc[16];
uint8_t tag_dec[16];
ret = furi_hal_crypto_gcm(
key_gcm_3,
iv_gcm_3,
aad_gcm_3,
sizeof(aad_gcm_3),
pt_gcm_3,
ct,
sizeof(pt_gcm_3),
tag_enc,
false);
mu_assert(ret, "GCM 3 encryption failed");
mu_assert_mem_eq(tv_gcm_ct_3, ct, sizeof(pt_gcm_3));
mu_assert_mem_eq(tv_gcm_tag_3, tag_enc, 16);
ret = furi_hal_crypto_gcm(
key_gcm_3, iv_gcm_3, aad_gcm_3, sizeof(aad_gcm_3), ct, pt, sizeof(pt_gcm_3), tag_dec, true);
mu_assert(ret, "GCM 3 decryption failed");
mu_assert_mem_eq(pt_gcm_3, pt, sizeof(pt_gcm_3));
mu_assert_mem_eq(tv_gcm_tag_3, tag_dec, 16);
}
MU_TEST(furi_hal_crypto_gcm_4) {
bool ret = false;
uint8_t pt[sizeof(pt_gcm_4)];
uint8_t ct[sizeof(pt_gcm_4)];
uint8_t tag_enc[16];
uint8_t tag_dec[16];
ret = furi_hal_crypto_gcm(
key_gcm_4,
iv_gcm_4,
aad_gcm_4,
sizeof(aad_gcm_4),
pt_gcm_4,
ct,
sizeof(pt_gcm_4),
tag_enc,
false);
mu_assert(ret, "GCM 4 encryption failed");
mu_assert_mem_eq(tv_gcm_ct_4, ct, sizeof(pt_gcm_4));
mu_assert_mem_eq(tv_gcm_tag_4, tag_enc, 16);
ret = furi_hal_crypto_gcm(
key_gcm_4, iv_gcm_4, aad_gcm_4, sizeof(aad_gcm_4), ct, pt, sizeof(pt_gcm_4), tag_dec, true);
mu_assert(ret, "GCM 4 decryption failed");
mu_assert_mem_eq(pt_gcm_4, pt, sizeof(pt_gcm_4));
mu_assert_mem_eq(tv_gcm_tag_4, tag_dec, 16);
}
MU_TEST_SUITE(furi_hal_crypto_ctr_test) {
MU_SUITE_CONFIGURE(&furi_hal_crypto_ctr_setup, &furi_hal_crypto_ctr_teardown);
MU_RUN_TEST(furi_hal_crypto_ctr_1);
MU_RUN_TEST(furi_hal_crypto_ctr_2);
MU_RUN_TEST(furi_hal_crypto_ctr_3);
MU_RUN_TEST(furi_hal_crypto_ctr_4);
MU_RUN_TEST(furi_hal_crypto_ctr_5);
}
MU_TEST_SUITE(furi_hal_crypto_gcm_test) {
MU_SUITE_CONFIGURE(&furi_hal_crypto_gcm_setup, &furi_hal_crypto_gcm_teardown);
MU_RUN_TEST(furi_hal_crypto_gcm_1);
MU_RUN_TEST(furi_hal_crypto_gcm_2);
MU_RUN_TEST(furi_hal_crypto_gcm_3);
MU_RUN_TEST(furi_hal_crypto_gcm_4);
}
int run_minunit_test_furi_hal_crypto(void) {
MU_RUN_SUITE(furi_hal_crypto_ctr_test);
MU_RUN_SUITE(furi_hal_crypto_gcm_test);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_furi_hal_crypto)

View File

@@ -0,0 +1,471 @@
#include <furi.h>
#include "../test.h"
static void test_setup(void) {
}
static void test_teardown(void) {
}
static FuriString* furi_string_alloc_vprintf_test(const char format[], ...) {
va_list args;
va_start(args, format);
FuriString* string = furi_string_alloc_vprintf(format, args);
va_end(args);
return string;
}
MU_TEST(mu_test_furi_string_alloc_free) {
FuriString* tmp;
FuriString* string;
// test alloc and free
string = furi_string_alloc();
mu_check(string != NULL);
mu_check(furi_string_empty(string));
furi_string_free(string);
// test furi_string_alloc_set_str and free
string = furi_string_alloc_set_str("test");
mu_check(string != NULL);
mu_check(!furi_string_empty(string));
mu_check(furi_string_cmp(string, "test") == 0);
furi_string_free(string);
// test furi_string_alloc_set and free
tmp = furi_string_alloc_set("more");
string = furi_string_alloc_set(tmp);
furi_string_free(tmp);
mu_check(string != NULL);
mu_check(!furi_string_empty(string));
mu_check(furi_string_cmp(string, "more") == 0);
furi_string_free(string);
// test alloc_printf and free
string = furi_string_alloc_printf("test %d %s %c 0x%02x", 1, "two", '3', 0x04);
mu_check(string != NULL);
mu_check(!furi_string_empty(string));
mu_check(furi_string_cmp(string, "test 1 two 3 0x04") == 0);
furi_string_free(string);
// test alloc_vprintf and free
string = furi_string_alloc_vprintf_test("test %d %s %c 0x%02x", 4, "five", '6', 0x07);
mu_check(string != NULL);
mu_check(!furi_string_empty(string));
mu_check(furi_string_cmp(string, "test 4 five 6 0x07") == 0);
furi_string_free(string);
// test alloc_move and free
tmp = furi_string_alloc_set("move");
string = furi_string_alloc_move(tmp);
mu_check(string != NULL);
mu_check(!furi_string_empty(string));
mu_check(furi_string_cmp(string, "move") == 0);
furi_string_free(string);
}
MU_TEST(mu_test_furi_string_mem) {
FuriString* string = furi_string_alloc_set("test");
mu_check(string != NULL);
mu_check(!furi_string_empty(string));
// TODO FL-3493: how to test furi_string_reserve?
// test furi_string_reset
furi_string_reset(string);
mu_check(furi_string_empty(string));
// test furi_string_swap
furi_string_set(string, "test");
FuriString* swap_string = furi_string_alloc_set("swap");
furi_string_swap(string, swap_string);
mu_check(furi_string_cmp(string, "swap") == 0);
mu_check(furi_string_cmp(swap_string, "test") == 0);
furi_string_free(swap_string);
// test furi_string_move
FuriString* move_string = furi_string_alloc_set("move");
furi_string_move(string, move_string);
mu_check(furi_string_cmp(string, "move") == 0);
// move_string is now empty
// and tested by leaked memory check at the end of the tests
furi_string_set(string, "abracadabra");
// test furi_string_hash
mu_assert_int_eq(0xc3bc16d7, furi_string_hash(string));
// test furi_string_size
mu_assert_int_eq(11, furi_string_size(string));
// test furi_string_empty
mu_check(!furi_string_empty(string));
furi_string_reset(string);
mu_check(furi_string_empty(string));
furi_string_free(string);
}
MU_TEST(mu_test_furi_string_getters) {
FuriString* string = furi_string_alloc_set("test");
// test furi_string_get_char
mu_check(furi_string_get_char(string, 0) == 't');
mu_check(furi_string_get_char(string, 1) == 'e');
mu_check(furi_string_get_char(string, 2) == 's');
mu_check(furi_string_get_char(string, 3) == 't');
// test furi_string_get_cstr
mu_assert_string_eq("test", furi_string_get_cstr(string));
furi_string_free(string);
}
static FuriString* furi_string_vprintf_test(FuriString* string, const char format[], ...) {
va_list args;
va_start(args, format);
furi_string_vprintf(string, format, args);
va_end(args);
return string;
}
MU_TEST(mu_test_furi_string_setters) {
FuriString* tmp;
FuriString* string = furi_string_alloc();
// test furi_string_set_str
furi_string_set_str(string, "test");
mu_assert_string_eq("test", furi_string_get_cstr(string));
// test furi_string_set
tmp = furi_string_alloc_set("more");
furi_string_set(string, tmp);
furi_string_free(tmp);
mu_assert_string_eq("more", furi_string_get_cstr(string));
// test furi_string_set_strn
furi_string_set_strn(string, "test", 2);
mu_assert_string_eq("te", furi_string_get_cstr(string));
// test furi_string_set_char
furi_string_set_char(string, 0, 'a');
furi_string_set_char(string, 1, 'b');
mu_assert_string_eq("ab", furi_string_get_cstr(string));
// test furi_string_set_n
tmp = furi_string_alloc_set("dodecahedron");
furi_string_set_n(string, tmp, 4, 5);
furi_string_free(tmp);
mu_assert_string_eq("cahed", furi_string_get_cstr(string));
// test furi_string_printf
furi_string_printf(string, "test %d %s %c 0x%02x", 1, "two", '3', 0x04);
mu_assert_string_eq("test 1 two 3 0x04", furi_string_get_cstr(string));
// test furi_string_vprintf
furi_string_vprintf_test(string, "test %d %s %c 0x%02x", 4, "five", '6', 0x07);
mu_assert_string_eq("test 4 five 6 0x07", furi_string_get_cstr(string));
furi_string_free(string);
}
static FuriString* furi_string_cat_vprintf_test(FuriString* string, const char format[], ...) {
va_list args;
va_start(args, format);
furi_string_cat_vprintf(string, format, args);
va_end(args);
return string;
}
MU_TEST(mu_test_furi_string_appends) {
FuriString* tmp;
FuriString* string = furi_string_alloc();
// test furi_string_push_back
furi_string_push_back(string, 't');
furi_string_push_back(string, 'e');
furi_string_push_back(string, 's');
furi_string_push_back(string, 't');
mu_assert_string_eq("test", furi_string_get_cstr(string));
furi_string_push_back(string, '!');
mu_assert_string_eq("test!", furi_string_get_cstr(string));
// test furi_string_cat_str
furi_string_cat_str(string, "test");
mu_assert_string_eq("test!test", furi_string_get_cstr(string));
// test furi_string_cat
tmp = furi_string_alloc_set("more");
furi_string_cat(string, tmp);
furi_string_free(tmp);
mu_assert_string_eq("test!testmore", furi_string_get_cstr(string));
// test furi_string_cat_printf
furi_string_cat_printf(string, "test %d %s %c 0x%02x", 1, "two", '3', 0x04);
mu_assert_string_eq("test!testmoretest 1 two 3 0x04", furi_string_get_cstr(string));
// test furi_string_cat_vprintf
furi_string_cat_vprintf_test(string, "test %d %s %c 0x%02x", 4, "five", '6', 0x07);
mu_assert_string_eq(
"test!testmoretest 1 two 3 0x04test 4 five 6 0x07", furi_string_get_cstr(string));
furi_string_free(string);
}
MU_TEST(mu_test_furi_string_compare) {
FuriString* string_1 = furi_string_alloc_set("string_1");
FuriString* string_2 = furi_string_alloc_set("string_2");
// test furi_string_cmp
mu_assert_int_eq(0, furi_string_cmp(string_1, string_1));
mu_assert_int_eq(0, furi_string_cmp(string_2, string_2));
mu_assert_int_eq(-1, furi_string_cmp(string_1, string_2));
mu_assert_int_eq(1, furi_string_cmp(string_2, string_1));
// test furi_string_cmp_str
mu_assert_int_eq(0, furi_string_cmp_str(string_1, "string_1"));
mu_assert_int_eq(0, furi_string_cmp_str(string_2, "string_2"));
mu_assert_int_eq(-1, furi_string_cmp_str(string_1, "string_2"));
mu_assert_int_eq(1, furi_string_cmp_str(string_2, "string_1"));
// test furi_string_cmpi
furi_string_set(string_1, "string");
furi_string_set(string_2, "StrIng");
mu_assert_int_eq(0, furi_string_cmpi(string_1, string_1));
mu_assert_int_eq(0, furi_string_cmpi(string_2, string_2));
mu_assert_int_eq(0, furi_string_cmpi(string_1, string_2));
mu_assert_int_eq(0, furi_string_cmpi(string_2, string_1));
furi_string_set(string_1, "string_1");
furi_string_set(string_2, "StrIng_2");
mu_assert_int_eq(32, furi_string_cmp(string_1, string_2));
mu_assert_int_eq(-32, furi_string_cmp(string_2, string_1));
mu_assert_int_eq(-1, furi_string_cmpi(string_1, string_2));
mu_assert_int_eq(1, furi_string_cmpi(string_2, string_1));
// test furi_string_cmpi_str
furi_string_set(string_1, "string");
mu_assert_int_eq(0, furi_string_cmp_str(string_1, "string"));
mu_assert_int_eq(32, furi_string_cmp_str(string_1, "String"));
mu_assert_int_eq(32, furi_string_cmp_str(string_1, "STring"));
mu_assert_int_eq(32, furi_string_cmp_str(string_1, "STRing"));
mu_assert_int_eq(32, furi_string_cmp_str(string_1, "STRIng"));
mu_assert_int_eq(32, furi_string_cmp_str(string_1, "STRINg"));
mu_assert_int_eq(32, furi_string_cmp_str(string_1, "STRING"));
mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "string"));
mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "String"));
mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "STring"));
mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "STRing"));
mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "STRIng"));
mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "STRINg"));
mu_assert_int_eq(0, furi_string_cmpi_str(string_1, "STRING"));
furi_string_free(string_1);
furi_string_free(string_2);
}
MU_TEST(mu_test_furi_string_search) {
// 012345678901234567
FuriString* haystack = furi_string_alloc_set("test321test123test");
FuriString* needle = furi_string_alloc_set("test");
// test furi_string_search
mu_assert_int_eq(0, furi_string_search(haystack, needle));
mu_assert_int_eq(7, furi_string_search(haystack, needle, 1));
mu_assert_int_eq(14, furi_string_search(haystack, needle, 8));
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search(haystack, needle, 15));
FuriString* tmp = furi_string_alloc_set("testnone");
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search(haystack, tmp));
furi_string_free(tmp);
// test furi_string_search_str
mu_assert_int_eq(0, furi_string_search_str(haystack, "test"));
mu_assert_int_eq(7, furi_string_search_str(haystack, "test", 1));
mu_assert_int_eq(14, furi_string_search_str(haystack, "test", 8));
mu_assert_int_eq(4, furi_string_search_str(haystack, "321"));
mu_assert_int_eq(11, furi_string_search_str(haystack, "123"));
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search_str(haystack, "testnone"));
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search_str(haystack, "test", 15));
// test furi_string_search_char
mu_assert_int_eq(0, furi_string_search_char(haystack, 't'));
mu_assert_int_eq(1, furi_string_search_char(haystack, 'e'));
mu_assert_int_eq(2, furi_string_search_char(haystack, 's'));
mu_assert_int_eq(3, furi_string_search_char(haystack, 't', 1));
mu_assert_int_eq(7, furi_string_search_char(haystack, 't', 4));
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search_char(haystack, 'x'));
// test furi_string_search_rchar
mu_assert_int_eq(17, furi_string_search_rchar(haystack, 't'));
mu_assert_int_eq(15, furi_string_search_rchar(haystack, 'e'));
mu_assert_int_eq(16, furi_string_search_rchar(haystack, 's'));
mu_assert_int_eq(13, furi_string_search_rchar(haystack, '3'));
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search_rchar(haystack, '3', 14));
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_search_rchar(haystack, 'x'));
furi_string_free(haystack);
furi_string_free(needle);
}
MU_TEST(mu_test_furi_string_equality) {
FuriString* string = furi_string_alloc_set("test");
FuriString* string_eq = furi_string_alloc_set("test");
FuriString* string_neq = furi_string_alloc_set("test2");
// test furi_string_equal
mu_check(furi_string_equal(string, string_eq));
mu_check(!furi_string_equal(string, string_neq));
// test furi_string_equal_str
mu_check(furi_string_equal_str(string, "test"));
mu_check(!furi_string_equal_str(string, "test2"));
mu_check(furi_string_equal_str(string_neq, "test2"));
mu_check(!furi_string_equal_str(string_neq, "test"));
furi_string_free(string);
furi_string_free(string_eq);
furi_string_free(string_neq);
}
MU_TEST(mu_test_furi_string_replace) {
FuriString* needle = furi_string_alloc_set("test");
FuriString* replace = furi_string_alloc_set("replace");
FuriString* string = furi_string_alloc_set("test123test");
// test furi_string_replace_at
furi_string_replace_at(string, 4, 3, "!biglongword!");
mu_assert_string_eq("test!biglongword!test", furi_string_get_cstr(string));
// test furi_string_replace
mu_assert_int_eq(17, furi_string_replace(string, needle, replace, 1));
mu_assert_string_eq("test!biglongword!replace", furi_string_get_cstr(string));
mu_assert_int_eq(0, furi_string_replace(string, needle, replace));
mu_assert_string_eq("replace!biglongword!replace", furi_string_get_cstr(string));
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_replace(string, needle, replace));
mu_assert_string_eq("replace!biglongword!replace", furi_string_get_cstr(string));
// test furi_string_replace_str
mu_assert_int_eq(20, furi_string_replace_str(string, "replace", "test", 1));
mu_assert_string_eq("replace!biglongword!test", furi_string_get_cstr(string));
mu_assert_int_eq(0, furi_string_replace_str(string, "replace", "test"));
mu_assert_string_eq("test!biglongword!test", furi_string_get_cstr(string));
mu_assert_int_eq(FURI_STRING_FAILURE, furi_string_replace_str(string, "replace", "test"));
mu_assert_string_eq("test!biglongword!test", furi_string_get_cstr(string));
// test furi_string_replace_all
furi_string_replace_all(string, needle, replace);
mu_assert_string_eq("replace!biglongword!replace", furi_string_get_cstr(string));
// test furi_string_replace_all_str
furi_string_replace_all_str(string, "replace", "test");
mu_assert_string_eq("test!biglongword!test", furi_string_get_cstr(string));
furi_string_free(string);
furi_string_free(needle);
furi_string_free(replace);
}
MU_TEST(mu_test_furi_string_start_end) {
FuriString* string = furi_string_alloc_set("start_end");
FuriString* start = furi_string_alloc_set("start");
FuriString* end = furi_string_alloc_set("end");
// test furi_string_start_with
mu_check(furi_string_start_with(string, start));
mu_check(!furi_string_start_with(string, end));
// test furi_string_start_with_str
mu_check(furi_string_start_with_str(string, "start"));
mu_check(!furi_string_start_with_str(string, "end"));
// test furi_string_end_with
mu_check(furi_string_end_with(string, end));
mu_check(!furi_string_end_with(string, start));
// test furi_string_end_with_str
mu_check(furi_string_end_with_str(string, "end"));
mu_check(!furi_string_end_with_str(string, "start"));
furi_string_free(string);
furi_string_free(start);
furi_string_free(end);
}
MU_TEST(mu_test_furi_string_trim) {
FuriString* string = furi_string_alloc_set("biglongstring");
// test furi_string_left
furi_string_left(string, 7);
mu_assert_string_eq("biglong", furi_string_get_cstr(string));
// test furi_string_right
furi_string_right(string, 3);
mu_assert_string_eq("long", furi_string_get_cstr(string));
// test furi_string_mid
furi_string_mid(string, 1, 2);
mu_assert_string_eq("on", furi_string_get_cstr(string));
// test furi_string_trim
furi_string_set(string, " \n\r\tbiglongstring \n\r\t ");
furi_string_trim(string);
mu_assert_string_eq("biglongstring", furi_string_get_cstr(string));
furi_string_set(string, "aaaabaaaabbaaabaaaabbtestaaaaaabbaaabaababaa");
furi_string_trim(string, "ab");
mu_assert_string_eq("test", furi_string_get_cstr(string));
furi_string_free(string);
}
MU_TEST(mu_test_furi_string_utf8) {
FuriString* utf8_string = furi_string_alloc_set("イルカ");
// test furi_string_utf8_length
mu_assert_int_eq(9, furi_string_size(utf8_string));
mu_assert_int_eq(3, furi_string_utf8_length(utf8_string));
// test furi_string_utf8_decode
const uint8_t dolphin_emoji_array[4] = {0xF0, 0x9F, 0x90, 0xAC};
FuriStringUTF8State state = FuriStringUTF8StateStarting;
FuriStringUnicodeValue value = 0;
furi_string_utf8_decode(dolphin_emoji_array[0], &state, &value);
mu_assert_int_eq(FuriStringUTF8StateDecoding3, state);
furi_string_utf8_decode(dolphin_emoji_array[1], &state, &value);
mu_assert_int_eq(FuriStringUTF8StateDecoding2, state);
furi_string_utf8_decode(dolphin_emoji_array[2], &state, &value);
mu_assert_int_eq(FuriStringUTF8StateDecoding1, state);
furi_string_utf8_decode(dolphin_emoji_array[3], &state, &value);
mu_assert_int_eq(FuriStringUTF8StateStarting, state);
mu_assert_int_eq(0x1F42C, value);
// test furi_string_utf8_push
furi_string_set(utf8_string, "");
furi_string_utf8_push(utf8_string, value);
mu_assert_string_eq("🐬", furi_string_get_cstr(utf8_string));
furi_string_free(utf8_string);
}
MU_TEST_SUITE(test_suite) {
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
MU_RUN_TEST(mu_test_furi_string_alloc_free);
MU_RUN_TEST(mu_test_furi_string_mem);
MU_RUN_TEST(mu_test_furi_string_getters);
MU_RUN_TEST(mu_test_furi_string_setters);
MU_RUN_TEST(mu_test_furi_string_appends);
MU_RUN_TEST(mu_test_furi_string_compare);
MU_RUN_TEST(mu_test_furi_string_search);
MU_RUN_TEST(mu_test_furi_string_equality);
MU_RUN_TEST(mu_test_furi_string_replace);
MU_RUN_TEST(mu_test_furi_string_start_end);
MU_RUN_TEST(mu_test_furi_string_trim);
MU_RUN_TEST(mu_test_furi_string_utf8);
}
int run_minunit_test_furi_string(void) {
MU_RUN_SUITE(test_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_furi_string)

View File

@@ -0,0 +1,553 @@
#include <furi.h>
#include <flipper_format.h>
#include <infrared.h>
#include <common/infrared_common_i.h>
#include "../test.h"
#define IR_TEST_FILES_DIR EXT_PATH("unit_tests/infrared/")
#define IR_TEST_FILE_PREFIX "test_"
#define IR_TEST_FILE_SUFFIX ".irtest"
typedef struct {
InfraredDecoderHandler* decoder_handler;
InfraredEncoderHandler* encoder_handler;
FuriString* file_path;
FlipperFormat* ff;
} InfraredTest;
static InfraredTest* test;
static void infrared_test_alloc(void) {
Storage* storage = furi_record_open(RECORD_STORAGE);
test = malloc(sizeof(InfraredTest));
test->decoder_handler = infrared_alloc_decoder();
test->encoder_handler = infrared_alloc_encoder();
test->ff = flipper_format_buffered_file_alloc(storage);
test->file_path = furi_string_alloc();
}
static void infrared_test_free(void) {
furi_check(test);
infrared_free_decoder(test->decoder_handler);
infrared_free_encoder(test->encoder_handler);
flipper_format_free(test->ff);
furi_string_free(test->file_path);
furi_record_close(RECORD_STORAGE);
free(test);
test = NULL;
}
static bool infrared_test_prepare_file(const char* protocol_name) {
FuriString* file_type;
file_type = furi_string_alloc();
bool success = false;
furi_string_printf(
test->file_path,
"%s%s%s%s",
IR_TEST_FILES_DIR,
IR_TEST_FILE_PREFIX,
protocol_name,
IR_TEST_FILE_SUFFIX);
do {
uint32_t format_version;
if(!flipper_format_buffered_file_open_existing(
test->ff, furi_string_get_cstr(test->file_path)))
break;
if(!flipper_format_read_header(test->ff, file_type, &format_version)) break;
if(furi_string_cmp_str(file_type, "IR tests file") || format_version != 1) break;
success = true;
} while(false);
furi_string_free(file_type);
return success;
}
static bool infrared_test_load_raw_signal(
FlipperFormat* ff,
const char* signal_name,
uint32_t** timings,
uint32_t* timings_count) {
FuriString* buf;
buf = furi_string_alloc();
bool success = false;
do {
bool is_name_found = false;
for(; !is_name_found && flipper_format_read_string(ff, "name", buf);
is_name_found = !furi_string_cmp(buf, signal_name))
;
if(!is_name_found) break;
if(!flipper_format_read_string(ff, "type", buf) || furi_string_cmp_str(buf, "raw")) break;
if(!flipper_format_get_value_count(ff, "data", timings_count)) break;
if(!*timings_count) break;
*timings = malloc(*timings_count * sizeof(uint32_t*));
if(!flipper_format_read_uint32(ff, "data", *timings, *timings_count)) {
free(*timings);
break;
}
success = true;
} while(false);
furi_string_free(buf);
return success;
}
static bool infrared_test_read_message(FlipperFormat* ff, InfraredMessage* message) {
FuriString* buf;
buf = furi_string_alloc();
bool success = false;
do {
if(!flipper_format_read_string(ff, "protocol", buf)) break;
message->protocol = infrared_get_protocol_by_name(furi_string_get_cstr(buf));
if(!infrared_is_protocol_valid(message->protocol)) break;
if(!flipper_format_read_hex(ff, "address", (uint8_t*)&message->address, sizeof(uint32_t)))
break;
if(!flipper_format_read_hex(ff, "command", (uint8_t*)&message->command, sizeof(uint32_t)))
break;
if(!flipper_format_read_bool(ff, "repeat", &message->repeat, 1)) break;
success = true;
} while(false);
furi_string_free(buf);
return success;
}
static bool infrared_test_load_messages(
FlipperFormat* ff,
const char* signal_name,
InfraredMessage** messages,
uint32_t* messages_count) {
FuriString* buf;
buf = furi_string_alloc();
bool success = false;
do {
bool is_name_found = false;
for(; !is_name_found && flipper_format_read_string(ff, "name", buf);
is_name_found = !furi_string_cmp(buf, signal_name))
;
if(!is_name_found) break;
if(!flipper_format_read_string(ff, "type", buf) ||
furi_string_cmp_str(buf, "parsed_array"))
break;
if(!flipper_format_read_uint32(ff, "count", messages_count, 1)) break;
if(!*messages_count) break;
*messages = malloc(*messages_count * sizeof(InfraredMessage));
uint32_t i;
for(i = 0; i < *messages_count; ++i) {
if(!infrared_test_read_message(ff, (*messages) + i)) {
break;
}
}
if(*messages_count != i) {
free(*messages);
break;
}
success = true;
} while(false);
furi_string_free(buf);
return success;
}
static void infrared_test_compare_message_results(
const InfraredMessage* message_decoded,
const InfraredMessage* message_expected) {
mu_check(message_decoded->protocol == message_expected->protocol);
mu_check(message_decoded->command == message_expected->command);
mu_check(message_decoded->address == message_expected->address);
if((message_expected->protocol == InfraredProtocolSIRC) ||
(message_expected->protocol == InfraredProtocolSIRC15) ||
(message_expected->protocol == InfraredProtocolSIRC20)) {
mu_check(message_decoded->repeat == false);
} else {
mu_check(message_decoded->repeat == message_expected->repeat);
}
}
/* Encodes signal and merges same levels (high+high, low+low) */
static void infrared_test_run_encoder_fill_array(
InfraredEncoderHandler* handler,
uint32_t* timings,
uint32_t* timings_len,
bool* start_level) {
uint32_t duration = 0;
bool level = false;
bool level_read;
InfraredStatus status = InfraredStatusError;
size_t i = 0;
bool first = true;
while(1) {
status = infrared_encode(handler, &duration, &level_read);
if(first) {
if(start_level) *start_level = level_read;
first = false;
timings[0] = 0;
} else if(level_read != level) {
++i;
furi_check(i < *timings_len);
timings[i] = 0;
}
level = level_read;
timings[i] += duration;
furi_check((status == InfraredStatusOk) || (status == InfraredStatusDone));
if(status == InfraredStatusDone) break;
}
*timings_len = i + 1;
}
// messages in input array for encoder should have one protocol
static void infrared_test_run_encoder(InfraredProtocol protocol, uint32_t test_index) {
uint32_t* timings;
uint32_t timings_count = 200;
uint32_t* expected_timings;
uint32_t expected_timings_count;
InfraredMessage* input_messages;
uint32_t input_messages_count;
FuriString* buf;
buf = furi_string_alloc();
const char* protocol_name = infrared_get_protocol_name(protocol);
mu_assert(infrared_test_prepare_file(protocol_name), "Failed to prepare test file");
furi_string_printf(buf, "encoder_input%ld", test_index);
mu_assert(
infrared_test_load_messages(
test->ff, furi_string_get_cstr(buf), &input_messages, &input_messages_count),
"Failed to load messages from file");
furi_string_printf(buf, "encoder_expected%ld", test_index);
mu_assert(
infrared_test_load_raw_signal(
test->ff, furi_string_get_cstr(buf), &expected_timings, &expected_timings_count),
"Failed to load raw signal from file");
flipper_format_buffered_file_close(test->ff);
furi_string_free(buf);
uint32_t j = 0;
timings = malloc(sizeof(uint32_t) * timings_count);
for(uint32_t message_counter = 0; message_counter < input_messages_count; ++message_counter) {
const InfraredMessage* message = &input_messages[message_counter];
if(!message->repeat) {
infrared_reset_encoder(test->encoder_handler, message);
}
timings_count = 200;
infrared_test_run_encoder_fill_array(test->encoder_handler, timings, &timings_count, NULL);
furi_check(timings_count <= 200);
for(size_t i = 0; i < timings_count; ++i, ++j) {
mu_check(MATCH_TIMING(timings[i], expected_timings[j], 120));
mu_assert(j < expected_timings_count, "encoded more timings than expected");
}
}
free(input_messages);
free(expected_timings);
free(timings);
mu_assert(j == expected_timings_count, "encoded less timings than expected");
}
static void infrared_test_run_encoder_decoder(InfraredProtocol protocol, uint32_t test_index) {
uint32_t* timings = 0;
uint32_t timings_count = 200;
InfraredMessage* input_messages;
uint32_t input_messages_count;
bool level = false;
FuriString* buf;
buf = furi_string_alloc();
timings = malloc(sizeof(uint32_t) * timings_count);
const char* protocol_name = infrared_get_protocol_name(protocol);
mu_assert(infrared_test_prepare_file(protocol_name), "Failed to prepare test file");
furi_string_printf(buf, "encoder_decoder_input%ld", test_index);
mu_assert(
infrared_test_load_messages(
test->ff, furi_string_get_cstr(buf), &input_messages, &input_messages_count),
"Failed to load messages from file");
flipper_format_buffered_file_close(test->ff);
furi_string_free(buf);
for(uint32_t message_counter = 0; message_counter < input_messages_count; ++message_counter) {
const InfraredMessage* message_encoded = &input_messages[message_counter];
if(!message_encoded->repeat) {
infrared_reset_encoder(test->encoder_handler, message_encoded);
}
timings_count = 200;
infrared_test_run_encoder_fill_array(
test->encoder_handler, timings, &timings_count, &level);
furi_check(timings_count <= 200);
const InfraredMessage* message_decoded = 0;
for(size_t i = 0; i < timings_count; ++i) {
message_decoded = infrared_decode(test->decoder_handler, level, timings[i]);
if((i == timings_count - 2) && level && message_decoded) {
/* In case we end with space timing - message can be decoded at last mark */
break;
} else if(i < timings_count - 1) {
mu_check(!message_decoded);
} else {
if(!message_decoded) {
message_decoded = infrared_check_decoder_ready(test->decoder_handler);
}
mu_check(message_decoded);
}
level = !level;
}
if(message_decoded) {
infrared_test_compare_message_results(message_decoded, message_encoded);
} else {
mu_check(0);
}
}
free(input_messages);
free(timings);
}
static void infrared_test_run_decoder(InfraredProtocol protocol, uint32_t test_index) {
uint32_t* timings;
uint32_t timings_count;
InfraredMessage* messages;
uint32_t messages_count;
FuriString* buf;
buf = furi_string_alloc();
mu_assert(
infrared_test_prepare_file(infrared_get_protocol_name(protocol)),
"Failed to prepare test file");
furi_string_printf(buf, "decoder_input%ld", test_index);
mu_assert(
infrared_test_load_raw_signal(
test->ff, furi_string_get_cstr(buf), &timings, &timings_count),
"Failed to load raw signal from file");
furi_string_printf(buf, "decoder_expected%ld", test_index);
mu_assert(
infrared_test_load_messages(
test->ff, furi_string_get_cstr(buf), &messages, &messages_count),
"Failed to load messages from file");
flipper_format_buffered_file_close(test->ff);
furi_string_free(buf);
InfraredMessage message_decoded_check_local;
bool level = 0;
uint32_t message_counter = 0;
const InfraredMessage* message_decoded = 0;
for(uint32_t i = 0; i < timings_count; ++i) {
const InfraredMessage* message_decoded_check = 0;
if(timings[i] > INFRARED_RAW_RX_TIMING_DELAY_US) {
message_decoded_check = infrared_check_decoder_ready(test->decoder_handler);
if(message_decoded_check) {
/* infrared_decode() can reset message, but we have to call infrared_decode() to perform real
* simulation: infrared_check() by timeout, then infrared_decode() when meet edge */
message_decoded_check_local = *message_decoded_check;
message_decoded_check = &message_decoded_check_local;
}
}
message_decoded = infrared_decode(test->decoder_handler, level, timings[i]);
if(message_decoded_check || message_decoded) {
mu_assert(
!(message_decoded_check && message_decoded),
"both messages decoded: check_ready() and infrared_decode()");
if(message_decoded_check) {
message_decoded = message_decoded_check;
}
mu_assert(message_counter < messages_count, "decoded more than expected");
infrared_test_compare_message_results(message_decoded, &messages[message_counter]);
++message_counter;
}
level = !level;
}
message_decoded = infrared_check_decoder_ready(test->decoder_handler);
if(message_decoded) {
infrared_test_compare_message_results(message_decoded, &messages[message_counter]);
++message_counter;
}
free(timings);
free(messages);
mu_assert(message_counter == messages_count, "decoded less than expected");
}
MU_TEST(infrared_test_decoder_samsung32) {
infrared_test_run_decoder(InfraredProtocolSamsung32, 1);
}
MU_TEST(infrared_test_decoder_mixed) {
infrared_test_run_decoder(InfraredProtocolRC5, 2);
infrared_test_run_decoder(InfraredProtocolSIRC, 1);
infrared_test_run_decoder(InfraredProtocolNECext, 1);
infrared_test_run_decoder(InfraredProtocolRC6, 2);
infrared_test_run_decoder(InfraredProtocolSamsung32, 1);
infrared_test_run_decoder(InfraredProtocolRC6, 1);
infrared_test_run_decoder(InfraredProtocolSamsung32, 1);
infrared_test_run_decoder(InfraredProtocolRC5, 1);
infrared_test_run_decoder(InfraredProtocolSIRC, 2);
infrared_test_run_decoder(InfraredProtocolNECext, 1);
infrared_test_run_decoder(InfraredProtocolSIRC, 4);
infrared_test_run_decoder(InfraredProtocolNEC, 2);
infrared_test_run_decoder(InfraredProtocolRC6, 1);
infrared_test_run_decoder(InfraredProtocolNECext, 1);
infrared_test_run_decoder(InfraredProtocolSIRC, 5);
infrared_test_run_decoder(InfraredProtocolNEC, 3);
infrared_test_run_decoder(InfraredProtocolRC5, 5);
infrared_test_run_decoder(InfraredProtocolSamsung32, 1);
infrared_test_run_decoder(InfraredProtocolSIRC, 3);
infrared_test_run_decoder(InfraredProtocolKaseikyo, 1);
infrared_test_run_decoder(InfraredProtocolRCA, 1);
infrared_test_run_decoder(InfraredProtocolPioneer, 6);
}
MU_TEST(infrared_test_decoder_nec) {
for(uint32_t i = 1; i <= 3; ++i) {
infrared_test_run_decoder(InfraredProtocolNEC, i);
}
}
MU_TEST(infrared_test_decoder_unexpected_end_in_sequence) {
for(uint32_t i = 1; i <= 2; ++i) {
infrared_test_run_decoder(InfraredProtocolNEC, i);
infrared_test_run_decoder(InfraredProtocolNEC, i);
}
}
MU_TEST(infrared_test_decoder_necext1) {
for(uint32_t i = 0; i < 2; ++i) {
UNUSED(i);
infrared_test_run_decoder(InfraredProtocolNECext, 1);
}
}
MU_TEST(infrared_test_decoder_long_packets_with_nec_start) {
for(uint32_t i = 1; i <= 2; ++i) {
infrared_test_run_decoder(InfraredProtocolNEC42ext, i);
}
}
MU_TEST(infrared_test_encoder_sirc) {
for(uint32_t i = 1; i <= 2; ++i) {
infrared_test_run_encoder(InfraredProtocolSIRC, i);
}
}
MU_TEST(infrared_test_decoder_sirc) {
for(uint32_t i = 1; i <= 5; ++i) {
infrared_test_run_decoder(InfraredProtocolSIRC, 5);
}
}
MU_TEST(infrared_test_decoder_rc5) {
infrared_test_run_decoder(InfraredProtocolRC5X, 1);
for(uint32_t i = 1; i <= 7; ++i) {
infrared_test_run_decoder(InfraredProtocolRC5, i);
}
}
MU_TEST(infrared_test_encoder_rc5x) {
infrared_test_run_encoder(InfraredProtocolRC5X, 1);
}
MU_TEST(infrared_test_encoder_rc5) {
infrared_test_run_encoder(InfraredProtocolRC5, 1);
}
MU_TEST(infrared_test_decoder_rc6) {
infrared_test_run_decoder(InfraredProtocolRC6, 1);
}
MU_TEST(infrared_test_encoder_rc6) {
infrared_test_run_encoder(InfraredProtocolRC6, 1);
}
MU_TEST(infrared_test_decoder_kaseikyo) {
for(uint32_t i = 1; i <= 6; ++i) {
infrared_test_run_decoder(InfraredProtocolKaseikyo, i);
}
}
MU_TEST(infrared_test_decoder_rca) {
for(uint32_t i = 1; i <= 6; ++i) {
infrared_test_run_decoder(InfraredProtocolRCA, i);
}
}
MU_TEST(infrared_test_decoder_pioneer) {
for(uint32_t i = 1; i <= 11; ++i) {
infrared_test_run_decoder(InfraredProtocolPioneer, i);
}
}
MU_TEST(infrared_test_encoder_decoder_all) {
infrared_test_run_encoder_decoder(InfraredProtocolNEC, 1);
infrared_test_run_encoder_decoder(InfraredProtocolNECext, 1);
infrared_test_run_encoder_decoder(InfraredProtocolNEC42, 1);
infrared_test_run_encoder_decoder(InfraredProtocolNEC42ext, 1);
infrared_test_run_encoder_decoder(InfraredProtocolSamsung32, 1);
infrared_test_run_encoder_decoder(InfraredProtocolRC6, 1);
infrared_test_run_encoder_decoder(InfraredProtocolRC5, 1);
infrared_test_run_encoder_decoder(InfraredProtocolSIRC, 1);
infrared_test_run_encoder_decoder(InfraredProtocolKaseikyo, 1);
infrared_test_run_encoder_decoder(InfraredProtocolRCA, 1);
infrared_test_run_encoder_decoder(InfraredProtocolPioneer, 1);
}
MU_TEST_SUITE(infrared_test) {
MU_SUITE_CONFIGURE(&infrared_test_alloc, &infrared_test_free);
MU_RUN_TEST(infrared_test_encoder_sirc);
MU_RUN_TEST(infrared_test_decoder_sirc);
MU_RUN_TEST(infrared_test_encoder_rc5x);
MU_RUN_TEST(infrared_test_encoder_rc5);
MU_RUN_TEST(infrared_test_decoder_rc5);
MU_RUN_TEST(infrared_test_decoder_rc6);
MU_RUN_TEST(infrared_test_encoder_rc6);
MU_RUN_TEST(infrared_test_decoder_unexpected_end_in_sequence);
MU_RUN_TEST(infrared_test_decoder_long_packets_with_nec_start);
MU_RUN_TEST(infrared_test_decoder_nec);
MU_RUN_TEST(infrared_test_decoder_samsung32);
MU_RUN_TEST(infrared_test_decoder_necext1);
MU_RUN_TEST(infrared_test_decoder_kaseikyo);
MU_RUN_TEST(infrared_test_decoder_rca);
MU_RUN_TEST(infrared_test_decoder_pioneer);
MU_RUN_TEST(infrared_test_decoder_mixed);
MU_RUN_TEST(infrared_test_encoder_decoder_all);
}
int run_minunit_test_infrared(void) {
MU_RUN_SUITE(infrared_test);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_infrared)

View File

@@ -0,0 +1,555 @@
#include <furi.h>
#include "../test.h"
#include <toolbox/protocols/protocol_dict.h>
#include <lfrfid/protocols/lfrfid_protocols.h>
#include <toolbox/pulse_protocols/pulse_glue.h>
#define LF_RFID_READ_TIMING_MULTIPLIER 8
#define EM_TEST_DATA \
{ 0x58, 0x00, 0x85, 0x64, 0x02 }
#define EM_TEST_DATA_SIZE 5
#define EM_TEST_EMULATION_TIMINGS_COUNT (64 * 2)
const int8_t em_test_timings[EM_TEST_EMULATION_TIMINGS_COUNT] = {
32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, -32,
32, 32, -32, -32, 32, 32, -32, -32, 32, 32, -32, -32, 32, -32, 32, -32, 32, 32, -32,
-32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32,
32, 32, -32, -32, 32, -32, 32, -32, 32, 32, -32, -32, 32, 32, -32, -32, 32, 32, -32,
-32, 32, -32, 32, 32, -32, 32, -32, -32, 32, -32, 32, -32, 32, 32, -32, -32, 32, -32,
32, 32, -32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, 32, -32,
-32, 32, 32, -32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32,
};
#define HID10301_TEST_DATA \
{ 0x8D, 0x48, 0xA8 }
#define HID10301_TEST_DATA_SIZE 3
#define HID10301_TEST_EMULATION_TIMINGS_COUNT (541 * 2)
const int8_t hid10301_test_timings[HID10301_TEST_EMULATION_TIMINGS_COUNT] = {
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5,
5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5,
5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5,
5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5,
5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5,
5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5,
5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5,
5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5,
5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5,
5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5,
5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
};
#define IOPROX_XSF_TEST_DATA \
{ 0x65, 0x01, 0x05, 0x39 }
#define IOPROX_XSF_TEST_DATA_SIZE 4
#define IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT (468 * 2)
const int8_t ioprox_xsf_test_timings[IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT] = {
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5,
5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5,
5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4,
4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
4, -4, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5,
5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5, 5, -5,
};
#define INDALA26_EMULATION_TIMINGS_COUNT (1024 * 2)
#define INDALA26_TEST_DATA \
{ 0x3B, 0x73, 0x64, 0xA8 }
#define INDALA26_TEST_DATA_SIZE 4
const int8_t indala26_test_timings[INDALA26_EMULATION_TIMINGS_COUNT] = {
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1,
-1, 1, -1, 1, -1, 1, -1, 1,
};
#define FDXB_TEST_DATA \
{ 0x44, 0x88, 0x23, 0xF2, 0x5A, 0x6F, 0x00, 0x01, 0x00, 0x00, 0x00 }
#define FDXB_TEST_DATA_SIZE 11
#define FDXB_TEST_EMULATION_TIMINGS_COUNT (206)
const int8_t fdxb_test_timings[FDXB_TEST_EMULATION_TIMINGS_COUNT] = {
32, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16,
-16, 16, -32, 16, -16, 32, -16, 16, -16, 16, -16, 16, -32, 16, -16, 16, -16, 32, -32,
16, -16, 16, -16, 16, -16, 32, -16, 16, -16, 16, -16, 16, -32, 16, -16, 16, -16, 32,
-16, 16, -16, 16, -16, 16, -32, 32, -32, 32, -32, 32, -32, 16, -16, 16, -16, 32, -16,
16, -32, 16, -16, 32, -16, 16, -32, 32, -16, 16, -32, 16, -16, 32, -16, 16, -32, 32,
-16, 16, -32, 32, -32, 32, -32, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16,
16, -16, 16, -16, 32, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16,
-32, 32, -32, 32, -32, 32, -32, 16, -16, 32, -32, 32, -16, 16, -16, 16, -32, 32, -32,
32, -32, 32, -32, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16,
-16, 32, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -32,
16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16, 16, -16,
};
MU_TEST(test_lfrfid_protocol_em_read_simple) {
ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
mu_assert_int_eq(EM_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolEM4100));
mu_assert_string_eq("EM4100", protocol_dict_get_name(dict, LFRFIDProtocolEM4100));
mu_assert_string_eq("EM-Micro", protocol_dict_get_manufacturer(dict, LFRFIDProtocolEM4100));
const uint8_t data[EM_TEST_DATA_SIZE] = EM_TEST_DATA;
protocol_dict_decoders_start(dict);
ProtocolId protocol = PROTOCOL_NO;
PulseGlue* pulse_glue = pulse_glue_alloc();
for(size_t i = 0; i < EM_TEST_EMULATION_TIMINGS_COUNT * 10; i++) {
bool pulse_pop = pulse_glue_push(
pulse_glue,
em_test_timings[i % EM_TEST_EMULATION_TIMINGS_COUNT] >= 0,
abs(em_test_timings[i % EM_TEST_EMULATION_TIMINGS_COUNT]) *
LF_RFID_READ_TIMING_MULTIPLIER);
if(pulse_pop) {
uint32_t length, period;
pulse_glue_pop(pulse_glue, &length, &period);
protocol = protocol_dict_decoders_feed(dict, true, period);
if(protocol != PROTOCOL_NO) break;
protocol = protocol_dict_decoders_feed(dict, false, length - period);
if(protocol != PROTOCOL_NO) break;
}
}
pulse_glue_free(pulse_glue);
mu_assert_int_eq(LFRFIDProtocolEM4100, protocol);
uint8_t received_data[EM_TEST_DATA_SIZE] = {0};
protocol_dict_get_data(dict, protocol, received_data, EM_TEST_DATA_SIZE);
mu_assert_mem_eq(data, received_data, EM_TEST_DATA_SIZE);
protocol_dict_free(dict);
}
MU_TEST(test_lfrfid_protocol_em_emulate_simple) {
ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
mu_assert_int_eq(EM_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolEM4100));
mu_assert_string_eq("EM4100", protocol_dict_get_name(dict, LFRFIDProtocolEM4100));
mu_assert_string_eq("EM-Micro", protocol_dict_get_manufacturer(dict, LFRFIDProtocolEM4100));
const uint8_t data[EM_TEST_DATA_SIZE] = EM_TEST_DATA;
protocol_dict_set_data(dict, LFRFIDProtocolEM4100, data, EM_TEST_DATA_SIZE);
mu_check(protocol_dict_encoder_start(dict, LFRFIDProtocolEM4100));
for(size_t i = 0; i < EM_TEST_EMULATION_TIMINGS_COUNT; i++) {
LevelDuration level_duration = protocol_dict_encoder_yield(dict, LFRFIDProtocolEM4100);
if(level_duration_get_level(level_duration)) {
mu_assert_int_eq(em_test_timings[i], level_duration_get_duration(level_duration));
} else {
mu_assert_int_eq(em_test_timings[i], -level_duration_get_duration(level_duration));
}
}
protocol_dict_free(dict);
}
MU_TEST(test_lfrfid_protocol_h10301_read_simple) {
ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
mu_assert_int_eq(
HID10301_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolH10301));
mu_assert_string_eq("H10301", protocol_dict_get_name(dict, LFRFIDProtocolH10301));
mu_assert_string_eq("HID", protocol_dict_get_manufacturer(dict, LFRFIDProtocolH10301));
const uint8_t data[HID10301_TEST_DATA_SIZE] = HID10301_TEST_DATA;
protocol_dict_decoders_start(dict);
ProtocolId protocol = PROTOCOL_NO;
PulseGlue* pulse_glue = pulse_glue_alloc();
for(size_t i = 0; i < HID10301_TEST_EMULATION_TIMINGS_COUNT * 10; i++) {
bool pulse_pop = pulse_glue_push(
pulse_glue,
hid10301_test_timings[i % HID10301_TEST_EMULATION_TIMINGS_COUNT] >= 0,
abs(hid10301_test_timings[i % HID10301_TEST_EMULATION_TIMINGS_COUNT]) *
LF_RFID_READ_TIMING_MULTIPLIER);
if(pulse_pop) {
uint32_t length, period;
pulse_glue_pop(pulse_glue, &length, &period);
protocol = protocol_dict_decoders_feed(dict, true, period);
if(protocol != PROTOCOL_NO) break;
protocol = protocol_dict_decoders_feed(dict, false, length - period);
if(protocol != PROTOCOL_NO) break;
}
}
pulse_glue_free(pulse_glue);
mu_assert_int_eq(LFRFIDProtocolH10301, protocol);
uint8_t received_data[HID10301_TEST_DATA_SIZE] = {0};
protocol_dict_get_data(dict, protocol, received_data, HID10301_TEST_DATA_SIZE);
mu_assert_mem_eq(data, received_data, HID10301_TEST_DATA_SIZE);
protocol_dict_free(dict);
}
MU_TEST(test_lfrfid_protocol_h10301_emulate_simple) {
ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
mu_assert_int_eq(
HID10301_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolH10301));
mu_assert_string_eq("H10301", protocol_dict_get_name(dict, LFRFIDProtocolH10301));
mu_assert_string_eq("HID", protocol_dict_get_manufacturer(dict, LFRFIDProtocolH10301));
const uint8_t data[HID10301_TEST_DATA_SIZE] = HID10301_TEST_DATA;
protocol_dict_set_data(dict, LFRFIDProtocolH10301, data, HID10301_TEST_DATA_SIZE);
mu_check(protocol_dict_encoder_start(dict, LFRFIDProtocolH10301));
for(size_t i = 0; i < HID10301_TEST_EMULATION_TIMINGS_COUNT; i++) {
LevelDuration level_duration = protocol_dict_encoder_yield(dict, LFRFIDProtocolH10301);
if(level_duration_get_level(level_duration)) {
mu_assert_int_eq(
hid10301_test_timings[i], level_duration_get_duration(level_duration));
} else {
mu_assert_int_eq(
hid10301_test_timings[i], -level_duration_get_duration(level_duration));
}
}
protocol_dict_free(dict);
}
MU_TEST(test_lfrfid_protocol_ioprox_xsf_read_simple) {
ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
mu_assert_int_eq(
IOPROX_XSF_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolIOProxXSF));
mu_assert_string_eq("IoProxXSF", protocol_dict_get_name(dict, LFRFIDProtocolIOProxXSF));
mu_assert_string_eq("Kantech", protocol_dict_get_manufacturer(dict, LFRFIDProtocolIOProxXSF));
const uint8_t data[IOPROX_XSF_TEST_DATA_SIZE] = IOPROX_XSF_TEST_DATA;
protocol_dict_decoders_start(dict);
ProtocolId protocol = PROTOCOL_NO;
PulseGlue* pulse_glue = pulse_glue_alloc();
for(size_t i = 0; i < IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT * 10; i++) {
bool pulse_pop = pulse_glue_push(
pulse_glue,
ioprox_xsf_test_timings[i % IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT] >= 0,
abs(ioprox_xsf_test_timings[i % IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT]) *
LF_RFID_READ_TIMING_MULTIPLIER);
if(pulse_pop) {
uint32_t length, period;
pulse_glue_pop(pulse_glue, &length, &period);
protocol = protocol_dict_decoders_feed(dict, true, period);
if(protocol != PROTOCOL_NO) break;
protocol = protocol_dict_decoders_feed(dict, false, length - period);
if(protocol != PROTOCOL_NO) break;
}
}
pulse_glue_free(pulse_glue);
mu_assert_int_eq(LFRFIDProtocolIOProxXSF, protocol);
uint8_t received_data[IOPROX_XSF_TEST_DATA_SIZE] = {0};
protocol_dict_get_data(dict, protocol, received_data, IOPROX_XSF_TEST_DATA_SIZE);
mu_assert_mem_eq(data, received_data, IOPROX_XSF_TEST_DATA_SIZE);
protocol_dict_free(dict);
}
MU_TEST(test_lfrfid_protocol_ioprox_xsf_emulate_simple) {
ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
mu_assert_int_eq(
IOPROX_XSF_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolIOProxXSF));
mu_assert_string_eq("IoProxXSF", protocol_dict_get_name(dict, LFRFIDProtocolIOProxXSF));
mu_assert_string_eq("Kantech", protocol_dict_get_manufacturer(dict, LFRFIDProtocolIOProxXSF));
const uint8_t data[IOPROX_XSF_TEST_DATA_SIZE] = IOPROX_XSF_TEST_DATA;
protocol_dict_set_data(dict, LFRFIDProtocolIOProxXSF, data, IOPROX_XSF_TEST_DATA_SIZE);
mu_check(protocol_dict_encoder_start(dict, LFRFIDProtocolIOProxXSF));
for(size_t i = 0; i < IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT; i++) {
LevelDuration level_duration = protocol_dict_encoder_yield(dict, LFRFIDProtocolIOProxXSF);
if(level_duration_get_level(level_duration)) {
mu_assert_int_eq(
ioprox_xsf_test_timings[i], level_duration_get_duration(level_duration));
} else {
mu_assert_int_eq(
ioprox_xsf_test_timings[i], -level_duration_get_duration(level_duration));
}
}
protocol_dict_free(dict);
}
MU_TEST(test_lfrfid_protocol_inadala26_emulate_simple) {
ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
mu_assert_int_eq(
INDALA26_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolIndala26));
mu_assert_string_eq("Indala26", protocol_dict_get_name(dict, LFRFIDProtocolIndala26));
mu_assert_string_eq("Motorola", protocol_dict_get_manufacturer(dict, LFRFIDProtocolIndala26));
const uint8_t data[INDALA26_TEST_DATA_SIZE] = INDALA26_TEST_DATA;
protocol_dict_set_data(dict, LFRFIDProtocolIndala26, data, INDALA26_TEST_DATA_SIZE);
mu_check(protocol_dict_encoder_start(dict, LFRFIDProtocolIndala26));
for(size_t i = 0; i < INDALA26_EMULATION_TIMINGS_COUNT; i++) {
LevelDuration level_duration = protocol_dict_encoder_yield(dict, LFRFIDProtocolIndala26);
if(level_duration_get_level(level_duration)) {
mu_assert_int_eq(
indala26_test_timings[i], level_duration_get_duration(level_duration));
} else {
mu_assert_int_eq(
indala26_test_timings[i], -level_duration_get_duration(level_duration));
}
}
protocol_dict_free(dict);
}
MU_TEST(test_lfrfid_protocol_fdxb_emulate_simple) {
ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
mu_assert_int_eq(FDXB_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolFDXB));
mu_assert_string_eq("FDX-B", protocol_dict_get_name(dict, LFRFIDProtocolFDXB));
mu_assert_string_eq("ISO", protocol_dict_get_manufacturer(dict, LFRFIDProtocolFDXB));
const uint8_t data[FDXB_TEST_DATA_SIZE] = FDXB_TEST_DATA;
protocol_dict_set_data(dict, LFRFIDProtocolFDXB, data, FDXB_TEST_DATA_SIZE);
mu_check(protocol_dict_encoder_start(dict, LFRFIDProtocolFDXB));
for(size_t i = 0; i < FDXB_TEST_EMULATION_TIMINGS_COUNT; i++) {
LevelDuration level_duration = protocol_dict_encoder_yield(dict, LFRFIDProtocolFDXB);
if(level_duration_get_level(level_duration)) {
mu_assert_int_eq(fdxb_test_timings[i], level_duration_get_duration(level_duration));
} else {
mu_assert_int_eq(fdxb_test_timings[i], -level_duration_get_duration(level_duration));
}
}
protocol_dict_free(dict);
}
MU_TEST(test_lfrfid_protocol_fdxb_read_simple) {
ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
mu_assert_int_eq(FDXB_TEST_DATA_SIZE, protocol_dict_get_data_size(dict, LFRFIDProtocolFDXB));
mu_assert_string_eq("FDX-B", protocol_dict_get_name(dict, LFRFIDProtocolFDXB));
mu_assert_string_eq("ISO", protocol_dict_get_manufacturer(dict, LFRFIDProtocolFDXB));
const uint8_t data[FDXB_TEST_DATA_SIZE] = FDXB_TEST_DATA;
protocol_dict_decoders_start(dict);
ProtocolId protocol = PROTOCOL_NO;
PulseGlue* pulse_glue = pulse_glue_alloc();
for(size_t i = 0; i < FDXB_TEST_EMULATION_TIMINGS_COUNT * 10; i++) {
bool pulse_pop = pulse_glue_push(
pulse_glue,
fdxb_test_timings[i % FDXB_TEST_EMULATION_TIMINGS_COUNT] >= 0,
abs(fdxb_test_timings[i % FDXB_TEST_EMULATION_TIMINGS_COUNT]) *
LF_RFID_READ_TIMING_MULTIPLIER);
if(pulse_pop) {
uint32_t length, period;
pulse_glue_pop(pulse_glue, &length, &period);
protocol = protocol_dict_decoders_feed(dict, true, period);
if(protocol != PROTOCOL_NO) break;
protocol = protocol_dict_decoders_feed(dict, false, length - period);
if(protocol != PROTOCOL_NO) break;
}
}
pulse_glue_free(pulse_glue);
mu_assert_int_eq(LFRFIDProtocolFDXB, protocol);
uint8_t received_data[FDXB_TEST_DATA_SIZE] = {0};
protocol_dict_get_data(dict, protocol, received_data, FDXB_TEST_DATA_SIZE);
mu_assert_mem_eq(data, received_data, FDXB_TEST_DATA_SIZE);
protocol_dict_free(dict);
}
MU_TEST_SUITE(test_lfrfid_protocols_suite) {
MU_RUN_TEST(test_lfrfid_protocol_em_read_simple);
MU_RUN_TEST(test_lfrfid_protocol_em_emulate_simple);
MU_RUN_TEST(test_lfrfid_protocol_h10301_read_simple);
MU_RUN_TEST(test_lfrfid_protocol_h10301_emulate_simple);
MU_RUN_TEST(test_lfrfid_protocol_ioprox_xsf_read_simple);
MU_RUN_TEST(test_lfrfid_protocol_ioprox_xsf_emulate_simple);
MU_RUN_TEST(test_lfrfid_protocol_inadala26_emulate_simple);
MU_RUN_TEST(test_lfrfid_protocol_fdxb_read_simple);
MU_RUN_TEST(test_lfrfid_protocol_fdxb_emulate_simple);
}
int run_minunit_test_lfrfid_protocols(void) {
MU_RUN_SUITE(test_lfrfid_protocols_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_lfrfid_protocols)

View File

@@ -0,0 +1,77 @@
#include <furi.c>
#include "../test.h"
#include <update_util/resources/manifest.h>
#define TAG "Manifest"
MU_TEST(manifest_type_test) {
mu_assert(ResourceManifestEntryTypeUnknown == 0, "ResourceManifestEntryTypeUnknown != 0\r\n");
mu_assert(ResourceManifestEntryTypeVersion == 1, "ResourceManifestEntryTypeVersion != 1\r\n");
mu_assert(
ResourceManifestEntryTypeTimestamp == 2, "ResourceManifestEntryTypeTimestamp != 2\r\n");
mu_assert(
ResourceManifestEntryTypeDirectory == 3, "ResourceManifestEntryTypeDirectory != 3\r\n");
mu_assert(ResourceManifestEntryTypeFile == 4, "ResourceManifestEntryTypeFile != 4\r\n");
}
MU_TEST(manifest_iteration_test) {
bool result = true;
size_t counters[5] = {0};
Storage* storage = furi_record_open(RECORD_STORAGE);
ResourceManifestReader* manifest_reader = resource_manifest_reader_alloc(storage);
do {
// Open manifest file
if(!resource_manifest_reader_open(manifest_reader, EXT_PATH("unit_tests/Manifest_test"))) {
result = false;
break;
}
// Iterate forward
ResourceManifestEntry* entry_ptr = NULL;
while((entry_ptr = resource_manifest_reader_next(manifest_reader))) {
FURI_LOG_D(TAG, "F:%u:%s", entry_ptr->type, furi_string_get_cstr(entry_ptr->name));
if(entry_ptr->type > 4) {
mu_fail("entry_ptr->type > 4\r\n");
result = false;
break;
}
counters[entry_ptr->type]++;
}
if(!result) break;
// Iterate backward
while((entry_ptr = resource_manifest_reader_previous(manifest_reader))) {
FURI_LOG_D(TAG, "B:%u:%s", entry_ptr->type, furi_string_get_cstr(entry_ptr->name));
if(entry_ptr->type > 4) {
mu_fail("entry_ptr->type > 4\r\n");
result = false;
break;
}
counters[entry_ptr->type]--;
}
} while(false);
resource_manifest_reader_free(manifest_reader);
furi_record_close(RECORD_STORAGE);
mu_assert(counters[ResourceManifestEntryTypeUnknown] == 0, "Unknown counter != 0\r\n");
mu_assert(counters[ResourceManifestEntryTypeVersion] == 0, "Version counter != 0\r\n");
mu_assert(counters[ResourceManifestEntryTypeTimestamp] == 0, "Timestamp counter != 0\r\n");
mu_assert(counters[ResourceManifestEntryTypeDirectory] == 0, "Directory counter != 0\r\n");
mu_assert(counters[ResourceManifestEntryTypeFile] == 0, "File counter != 0\r\n");
mu_assert(result, "Manifest forward iterate failed\r\n");
}
MU_TEST_SUITE(manifest_suite) {
MU_RUN_TEST(manifest_type_test);
MU_RUN_TEST(manifest_iteration_test);
}
int run_minunit_test_manifest(void) {
MU_RUN_SUITE(manifest_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_manifest)

View File

@@ -0,0 +1,661 @@
/*
* Copyright (c) 2012 David Siñuela Pastor, siu.4coders@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MINUNIT_MINUNIT_H
#define MINUNIT_MINUNIT_H
#ifdef __cplusplus
extern "C" {
#endif
#if defined(_WIN32)
#include <Windows.h>
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
#define __func__ __FUNCTION__
#endif
#elif defined(__unix__) || defined(__unix) || defined(unix) || \
(defined(__APPLE__) && defined(__MACH__))
/* Change POSIX C SOURCE version for pure c99 compilers */
#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 200112L
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200112L
#endif
#include <unistd.h> /* POSIX flags */
#include <time.h> /* clock_gettime(), time() */
#include <sys/time.h> /* gethrtime(), gettimeofday() */
#include <sys/resource.h>
#include <sys/times.h>
#include <string.h>
#if defined(__MACH__) && defined(__APPLE__)
#include <mach/mach.h>
#include <mach/mach_time.h>
#endif
#if __GNUC__ >= 5 && !defined(__STDC_VERSION__)
#define __func__ __extension__ __FUNCTION__
#endif
#else
// #error "Unable to define timers for an unknown OS."
#endif
#include <stdio.h>
#include <math.h>
/* Maximum length of last message */
#define MINUNIT_MESSAGE_LEN 1024
/* Accuracy with which floats are compared */
#define MINUNIT_EPSILON 1E-12
#include "minunit_vars_ex.h"
/* Test setup and teardown function pointers */
__attribute__((unused)) static void (*minunit_setup)(void) = NULL;
__attribute__((unused)) static void (*minunit_teardown)(void) = NULL;
void minunit_print_progress(void);
void minunit_print_fail(const char* error);
void minunit_printf_warning(const char* format, ...);
/* Definitions */
#define MU_TEST(method_name) static void method_name(void)
#define MU_TEST_1(method_name, arg_1) static void method_name(arg_1)
#define MU_TEST_SUITE(suite_name) static void suite_name(void)
#define MU__SAFE_BLOCK(block) \
do { \
block \
} while(0)
/* Run test suite and unset setup and teardown functions */
#define MU_RUN_SUITE(suite_name) \
MU__SAFE_BLOCK(suite_name(); minunit_setup = NULL; minunit_teardown = NULL;)
/* Configure setup and teardown functions */
#define MU_SUITE_CONFIGURE(setup_fun, teardown_fun) \
MU__SAFE_BLOCK(minunit_setup = setup_fun; minunit_teardown = teardown_fun;)
/* Test runner */
#define MU_RUN_TEST(test) \
MU__SAFE_BLOCK( \
if(minunit_real_timer == 0 && minunit_proc_timer == 0) { \
minunit_real_timer = mu_timer_real(); \
minunit_proc_timer = mu_timer_cpu(); \
} if(minunit_setup) (*minunit_setup)(); \
minunit_status = 0; \
printf(#test "()\r\n"); \
test(); \
minunit_run++; \
if(minunit_status) { \
minunit_fail++; \
minunit_print_fail(minunit_last_message); \
minunit_status = 0; \
} fflush(stdout); \
if(minunit_teardown)(*minunit_teardown)();)
#define MU_RUN_TEST_1(test, arg_1) \
MU__SAFE_BLOCK( \
if(minunit_real_timer == 0 && minunit_proc_timer == 0) { \
minunit_real_timer = mu_timer_real(); \
minunit_proc_timer = mu_timer_cpu(); \
} if(minunit_setup) (*minunit_setup)(); \
minunit_status = 0; \
printf(#test "(" #arg_1 ")\r\n"); \
test(arg_1); \
minunit_run++; \
if(minunit_status) { \
minunit_fail++; \
minunit_print_fail(minunit_last_message); \
minunit_status = 0; \
} fflush(stdout); \
if(minunit_teardown)(*minunit_teardown)();)
/* Report */
#define MU_REPORT() \
MU__SAFE_BLOCK(double minunit_end_real_timer; double minunit_end_proc_timer; printf( \
"\n\n%d tests, %d assertions, %d failures\n", \
minunit_run, \
minunit_assert, \
minunit_fail); \
minunit_end_real_timer = mu_timer_real(); \
minunit_end_proc_timer = mu_timer_cpu(); \
printf( \
"\nFinished in %.8f seconds (real) %.8f seconds (proc)\n\n", \
minunit_end_real_timer - minunit_real_timer, \
minunit_end_proc_timer - minunit_proc_timer);)
#define MU_EXIT_CODE minunit_fail
/* Warnings */
#define mu_warn(message) \
MU__SAFE_BLOCK(minunit_printf_warning("%s:%d: %s", __FILE__, __LINE__, message);)
/* Assertions */
#define mu_check(test) \
MU__SAFE_BLOCK( \
minunit_assert++; if(!(test)) { \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: %s", \
__func__, \
__FILE__, \
__LINE__, \
#test); \
minunit_status = 1; \
return; \
} else { minunit_print_progress(); })
#define mu_fail(message) \
MU__SAFE_BLOCK(minunit_assert++; snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: %s", \
__func__, \
__FILE__, \
__LINE__, \
message); \
minunit_status = 1; \
return;)
#define mu_assert(test, message) \
MU__SAFE_BLOCK( \
minunit_assert++; if(!(test)) { \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: %s", \
__func__, \
__FILE__, \
__LINE__, \
message); \
minunit_status = 1; \
return; \
} else { minunit_print_progress(); })
#define mu_assert_int_eq(expected, result) \
MU__SAFE_BLOCK( \
int minunit_tmp_e; int minunit_tmp_r; minunit_assert++; minunit_tmp_e = (expected); \
minunit_tmp_r = (result); \
if(minunit_tmp_e != minunit_tmp_r) { \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: %d expected but was %d", \
__func__, \
__FILE__, \
__LINE__, \
minunit_tmp_e, \
minunit_tmp_r); \
minunit_status = 1; \
return; \
} else { minunit_print_progress(); })
#define mu_assert_int_not_eq(expected, result) \
MU__SAFE_BLOCK( \
int minunit_tmp_e; int minunit_tmp_r; minunit_assert++; minunit_tmp_e = (expected); \
minunit_tmp_r = (result); \
if(minunit_tmp_e == minunit_tmp_r) { \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: expected different results but both were %d", \
__func__, \
__FILE__, \
__LINE__, \
minunit_tmp_e); \
minunit_status = 1; \
return; \
} else { minunit_print_progress(); })
#define mu_assert_int_greater_than(val, result) \
MU__SAFE_BLOCK( \
int minunit_tmp_e; int minunit_tmp_r; minunit_assert++; minunit_tmp_e = (val); \
minunit_tmp_r = (result); \
if(val >= minunit_tmp_r) { \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: %d <= %d", \
__func__, \
__FILE__, \
__LINE__, \
minunit_tmp_r, \
minunit_tmp_e); \
minunit_status = 1; \
return; \
} else { minunit_print_progress(); })
#define mu_assert_int_less_than(val, result) \
MU__SAFE_BLOCK( \
int minunit_tmp_e; int minunit_tmp_r; minunit_assert++; minunit_tmp_e = (val); \
minunit_tmp_r = (result); \
if(val <= minunit_tmp_r) { \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: %d >= %d", \
__func__, \
__FILE__, \
__LINE__, \
minunit_tmp_r, \
minunit_tmp_e); \
minunit_status = 1; \
return; \
} else { minunit_print_progress(); })
#define mu_assert_int_between(expected_lower, expected_upper, result) \
MU__SAFE_BLOCK( \
int minunit_tmp_e; int minunit_tmp_m; int minunit_tmp_r; minunit_assert++; \
minunit_tmp_e = (expected_lower); \
minunit_tmp_m = (expected_upper); \
minunit_tmp_r = (result); \
if(result < minunit_tmp_e || result > minunit_tmp_m) { \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: %d was not between (inclusive) %d and %d", \
__func__, \
__FILE__, \
__LINE__, \
minunit_tmp_e, \
minunit_tmp_r, \
minunit_tmp_m); \
minunit_status = 1; \
return; \
} else { minunit_print_progress(); })
#define mu_assert_int_in(expected, array_length, result) \
MU__SAFE_BLOCK( \
int minunit_tmp_r; minunit_assert++; minunit_tmp_r = (result); int t = 0; int i; \
for(i = 0; i < array_length; i++) { \
if(expected[i] == minunit_tmp_r) t = 1; \
} if(t == 0) { \
char tmp[500] = {0}; \
tmp[0] = '['; \
for(i = 0; i < array_length; i++) { \
sprintf(tmp + strlen(tmp), "%d, ", expected[i]); \
} \
int len = strlen(tmp); \
tmp[len - 2] = ']'; \
tmp[len - 1] = '\0'; \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: expected to be one of %s but was %d", \
__func__, \
__FILE__, \
__LINE__, \
tmp, \
minunit_tmp_r); \
minunit_status = 1; \
return; \
} else { minunit_print_progress(); })
#define mu_assert_double_eq(expected, result) \
MU__SAFE_BLOCK( \
double minunit_tmp_e; double minunit_tmp_r; minunit_assert++; minunit_tmp_e = (expected); \
minunit_tmp_r = (result); \
if(fabs(minunit_tmp_e - minunit_tmp_r) > (double)MINUNIT_EPSILON) { \
int minunit_significant_figures = 1 - log10(MINUNIT_EPSILON); \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: %.*g expected but was %.*g", \
__func__, \
__FILE__, \
__LINE__, \
minunit_significant_figures, \
minunit_tmp_e, \
minunit_significant_figures, \
minunit_tmp_r); \
minunit_status = 1; \
return; \
} else { minunit_print_progress(); })
#define mu_assert_double_greater_than(val, result) \
MU__SAFE_BLOCK( \
double minunit_tmp_e; double minunit_tmp_r; minunit_assert++; minunit_tmp_e = (val); \
minunit_tmp_r = (result); \
if(val >= minunit_tmp_r) { \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: %f <= %f", \
__func__, \
__FILE__, \
__LINE__, \
minunit_tmp_r, \
minunit_tmp_e); \
minunit_status = 1; \
return; \
} else { minunit_print_progress(); })
#define mu_assert_double_less_than(val, result) \
MU__SAFE_BLOCK( \
double minunit_tmp_e; double minunit_tmp_r; minunit_assert++; minunit_tmp_e = (val); \
minunit_tmp_r = (result); \
if(val <= minunit_tmp_r) { \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: %f >= %f", \
__func__, \
__FILE__, \
__LINE__, \
minunit_tmp_r, \
minunit_tmp_e); \
minunit_status = 1; \
return; \
} else { minunit_print_progress(); })
#define mu_assert_double_between(expected_lower, expected_upper, result) \
MU__SAFE_BLOCK( \
double minunit_tmp_e; double minunit_tmp_m; double minunit_tmp_r; minunit_assert++; \
minunit_tmp_e = (expected_lower); \
minunit_tmp_m = (expected_upper); \
minunit_tmp_r = (result); \
if(result < minunit_tmp_e || result > minunit_tmp_m) { \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: %f was not between (inclusive) %f and %f", \
__func__, \
__FILE__, \
__LINE__, \
minunit_tmp_e, \
minunit_tmp_r, \
minunit_tmp_m); \
minunit_status = 1; \
return; \
} else { minunit_print_progress(); })
#define mu_assert_string_eq(expected, result) \
MU__SAFE_BLOCK( \
const char* minunit_tmp_e = expected; const char* minunit_tmp_r = result; \
minunit_assert++; \
if(!minunit_tmp_e) { minunit_tmp_e = "<null pointer>"; } if(!minunit_tmp_r) { \
minunit_tmp_r = "<null pointer>"; \
} if(strcmp(minunit_tmp_e, minunit_tmp_r)) { \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: '%s' expected but was '%s'", \
__func__, \
__FILE__, \
__LINE__, \
minunit_tmp_e, \
minunit_tmp_r); \
minunit_status = 1; \
return; \
} else { minunit_print_progress(); })
#define mu_assert_mem_eq(expected, result, size) \
MU__SAFE_BLOCK( \
const void* minunit_tmp_e = expected; const void* minunit_tmp_r = result; \
minunit_assert++; \
if(memcmp(minunit_tmp_e, minunit_tmp_r, size)) { \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: mem not equal\r\n\tEXP RES", \
__func__, \
__FILE__, \
__LINE__); \
for(size_t __index = 0; __index < size; __index++) { \
if(strlen(minunit_last_message) > MINUNIT_MESSAGE_LEN - 20) break; \
uint8_t __e = ((uint8_t*)minunit_tmp_e)[__index]; \
uint8_t __r = ((uint8_t*)minunit_tmp_r)[__index]; \
snprintf( \
minunit_last_message + strlen(minunit_last_message), \
MINUNIT_MESSAGE_LEN - strlen(minunit_last_message), \
"\r\n\t%02X %s %02X", \
__e, \
((__e == __r) ? ".." : "!="), \
__r); \
} \
minunit_status = 1; \
return; \
} else { minunit_print_progress(); })
#define mu_assert_null(result) \
MU__SAFE_BLOCK( \
minunit_assert++; if(result == NULL) { minunit_print_progress(); } else { \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: Expected result was not NULL", \
__func__, \
__FILE__, \
__LINE__); \
minunit_status = 1; \
return; \
})
#define mu_assert_not_null(result) \
MU__SAFE_BLOCK( \
minunit_assert++; if(result != NULL) { minunit_print_progress(); } else { \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: Expected result was not NULL", \
__func__, \
__FILE__, \
__LINE__); \
minunit_status = 1; \
return; \
})
#define mu_assert_pointers_eq(pointer1, pointer2) \
MU__SAFE_BLOCK( \
minunit_assert++; if(pointer1 == pointer2) { minunit_print_progress(); } else { \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: Expected the pointers to point to the same memory location", \
__func__, \
__FILE__, \
__LINE__); \
minunit_status = 1; \
return; \
})
#define mu_assert_pointers_not_eq(pointer1, pointer2) \
MU__SAFE_BLOCK( \
minunit_assert++; if(pointer1 != pointer2) { minunit_print_progress(); } else { \
snprintf( \
minunit_last_message, \
MINUNIT_MESSAGE_LEN, \
"%s failed:\r\n\t%s:%d: Expected the pointers to point to the same memory location", \
__func__, \
__FILE__, \
__LINE__); \
minunit_status = 1; \
return; \
})
/*
* The following two functions were written by David Robert Nadeau
* from http://NadeauSoftware.com/ and distributed under the
* Creative Commons Attribution 3.0 Unported License
*/
/**
* Returns the real time, in seconds, or -1.0 if an error occurred.
*
* Time is measured since an arbitrary and OS-dependent start time.
* The returned real time is only useful for computing an elapsed time
* between two calls to this function.
*/
__attribute__((unused)) static double mu_timer_real(void) {
#if defined(_WIN32)
/* Windows 2000 and later. ---------------------------------- */
LARGE_INTEGER Time;
LARGE_INTEGER Frequency;
QueryPerformanceFrequency(&Frequency);
QueryPerformanceCounter(&Time);
Time.QuadPart *= 1000000;
Time.QuadPart /= Frequency.QuadPart;
return (double)Time.QuadPart / 1000000.0;
#elif(defined(__hpux) || defined(hpux)) || \
((defined(__sun__) || defined(__sun) || defined(sun)) && \
(defined(__SVR4) || defined(__svr4__)))
/* HP-UX, Solaris. ------------------------------------------ */
return (double)gethrtime() / 1000000000.0;
#elif defined(__MACH__) && defined(__APPLE__)
/* OSX. ----------------------------------------------------- */
static double timeConvert = 0.0;
if(timeConvert == 0.0) {
mach_timebase_info_data_t timeBase;
(void)mach_timebase_info(&timeBase);
timeConvert = (double)timeBase.numer / (double)timeBase.denom / 1000000000.0;
}
return (double)mach_absolute_time() * timeConvert;
#elif defined(_POSIX_VERSION)
/* POSIX. --------------------------------------------------- */
struct timeval tm;
#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
{
struct timespec ts;
#if defined(CLOCK_MONOTONIC_PRECISE)
/* BSD. --------------------------------------------- */
const clockid_t id = CLOCK_MONOTONIC_PRECISE;
#elif defined(CLOCK_MONOTONIC_RAW)
/* Linux. ------------------------------------------- */
const clockid_t id = CLOCK_MONOTONIC_RAW;
#elif defined(CLOCK_HIGHRES)
/* Solaris. ----------------------------------------- */
const clockid_t id = CLOCK_HIGHRES;
#elif defined(CLOCK_MONOTONIC)
/* AIX, BSD, Linux, POSIX, Solaris. ----------------- */
const clockid_t id = CLOCK_MONOTONIC;
#elif defined(CLOCK_REALTIME)
/* AIX, BSD, HP-UX, Linux, POSIX. ------------------- */
const clockid_t id = CLOCK_REALTIME;
#else
const clockid_t id = (clockid_t)-1; /* Unknown. */
#endif /* CLOCK_* */
if(id != (clockid_t)-1 && clock_gettime(id, &ts) != -1)
return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0;
/* Fall thru. */
}
#endif /* _POSIX_TIMERS */
/* AIX, BSD, Cygwin, HP-UX, Linux, OSX, POSIX, Solaris. ----- */
gettimeofday(&tm, NULL);
return (double)tm.tv_sec + (double)tm.tv_usec / 1000000.0;
#else
return -1.0; /* Failed. */
#endif
}
/**
* Returns the amount of CPU time used by the current process,
* in seconds, or -1.0 if an error occurred.
*/
__attribute__((unused)) static double mu_timer_cpu(void) {
#if defined(_WIN32)
/* Windows -------------------------------------------------- */
FILETIME createTime;
FILETIME exitTime;
FILETIME kernelTime;
FILETIME userTime;
/* This approach has a resolution of 1/64 second. Unfortunately, Windows' API does not offer better */
if(GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime) != 0) {
ULARGE_INTEGER userSystemTime;
memcpy(&userSystemTime, &userTime, sizeof(ULARGE_INTEGER));
return (double)userSystemTime.QuadPart / 10000000.0;
}
#elif defined(__unix__) || defined(__unix) || defined(unix) || \
(defined(__APPLE__) && defined(__MACH__))
/* AIX, BSD, Cygwin, HP-UX, Linux, OSX, and Solaris --------- */
#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
/* Prefer high-res POSIX timers, when available. */
{
clockid_t id;
struct timespec ts;
#if _POSIX_CPUTIME > 0
/* Clock ids vary by OS. Query the id, if possible. */
if(clock_getcpuclockid(0, &id) == -1)
#endif
#if defined(CLOCK_PROCESS_CPUTIME_ID)
/* Use known clock id for AIX, Linux, or Solaris. */
id = CLOCK_PROCESS_CPUTIME_ID;
#elif defined(CLOCK_VIRTUAL)
/* Use known clock id for BSD or HP-UX. */
id = CLOCK_VIRTUAL;
#else
id = (clockid_t)-1;
#endif
if(id != (clockid_t)-1 && clock_gettime(id, &ts) != -1)
return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0;
}
#endif
#if defined(RUSAGE_SELF)
{
struct rusage rusage;
if(getrusage(RUSAGE_SELF, &rusage) != -1)
return (double)rusage.ru_utime.tv_sec + (double)rusage.ru_utime.tv_usec / 1000000.0;
}
#endif
#if defined(_SC_CLK_TCK)
{
const double ticks = (double)sysconf(_SC_CLK_TCK);
struct tms tms;
if(times(&tms) != (clock_t)-1) return (double)tms.tms_utime / ticks;
}
#endif
#if defined(CLOCKS_PER_SEC)
{
clock_t cl = clock();
if(cl != (clock_t)-1) return (double)cl / (double)CLOCKS_PER_SEC;
}
#endif
#endif
return -1; /* Failed. */
}
#ifdef __cplusplus
}
#endif
#endif /* MINUNIT_MINUNIT_H */

View File

@@ -0,0 +1,15 @@
#pragma once
#include "minunit.h"
/* Misc. counters */
int minunit_run = 0;
int minunit_assert = 0;
int minunit_fail = 0;
int minunit_status = 0;
/* Timers */
double minunit_real_timer = 0;
double minunit_proc_timer = 0;
/* Last message */
char minunit_last_message[MINUNIT_MESSAGE_LEN];

View File

@@ -0,0 +1,15 @@
#pragma once
#include "minunit.h"
/* Misc. counters */
extern int minunit_run;
extern int minunit_assert;
extern int minunit_fail;
extern int minunit_status;
/* Timers */
extern double minunit_real_timer;
extern double minunit_proc_timer;
/* Last message */
extern char minunit_last_message[MINUNIT_MESSAGE_LEN];

View File

@@ -0,0 +1,824 @@
#include <furi.h>
#include <furi_hal.h>
#include <storage/storage.h>
#include <nfc/nfc_device.h>
#include <nfc/helpers/nfc_data_generator.h>
#include <nfc/nfc_poller.h>
#include <nfc/nfc_listener.h>
#include <nfc/protocols/iso14443_3a/iso14443_3a.h>
#include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
#include <nfc/protocols/iso14443_3a/iso14443_3a_poller_sync.h>
#include <nfc/protocols/mf_ultralight/mf_ultralight.h>
#include <nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h>
#include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
#include <nfc/protocols/mf_classic/mf_classic_poller.h>
#include <nfc/protocols/iso15693_3/iso15693_3_poller.h>
#include <nfc/protocols/slix/slix.h>
#include <nfc/protocols/slix/slix_i.h>
#include <nfc/protocols/slix/slix_poller.h>
#include <nfc/protocols/slix/slix_poller_i.h>
#include <nfc/nfc_poller.h>
#include <toolbox/keys_dict.h>
#include <nfc/nfc.h>
#include "../test.h"
#define TAG "NfcTest"
#define NFC_TEST_NFC_DEV_PATH EXT_PATH("unit_tests/nfc/nfc_device_test.nfc")
#define NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH EXT_PATH("unit_tests/mf_dict.nfc")
#define NFC_TEST_FLAG_WORKER_DONE (1)
typedef enum {
NfcTestMfClassicSendFrameTestStateAuth,
NfcTestMfClassicSendFrameTestStateReadBlock,
NfcTestMfClassicSendFrameTestStateFail,
NfcTestMfClassicSendFrameTestStateSuccess,
} NfcTestMfClassicSendFrameTestState;
typedef struct {
NfcTestMfClassicSendFrameTestState state;
BitBuffer* tx_buf;
BitBuffer* rx_buf;
FuriThreadId thread_id;
} NfcTestMfClassicSendFrameTest;
typedef enum {
NfcTestSlixPollerSetPasswordStateGetRandomNumber,
NfcTestSlixPollerSetPasswordStateSetPassword,
} NfcTestSlixPollerSetPasswordState;
typedef struct {
FuriThreadId thread_id;
NfcTestSlixPollerSetPasswordState state;
SlixRandomNumber random_number;
SlixPassword password;
SlixError error;
} NfcTestSlixPollerSetPasswordContext;
typedef struct {
Storage* storage;
} NfcTest;
static NfcTest* nfc_test = NULL;
static void nfc_test_alloc(void) {
nfc_test = malloc(sizeof(NfcTest));
nfc_test->storage = furi_record_open(RECORD_STORAGE);
}
static void nfc_test_free(void) {
furi_check(nfc_test);
furi_record_close(RECORD_STORAGE);
free(nfc_test);
nfc_test = NULL;
}
static void nfc_test_save_and_load(NfcDevice* nfc_device_ref) {
NfcDevice* nfc_device_dut = nfc_device_alloc();
mu_assert(
nfc_device_save(nfc_device_ref, NFC_TEST_NFC_DEV_PATH), "nfc_device_save() failed\r\n");
mu_assert(
nfc_device_load(nfc_device_dut, NFC_TEST_NFC_DEV_PATH), "nfc_device_load() failed\r\n");
mu_assert(
nfc_device_is_equal(nfc_device_ref, nfc_device_dut),
"nfc_device_data_dut != nfc_device_data_ref\r\n");
mu_assert(
storage_simply_remove(nfc_test->storage, NFC_TEST_NFC_DEV_PATH),
"storage_simply_remove() failed\r\n");
nfc_device_free(nfc_device_dut);
}
static void iso14443_3a_file_test(uint8_t uid_len) {
NfcDevice* nfc_device = nfc_device_alloc();
Iso14443_3aData* data = iso14443_3a_alloc();
data->uid_len = uid_len;
furi_hal_random_fill_buf(data->uid, uid_len);
furi_hal_random_fill_buf(data->atqa, sizeof(data->atqa));
furi_hal_random_fill_buf(&data->sak, 1);
nfc_device_set_data(nfc_device, NfcProtocolIso14443_3a, data);
nfc_test_save_and_load(nfc_device);
iso14443_3a_free(data);
nfc_device_free(nfc_device);
}
static void nfc_file_test_with_generator(NfcDataGeneratorType type) {
NfcDevice* nfc_device_ref = nfc_device_alloc();
nfc_data_generator_fill_data(type, nfc_device_ref);
nfc_test_save_and_load(nfc_device_ref);
nfc_device_free(nfc_device_ref);
}
MU_TEST(iso14443_3a_4b_file_test) {
iso14443_3a_file_test(4);
}
MU_TEST(iso14443_3a_7b_file_test) {
iso14443_3a_file_test(7);
}
MU_TEST(mf_ultralight_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeMfUltralight);
}
MU_TEST(mf_ultralight_ev1_11_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_11);
}
MU_TEST(mf_ultralight_ev1_h11_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_H11);
}
MU_TEST(mf_ultralight_ev1_21_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_21);
}
MU_TEST(mf_ultralight_ev1_h21_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeMfUltralightEV1_H21);
}
MU_TEST(mf_ultralight_ntag_203_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeNTAG203);
}
MU_TEST(mf_ultralight_ntag_213_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeNTAG213);
}
MU_TEST(mf_ultralight_ntag_215_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeNTAG215);
}
MU_TEST(mf_ultralight_ntag_216_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeNTAG216);
}
MU_TEST(mf_ultralight_ntag_i2c_1k_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeNTAGI2C1k);
}
MU_TEST(mf_ultralight_ntag_i2c_2k_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeNTAGI2C2k);
}
MU_TEST(mf_ultralight_ntag_i2c_plus_1k_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus1k);
}
MU_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeNTAGI2CPlus2k);
}
MU_TEST(mf_classic_mini_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeMfClassicMini);
}
MU_TEST(mf_classic_1k_4b_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeMfClassic1k_4b);
}
MU_TEST(mf_classic_1k_7b_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeMfClassic1k_7b);
}
MU_TEST(mf_classic_4k_4b_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeMfClassic4k_4b);
}
MU_TEST(mf_classic_4k_7b_file_test) {
nfc_file_test_with_generator(NfcDataGeneratorTypeMfClassic4k_7b);
}
MU_TEST(iso14443_3a_reader) {
Nfc* poller = nfc_alloc();
Nfc* listener = nfc_alloc();
Iso14443_3aData iso14443_3a_listener_data = {
.uid_len = 7,
.uid = {0x04, 0x51, 0x5C, 0xFA, 0x6F, 0x73, 0x81},
.atqa = {0x44, 0x00},
.sak = 0x00,
};
NfcListener* iso3_listener =
nfc_listener_alloc(listener, NfcProtocolIso14443_3a, &iso14443_3a_listener_data);
nfc_listener_start(iso3_listener, NULL, NULL);
Iso14443_3aData iso14443_3a_poller_data = {};
mu_assert(
iso14443_3a_poller_sync_read(poller, &iso14443_3a_poller_data) == Iso14443_3aErrorNone,
"iso14443_3a_poller_sync_read() failed");
nfc_listener_stop(iso3_listener);
mu_assert(
iso14443_3a_is_equal(&iso14443_3a_poller_data, &iso14443_3a_listener_data),
"Data not matches");
nfc_listener_free(iso3_listener);
nfc_free(listener);
nfc_free(poller);
}
static void mf_ultralight_reader_test(const char* path) {
FURI_LOG_I(TAG, "Testing file: %s", path);
Nfc* poller = nfc_alloc();
Nfc* listener = nfc_alloc();
NfcDevice* nfc_device = nfc_device_alloc();
mu_assert(nfc_device_load(nfc_device, path), "nfc_device_load() failed\r\n");
MfUltralightData* data =
(MfUltralightData*)nfc_device_get_data(nfc_device, NfcProtocolMfUltralight);
uint32_t features = mf_ultralight_get_feature_support_set(data->type);
bool pwd_supported =
mf_ultralight_support_feature(features, MfUltralightFeatureSupportPasswordAuth);
uint8_t pwd_num = mf_ultralight_get_pwd_page_num(data->type);
const uint8_t zero_pwd[4] = {0, 0, 0, 0};
if(pwd_supported && !memcmp(data->page[pwd_num].data, zero_pwd, sizeof(zero_pwd))) {
data->pages_read -= 2;
}
NfcListener* mfu_listener = nfc_listener_alloc(listener, NfcProtocolMfUltralight, data);
nfc_listener_start(mfu_listener, NULL, NULL);
MfUltralightData* mfu_data = mf_ultralight_alloc();
MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data);
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed");
nfc_listener_stop(mfu_listener);
nfc_listener_free(mfu_listener);
mu_assert(
mf_ultralight_is_equal(mfu_data, nfc_device_get_data(nfc_device, NfcProtocolMfUltralight)),
"Data not matches");
mf_ultralight_free(mfu_data);
nfc_device_free(nfc_device);
nfc_free(listener);
nfc_free(poller);
}
MU_TEST(mf_ultralight_11_reader) {
mf_ultralight_reader_test(EXT_PATH("unit_tests/nfc/Ultralight_11.nfc"));
}
MU_TEST(mf_ultralight_21_reader) {
mf_ultralight_reader_test(EXT_PATH("unit_tests/nfc/Ultralight_21.nfc"));
}
MU_TEST(ntag_215_reader) {
mf_ultralight_reader_test(EXT_PATH("unit_tests/nfc/Ntag215.nfc"));
}
MU_TEST(ntag_216_reader) {
mf_ultralight_reader_test(EXT_PATH("unit_tests/nfc/Ntag216.nfc"));
}
MU_TEST(ntag_213_locked_reader) {
FURI_LOG_I(TAG, "Testing Ntag215 locked file");
Nfc* poller = nfc_alloc();
Nfc* listener = nfc_alloc();
NfcDeviceData* nfc_device = nfc_device_alloc();
mu_assert(
nfc_device_load(nfc_device, EXT_PATH("unit_tests/nfc/Ntag213_locked.nfc")),
"nfc_device_load() failed\r\n");
NfcListener* mfu_listener = nfc_listener_alloc(
listener,
NfcProtocolMfUltralight,
nfc_device_get_data(nfc_device, NfcProtocolMfUltralight));
nfc_listener_start(mfu_listener, NULL, NULL);
MfUltralightData* mfu_data = mf_ultralight_alloc();
MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data);
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed");
nfc_listener_stop(mfu_listener);
nfc_listener_free(mfu_listener);
MfUltralightConfigPages* config = NULL;
const MfUltralightData* mfu_ref_data =
nfc_device_get_data(nfc_device, NfcProtocolMfUltralight);
mu_assert(
mf_ultralight_get_config_page(mfu_ref_data, &config),
"mf_ultralight_get_config_page() failed");
uint16_t pages_locked = config->auth0;
mu_assert(mfu_data->pages_read == pages_locked, "Unexpected pages read");
mf_ultralight_free(mfu_data);
nfc_device_free(nfc_device);
nfc_free(listener);
nfc_free(poller);
}
static void mf_ultralight_write(void) {
Nfc* poller = nfc_alloc();
Nfc* listener = nfc_alloc();
NfcDevice* nfc_device = nfc_device_alloc();
nfc_data_generator_fill_data(NfcDataGeneratorTypeMfUltralightEV1_21, nfc_device);
NfcListener* mfu_listener = nfc_listener_alloc(
listener,
NfcProtocolMfUltralight,
nfc_device_get_data(nfc_device, NfcProtocolMfUltralight));
nfc_listener_start(mfu_listener, NULL, NULL);
MfUltralightData* mfu_data = mf_ultralight_alloc();
// Initial read
MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data);
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed");
mu_assert(
mf_ultralight_is_equal(mfu_data, nfc_device_get_data(nfc_device, NfcProtocolMfUltralight)),
"Data not matches");
// Write random data
for(size_t i = 5; i < 15; i++) {
MfUltralightPage page = {};
FURI_LOG_D(TAG, "Writing page %d", i);
furi_hal_random_fill_buf(page.data, sizeof(MfUltralightPage));
mfu_data->page[i] = page;
error = mf_ultralight_poller_sync_write_page(poller, i, &page);
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_write_page() failed");
}
// Verification read
error = mf_ultralight_poller_sync_read_card(poller, mfu_data);
mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed");
nfc_listener_stop(mfu_listener);
const MfUltralightData* mfu_listener_data =
nfc_listener_get_data(mfu_listener, NfcProtocolMfUltralight);
mu_assert(mf_ultralight_is_equal(mfu_data, mfu_listener_data), "Data not matches");
nfc_listener_free(mfu_listener);
mf_ultralight_free(mfu_data);
nfc_device_free(nfc_device);
nfc_free(listener);
nfc_free(poller);
}
static void mf_classic_reader(void) {
Nfc* poller = nfc_alloc();
Nfc* listener = nfc_alloc();
NfcDevice* nfc_device = nfc_device_alloc();
nfc_data_generator_fill_data(NfcDataGeneratorTypeMfClassic4k_7b, nfc_device);
NfcListener* mfc_listener = nfc_listener_alloc(
listener, NfcProtocolMfClassic, nfc_device_get_data(nfc_device, NfcProtocolMfClassic));
nfc_listener_start(mfc_listener, NULL, NULL);
MfClassicBlock block = {};
MfClassicKey key = {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
mf_classic_poller_sync_read_block(poller, 0, &key, MfClassicKeyTypeA, &block);
nfc_listener_stop(mfc_listener);
nfc_listener_free(mfc_listener);
const MfClassicData* mfc_data = nfc_device_get_data(nfc_device, NfcProtocolMfClassic);
mu_assert(memcmp(&mfc_data->block[0], &block, sizeof(MfClassicBlock)) == 0, "Data mismatch");
nfc_device_free(nfc_device);
nfc_free(listener);
nfc_free(poller);
}
static void mf_classic_write(void) {
Nfc* poller = nfc_alloc();
Nfc* listener = nfc_alloc();
NfcDevice* nfc_device = nfc_device_alloc();
nfc_data_generator_fill_data(NfcDataGeneratorTypeMfClassic4k_7b, nfc_device);
NfcListener* mfc_listener = nfc_listener_alloc(
listener, NfcProtocolMfClassic, nfc_device_get_data(nfc_device, NfcProtocolMfClassic));
nfc_listener_start(mfc_listener, NULL, NULL);
MfClassicBlock block_write = {};
MfClassicBlock block_read = {};
furi_hal_random_fill_buf(block_write.data, sizeof(MfClassicBlock));
MfClassicKey key = {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
mf_classic_poller_sync_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write);
mf_classic_poller_sync_read_block(poller, 1, &key, MfClassicKeyTypeA, &block_read);
nfc_listener_stop(mfc_listener);
nfc_listener_free(mfc_listener);
mu_assert(memcmp(&block_read, &block_write, sizeof(MfClassicBlock)) == 0, "Data mismatch");
nfc_device_free(nfc_device);
nfc_free(listener);
nfc_free(poller);
}
static void mf_classic_value_block(void) {
Nfc* poller = nfc_alloc();
Nfc* listener = nfc_alloc();
NfcDevice* nfc_device = nfc_device_alloc();
nfc_data_generator_fill_data(NfcDataGeneratorTypeMfClassic4k_7b, nfc_device);
NfcListener* mfc_listener = nfc_listener_alloc(
listener, NfcProtocolMfClassic, nfc_device_get_data(nfc_device, NfcProtocolMfClassic));
nfc_listener_start(mfc_listener, NULL, NULL);
MfClassicKey key = {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
int32_t value = 228;
MfClassicBlock block_write = {};
mf_classic_value_to_block(value, 1, &block_write);
MfClassicError error = MfClassicErrorNone;
error = mf_classic_poller_sync_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write);
mu_assert(error == MfClassicErrorNone, "Write failed");
int32_t data = 200;
int32_t new_value = 0;
error =
mf_classic_poller_sync_change_value(poller, 1, &key, MfClassicKeyTypeA, data, &new_value);
mu_assert(error == MfClassicErrorNone, "Value increment failed");
mu_assert(new_value == value + data, "Value not match");
error =
mf_classic_poller_sync_change_value(poller, 1, &key, MfClassicKeyTypeA, -data, &new_value);
mu_assert(error == MfClassicErrorNone, "Value decrement failed");
mu_assert(new_value == value, "Value not match");
nfc_listener_stop(mfc_listener);
nfc_listener_free(mfc_listener);
nfc_device_free(nfc_device);
nfc_free(listener);
nfc_free(poller);
}
NfcCommand mf_classic_poller_send_frame_callback(NfcGenericEventEx event, void* context) {
furi_check(event.poller);
furi_check(event.parent_event_data);
furi_check(context);
NfcCommand command = NfcCommandContinue;
MfClassicPoller* instance = event.poller;
NfcTestMfClassicSendFrameTest* frame_test = context;
Iso14443_3aPollerEvent* iso3_event = event.parent_event_data;
MfClassicError error = MfClassicErrorNone;
if(iso3_event->type == Iso14443_3aPollerEventTypeReady) {
if(frame_test->state == NfcTestMfClassicSendFrameTestStateAuth) {
MfClassicKey key = {
.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
};
error = mf_classic_poller_auth(instance, 0, &key, MfClassicKeyTypeA, NULL);
frame_test->state = (error == MfClassicErrorNone) ?
NfcTestMfClassicSendFrameTestStateReadBlock :
NfcTestMfClassicSendFrameTestStateFail;
} else if(frame_test->state == NfcTestMfClassicSendFrameTestStateReadBlock) {
do {
const uint8_t read_block_cmd[] = {
0x30,
0x01,
0x8b,
0xb9,
};
bit_buffer_copy_bytes(frame_test->tx_buf, read_block_cmd, sizeof(read_block_cmd));
error = mf_classic_poller_send_encrypted_frame(
instance, frame_test->tx_buf, frame_test->rx_buf, 200000);
if(error != MfClassicErrorNone) break;
if(bit_buffer_get_size_bytes(frame_test->rx_buf) != 18) {
error = MfClassicErrorProtocol;
break;
}
const uint8_t* rx_data = bit_buffer_get_data(frame_test->rx_buf);
const uint8_t rx_data_ref[16] = {0};
if(memcmp(rx_data, rx_data_ref, sizeof(rx_data_ref)) != 0) {
error = MfClassicErrorProtocol;
break;
}
} while(false);
frame_test->state = (error == MfClassicErrorNone) ?
NfcTestMfClassicSendFrameTestStateSuccess :
NfcTestMfClassicSendFrameTestStateFail;
} else if(frame_test->state == NfcTestMfClassicSendFrameTestStateSuccess) {
command = NfcCommandStop;
} else if(frame_test->state == NfcTestMfClassicSendFrameTestStateFail) {
command = NfcCommandStop;
}
} else {
frame_test->state = NfcTestMfClassicSendFrameTestStateFail;
command = NfcCommandStop;
}
if(command == NfcCommandStop) {
furi_thread_flags_set(frame_test->thread_id, NFC_TEST_FLAG_WORKER_DONE);
}
return command;
}
MU_TEST(mf_classic_send_frame_test) {
Nfc* poller = nfc_alloc();
Nfc* listener = nfc_alloc();
NfcDevice* nfc_device = nfc_device_alloc();
nfc_data_generator_fill_data(NfcDataGeneratorTypeMfClassic4k_7b, nfc_device);
NfcListener* mfc_listener = nfc_listener_alloc(
listener, NfcProtocolMfClassic, nfc_device_get_data(nfc_device, NfcProtocolMfClassic));
nfc_listener_start(mfc_listener, NULL, NULL);
NfcPoller* mfc_poller = nfc_poller_alloc(poller, NfcProtocolMfClassic);
NfcTestMfClassicSendFrameTest context = {
.state = NfcTestMfClassicSendFrameTestStateAuth,
.thread_id = furi_thread_get_current_id(),
.tx_buf = bit_buffer_alloc(32),
.rx_buf = bit_buffer_alloc(32),
};
nfc_poller_start_ex(mfc_poller, mf_classic_poller_send_frame_callback, &context);
uint32_t flag =
furi_thread_flags_wait(NFC_TEST_FLAG_WORKER_DONE, FuriFlagWaitAny, FuriWaitForever);
mu_assert(flag == NFC_TEST_FLAG_WORKER_DONE, "Wrong thread flag");
nfc_poller_stop(mfc_poller);
nfc_poller_free(mfc_poller);
mu_assert(
context.state == NfcTestMfClassicSendFrameTestStateSuccess, "Wrong test state at the end");
bit_buffer_free(context.tx_buf);
bit_buffer_free(context.rx_buf);
nfc_listener_stop(mfc_listener);
nfc_listener_free(mfc_listener);
nfc_device_free(nfc_device);
nfc_free(listener);
nfc_free(poller);
}
MU_TEST(mf_classic_dict_test) {
Storage* storage = furi_record_open(RECORD_STORAGE);
if(storage_common_stat(storage, NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, NULL) == FSE_OK) {
mu_assert(
storage_simply_remove(storage, NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH),
"Remove test dict failed");
}
KeysDict* dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
mu_assert(dict != NULL, "keys_dict_alloc() failed");
size_t dict_keys_total = keys_dict_get_total_keys(dict);
mu_assert(dict_keys_total == 0, "keys_dict_keys_total() failed");
const uint32_t test_key_num = 30;
MfClassicKey* key_arr_ref = malloc(test_key_num * sizeof(MfClassicKey));
for(size_t i = 0; i < test_key_num; i++) {
furi_hal_random_fill_buf(key_arr_ref[i].data, sizeof(MfClassicKey));
mu_assert(
keys_dict_add_key(dict, key_arr_ref[i].data, sizeof(MfClassicKey)), "add key failed");
size_t dict_keys_total = keys_dict_get_total_keys(dict);
mu_assert(dict_keys_total == (i + 1), "keys_dict_keys_total() failed");
}
keys_dict_free(dict);
dict = keys_dict_alloc(
NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey));
mu_assert(dict != NULL, "keys_dict_alloc() failed");
dict_keys_total = keys_dict_get_total_keys(dict);
mu_assert(dict_keys_total == test_key_num, "keys_dict_keys_total() failed");
MfClassicKey key_dut = {};
size_t key_idx = 0;
while(keys_dict_get_next_key(dict, key_dut.data, sizeof(MfClassicKey))) {
mu_assert(
memcmp(key_arr_ref[key_idx].data, key_dut.data, sizeof(MfClassicKey)) == 0,
"Loaded key data mismatch");
key_idx++;
}
uint32_t delete_keys_idx[] = {1, 3, 9, 11, 19, 27};
for(size_t i = 0; i < COUNT_OF(delete_keys_idx); i++) {
MfClassicKey* key = &key_arr_ref[delete_keys_idx[i]];
mu_assert(
keys_dict_is_key_present(dict, key->data, sizeof(MfClassicKey)),
"keys_dict_is_key_present() failed");
mu_assert(
keys_dict_delete_key(dict, key->data, sizeof(MfClassicKey)),
"keys_dict_delete_key() failed");
}
dict_keys_total = keys_dict_get_total_keys(dict);
mu_assert(
dict_keys_total == test_key_num - COUNT_OF(delete_keys_idx),
"keys_dict_keys_total() failed");
keys_dict_free(dict);
free(key_arr_ref);
mu_assert(
storage_simply_remove(storage, NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH),
"Remove test dict failed");
}
MU_TEST(slix_file_with_capabilities_test) {
NfcDevice* nfc_device_missed_cap = nfc_device_alloc();
mu_assert(
nfc_device_load(nfc_device_missed_cap, EXT_PATH("unit_tests/nfc/Slix_cap_missed.nfc")),
"nfc_device_load() failed\r\n");
NfcDevice* nfc_device_default_cap = nfc_device_alloc();
mu_assert(
nfc_device_load(nfc_device_default_cap, EXT_PATH("unit_tests/nfc/Slix_cap_default.nfc")),
"nfc_device_load() failed\r\n");
mu_assert(
nfc_device_is_equal(nfc_device_missed_cap, nfc_device_default_cap),
"nfc_device_is_equal() failed\r\n");
nfc_device_free(nfc_device_default_cap);
nfc_device_free(nfc_device_missed_cap);
}
NfcCommand slix_poller_set_password_callback(NfcGenericEventEx event, void* context) {
furi_check(event.poller);
furi_check(event.parent_event_data);
furi_check(context);
NfcCommand command = NfcCommandContinue;
Iso15693_3PollerEvent* iso15_event = event.parent_event_data;
SlixPoller* poller = event.poller;
NfcTestSlixPollerSetPasswordContext* slix_ctx = context;
if(iso15_event->type == Iso15693_3PollerEventTypeReady) {
iso15693_3_copy(
poller->data->iso15693_3_data, iso15693_3_poller_get_data(poller->iso15693_3_poller));
if(slix_ctx->state == NfcTestSlixPollerSetPasswordStateGetRandomNumber) {
slix_ctx->error = slix_poller_get_random_number(poller, &slix_ctx->random_number);
if(slix_ctx->error != SlixErrorNone) {
furi_thread_flags_set(slix_ctx->thread_id, NFC_TEST_FLAG_WORKER_DONE);
command = NfcCommandStop;
} else {
slix_ctx->state = NfcTestSlixPollerSetPasswordStateSetPassword;
}
} else if(slix_ctx->state == NfcTestSlixPollerSetPasswordStateSetPassword) {
slix_ctx->error = slix_poller_set_password(
poller, SlixPasswordTypeRead, slix_ctx->password, slix_ctx->random_number);
furi_thread_flags_set(slix_ctx->thread_id, NFC_TEST_FLAG_WORKER_DONE);
command = NfcCommandStop;
}
} else {
slix_ctx->error = slix_process_iso15693_3_error(iso15_event->data->error);
furi_thread_flags_set(slix_ctx->thread_id, NFC_TEST_FLAG_WORKER_DONE);
command = NfcCommandStop;
}
return command;
}
static void slix_set_password_test(const char* file_path, SlixPassword pass, bool correct_pass) {
FURI_LOG_I(TAG, "Testing file: %s", file_path);
Nfc* poller = nfc_alloc();
Nfc* listener = nfc_alloc();
NfcDevice* nfc_device = nfc_device_alloc();
mu_assert(nfc_device_load(nfc_device, file_path), "nfc_device_load() failed\r\n");
const SlixData* slix_data = nfc_device_get_data(nfc_device, NfcProtocolSlix);
NfcListener* slix_listener = nfc_listener_alloc(listener, NfcProtocolSlix, slix_data);
nfc_listener_start(slix_listener, NULL, NULL);
SlixCapabilities slix_capabilities = slix_data->capabilities;
NfcPoller* slix_poller = nfc_poller_alloc(poller, NfcProtocolSlix);
NfcTestSlixPollerSetPasswordContext slix_poller_context = {
.thread_id = furi_thread_get_current_id(),
.state = NfcTestSlixPollerSetPasswordStateGetRandomNumber,
.password = pass,
.error = SlixErrorNone,
};
nfc_poller_start_ex(slix_poller, slix_poller_set_password_callback, &slix_poller_context);
uint32_t flag =
furi_thread_flags_wait(NFC_TEST_FLAG_WORKER_DONE, FuriFlagWaitAny, FuriWaitForever);
mu_assert(flag == NFC_TEST_FLAG_WORKER_DONE, "Wrong thread flag\r\n");
nfc_poller_stop(slix_poller);
nfc_poller_free(slix_poller);
nfc_listener_stop(slix_listener);
nfc_listener_free(slix_listener);
mu_assert(
slix_poller_context.state == NfcTestSlixPollerSetPasswordStateSetPassword,
"Poller failed before setting password\r\n");
if((slix_capabilities == SlixCapabilitiesAcceptAllPasswords) || (correct_pass)) {
mu_assert(slix_poller_context.error == SlixErrorNone, "Failed to set password\r\n");
} else {
mu_assert(
slix_poller_context.error == SlixErrorTimeout,
"Must have received SlixErrorTimeout\r\n");
}
nfc_device_free(nfc_device);
nfc_free(listener);
nfc_free(poller);
}
MU_TEST(slix_set_password_default_cap_correct_pass) {
slix_set_password_test(EXT_PATH("unit_tests/nfc/Slix_cap_default.nfc"), 0x00000000, true);
}
MU_TEST(slix_set_password_default_cap_incorrect_pass) {
slix_set_password_test(EXT_PATH("unit_tests/nfc/Slix_cap_default.nfc"), 0x12341234, false);
}
MU_TEST(slix_set_password_access_all_passwords_cap) {
slix_set_password_test(
EXT_PATH("unit_tests/nfc/Slix_cap_accept_all_pass.nfc"), 0x12341234, false);
}
MU_TEST_SUITE(nfc) {
nfc_test_alloc();
MU_RUN_TEST(iso14443_3a_reader);
MU_RUN_TEST(mf_ultralight_11_reader);
MU_RUN_TEST(mf_ultralight_21_reader);
MU_RUN_TEST(ntag_215_reader);
MU_RUN_TEST(ntag_216_reader);
MU_RUN_TEST(ntag_213_locked_reader);
MU_RUN_TEST(mf_ultralight_write);
MU_RUN_TEST(iso14443_3a_4b_file_test);
MU_RUN_TEST(iso14443_3a_7b_file_test);
MU_RUN_TEST(mf_ultralight_file_test);
MU_RUN_TEST(mf_ultralight_ev1_11_file_test);
MU_RUN_TEST(mf_ultralight_ev1_h11_file_test);
MU_RUN_TEST(mf_ultralight_ev1_21_file_test);
MU_RUN_TEST(mf_ultralight_ev1_h21_file_test);
MU_RUN_TEST(mf_ultralight_ntag_203_file_test);
MU_RUN_TEST(mf_ultralight_ntag_213_file_test);
MU_RUN_TEST(mf_ultralight_ntag_215_file_test);
MU_RUN_TEST(mf_ultralight_ntag_216_file_test);
MU_RUN_TEST(mf_ultralight_ntag_i2c_1k_file_test);
MU_RUN_TEST(mf_ultralight_ntag_i2c_2k_file_test);
MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_1k_file_test);
MU_RUN_TEST(mf_ultralight_ntag_i2c_plus_2k_file_test);
MU_RUN_TEST(mf_classic_mini_file_test);
MU_RUN_TEST(mf_classic_1k_4b_file_test);
MU_RUN_TEST(mf_classic_1k_7b_file_test);
MU_RUN_TEST(mf_classic_4k_4b_file_test);
MU_RUN_TEST(mf_classic_4k_7b_file_test);
MU_RUN_TEST(mf_classic_reader);
MU_RUN_TEST(mf_classic_write);
MU_RUN_TEST(mf_classic_value_block);
MU_RUN_TEST(mf_classic_send_frame_test);
MU_RUN_TEST(mf_classic_dict_test);
MU_RUN_TEST(slix_file_with_capabilities_test);
MU_RUN_TEST(slix_set_password_default_cap_correct_pass);
MU_RUN_TEST(slix_set_password_default_cap_incorrect_pass);
MU_RUN_TEST(slix_set_password_access_all_passwords_cap);
nfc_test_free();
}
int run_minunit_test_nfc(void) {
MU_RUN_SUITE(nfc);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_nfc)

View File

@@ -0,0 +1,71 @@
#include <furi.h>
#include <furi_hal.h>
#include "../test.h"
static void power_test_deinit(void) {
// Try to reset to default charge voltage limit
furi_hal_power_set_battery_charge_voltage_limit(4.208f);
}
MU_TEST(test_power_charge_voltage_limit_exact) {
// Power of 16mV charge voltage limits get applied exactly
// (bq25896 charge controller works in 16mV increments)
//
// This test may need adapted if other charge controllers are used in the future.
for(uint16_t charge_mv = 3840; charge_mv <= 4208; charge_mv += 16) {
float charge_volt = (float)charge_mv / 1000.0f;
furi_hal_power_set_battery_charge_voltage_limit(charge_volt);
mu_assert_double_eq(charge_volt, furi_hal_power_get_battery_charge_voltage_limit());
}
}
MU_TEST(test_power_charge_voltage_limit_floating_imprecision) {
// 4.016f should act as 4.016 V, even with floating point imprecision
furi_hal_power_set_battery_charge_voltage_limit(4.016f);
mu_assert_double_eq(4.016f, furi_hal_power_get_battery_charge_voltage_limit());
}
MU_TEST(test_power_charge_voltage_limit_inexact) {
// Charge voltage limits that are not power of 16mV get truncated down
furi_hal_power_set_battery_charge_voltage_limit(3.841f);
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit());
furi_hal_power_set_battery_charge_voltage_limit(3.900f);
mu_assert_double_eq(3.888, furi_hal_power_get_battery_charge_voltage_limit());
furi_hal_power_set_battery_charge_voltage_limit(4.200f);
mu_assert_double_eq(4.192, furi_hal_power_get_battery_charge_voltage_limit());
}
MU_TEST(test_power_charge_voltage_limit_invalid_clamped) {
// Out-of-range charge voltage limits get clamped to 3.840 V and 4.208 V
furi_hal_power_set_battery_charge_voltage_limit(3.808f);
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit());
furi_hal_power_set_battery_charge_voltage_limit(1.0f);
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit());
// NOTE: Intentionally picking a small increment above 4.208 V to reduce the risk of an
// unhappy battery if this fails.
furi_hal_power_set_battery_charge_voltage_limit(4.240f);
mu_assert_double_eq(4.208, furi_hal_power_get_battery_charge_voltage_limit());
// Likewise, picking a number that the uint8_t wraparound in the driver would result in a
// VREG value under 23 if this test fails.
// E.g. (uint8_t)((8105-3840)/16) -> 10
furi_hal_power_set_battery_charge_voltage_limit(8.105f);
mu_assert_double_eq(4.208, furi_hal_power_get_battery_charge_voltage_limit());
}
MU_TEST_SUITE(test_power_suite) {
MU_RUN_TEST(test_power_charge_voltage_limit_exact);
MU_RUN_TEST(test_power_charge_voltage_limit_floating_imprecision);
MU_RUN_TEST(test_power_charge_voltage_limit_inexact);
MU_RUN_TEST(test_power_charge_voltage_limit_invalid_clamped);
power_test_deinit();
}
int run_minunit_test_power(void) {
MU_RUN_SUITE(test_power_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_power)

View File

@@ -0,0 +1,224 @@
#include <furi.h>
#include "../test.h"
#include <toolbox/protocols/protocol_dict.h>
typedef enum {
TestDictProtocol0,
TestDictProtocol1,
TestDictProtocolMax,
} TestDictProtocols;
/*********************** PROTOCOL 0 START ***********************/
typedef struct {
uint32_t data;
size_t encoder_counter;
} Protocol0Data;
static const uint32_t protocol_0_decoder_result = 0xDEADBEEF;
static void* protocol_0_alloc(void) {
void* data = malloc(sizeof(Protocol0Data));
return data;
}
static void protocol_0_free(Protocol0Data* data) {
free(data);
}
static uint8_t* protocol_0_get_data(Protocol0Data* data) {
return (uint8_t*)&data->data;
}
static void protocol_0_decoder_start(Protocol0Data* data) {
data->data = 0;
}
static bool protocol_0_decoder_feed(Protocol0Data* data, bool level, uint32_t duration) {
if(level && duration == 666) {
data->data = protocol_0_decoder_result;
return true;
} else {
return false;
}
}
static bool protocol_0_encoder_start(Protocol0Data* data) {
data->encoder_counter = 0;
return true;
}
static LevelDuration protocol_0_encoder_yield(Protocol0Data* data) {
data->encoder_counter++;
return level_duration_make(data->encoder_counter % 2, data->data);
}
/*********************** PROTOCOL 1 START ***********************/
typedef struct {
uint64_t data;
size_t encoder_counter;
} Protocol1Data;
static const uint64_t protocol_1_decoder_result = 0x1234567890ABCDEF;
static void* protocol_1_alloc(void) {
void* data = malloc(sizeof(Protocol1Data));
return data;
}
static void protocol_1_free(Protocol1Data* data) {
free(data);
}
static uint8_t* protocol_1_get_data(Protocol1Data* data) {
return (uint8_t*)&data->data;
}
static void protocol_1_decoder_start(Protocol1Data* data) {
data->data = 0;
}
static bool protocol_1_decoder_feed(Protocol1Data* data, bool level, uint32_t duration) {
if(level && duration == 543) {
data->data = 0x1234567890ABCDEF;
return true;
} else {
return false;
}
}
static bool protocol_1_encoder_start(Protocol1Data* data) {
data->encoder_counter = 0;
return true;
}
static LevelDuration protocol_1_encoder_yield(Protocol1Data* data) {
data->encoder_counter++;
return level_duration_make(!(data->encoder_counter % 2), 100);
}
/*********************** PROTOCOLS DESCRIPTION ***********************/
static const ProtocolBase protocol_0 = {
.name = "Protocol 0",
.manufacturer = "Manufacturer 0",
.data_size = 4,
.alloc = (ProtocolAlloc)protocol_0_alloc,
.free = (ProtocolFree)protocol_0_free,
.get_data = (ProtocolGetData)protocol_0_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_0_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_0_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_0_encoder_start,
.yield = (ProtocolEncoderYield)protocol_0_encoder_yield,
},
};
static const ProtocolBase protocol_1 = {
.name = "Protocol 1",
.manufacturer = "Manufacturer 1",
.data_size = 8,
.alloc = (ProtocolAlloc)protocol_1_alloc,
.free = (ProtocolFree)protocol_1_free,
.get_data = (ProtocolGetData)protocol_1_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_1_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_1_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_1_encoder_start,
.yield = (ProtocolEncoderYield)protocol_1_encoder_yield,
},
};
static const ProtocolBase* test_protocols_base[] = {
[TestDictProtocol0] = &protocol_0,
[TestDictProtocol1] = &protocol_1,
};
MU_TEST(test_protocol_dict) {
ProtocolDict* dict = protocol_dict_alloc(test_protocols_base, TestDictProtocolMax);
size_t max_data_size = protocol_dict_get_max_data_size(dict);
mu_assert_int_eq(8, max_data_size);
uint8_t* data = malloc(max_data_size);
protocol_dict_decoders_start(dict);
ProtocolId protocol_id = PROTOCOL_NO;
for(size_t i = 0; i < 100; i++) {
protocol_id = protocol_dict_decoders_feed(dict, i % 2, 100);
mu_assert_int_eq(PROTOCOL_NO, protocol_id);
}
// trigger protocol 1
protocol_id = protocol_dict_decoders_feed(dict, true, 543);
mu_assert_int_eq(TestDictProtocol1, protocol_id);
mu_assert_string_eq("Protocol 1", protocol_dict_get_name(dict, protocol_id));
mu_assert_string_eq("Manufacturer 1", protocol_dict_get_manufacturer(dict, protocol_id));
size_t data_size = protocol_dict_get_data_size(dict, protocol_id);
mu_assert_int_eq(8, data_size);
protocol_dict_get_data(dict, protocol_id, data, data_size);
mu_assert_mem_eq(&protocol_1_decoder_result, data, data_size);
// trigger protocol 0
protocol_id = protocol_dict_decoders_feed(dict, true, 666);
mu_assert_int_eq(TestDictProtocol0, protocol_id);
mu_assert_string_eq("Protocol 0", protocol_dict_get_name(dict, protocol_id));
mu_assert_string_eq("Manufacturer 0", protocol_dict_get_manufacturer(dict, protocol_id));
data_size = protocol_dict_get_data_size(dict, protocol_id);
mu_assert_int_eq(4, data_size);
protocol_dict_get_data(dict, protocol_id, data, data_size);
mu_assert_mem_eq(&protocol_0_decoder_result, data, data_size);
protocol_dict_decoders_start(dict);
protocol_id = TestDictProtocol0;
const uint8_t protocol_0_test_data[4] = {100, 0, 0, 0};
protocol_dict_set_data(dict, protocol_id, protocol_0_test_data, 4);
mu_check(protocol_dict_encoder_start(dict, protocol_id));
LevelDuration level;
level = protocol_dict_encoder_yield(dict, protocol_id);
mu_assert_int_eq(true, level_duration_get_level(level));
mu_assert_int_eq(100, level_duration_get_duration(level));
level = protocol_dict_encoder_yield(dict, protocol_id);
mu_assert_int_eq(false, level_duration_get_level(level));
mu_assert_int_eq(100, level_duration_get_duration(level));
level = protocol_dict_encoder_yield(dict, protocol_id);
mu_assert_int_eq(true, level_duration_get_level(level));
mu_assert_int_eq(100, level_duration_get_duration(level));
mu_check(protocol_dict_encoder_start(dict, protocol_id));
level = protocol_dict_encoder_yield(dict, protocol_id);
mu_assert_int_eq(true, level_duration_get_level(level));
mu_assert_int_eq(100, level_duration_get_duration(level));
protocol_dict_free(dict);
free(data);
}
MU_TEST_SUITE(test_protocol_dict_suite) {
MU_RUN_TEST(test_protocol_dict);
}
int run_minunit_test_protocol_dict(void) {
MU_RUN_SUITE(test_protocol_dict_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_protocol_dict)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,716 @@
#include "../test.h"
#include <furi.h>
#include <storage/storage.h>
// DO NOT USE THIS IN PRODUCTION CODE
// This is a hack to access internal storage functions and definitions
#include <storage/storage_i.h>
#define UNIT_TESTS_PATH(path) EXT_PATH("unit_tests/" path)
#define STORAGE_LOCKED_FILE EXT_PATH("locked_file.test")
#define STORAGE_LOCKED_DIR STORAGE_INT_PATH_PREFIX
#define STORAGE_TEST_DIR UNIT_TESTS_PATH("test_dir")
static bool storage_file_create(Storage* storage, const char* path, const char* data) {
File* file = storage_file_alloc(storage);
bool result = false;
do {
if(!storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_NEW)) {
break;
}
if(storage_file_write(file, data, strlen(data)) != strlen(data)) {
break;
}
if(!storage_file_close(file)) {
break;
}
result = true;
} while(0);
storage_file_free(file);
return result;
}
static void storage_file_open_lock_setup(void) {
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);
storage_simply_remove(storage, STORAGE_LOCKED_FILE);
mu_check(storage_file_open(file, STORAGE_LOCKED_FILE, FSAM_WRITE, FSOM_CREATE_NEW));
mu_check(storage_file_write(file, "0123", 4) == 4);
mu_check(storage_file_close(file));
storage_file_free(file);
furi_record_close(RECORD_STORAGE);
}
static void storage_file_open_lock_teardown(void) {
Storage* storage = furi_record_open(RECORD_STORAGE);
mu_check(storage_simply_remove(storage, STORAGE_LOCKED_FILE));
furi_record_close(RECORD_STORAGE);
}
static int32_t storage_file_locker(void* ctx) {
Storage* storage = furi_record_open(RECORD_STORAGE);
FuriSemaphore* semaphore = ctx;
File* file = storage_file_alloc(storage);
furi_check(storage_file_open(file, STORAGE_LOCKED_FILE, FSAM_READ_WRITE, FSOM_OPEN_EXISTING));
furi_semaphore_release(semaphore);
furi_delay_ms(1000);
furi_check(storage_file_close(file));
furi_record_close(RECORD_STORAGE);
storage_file_free(file);
return 0;
}
MU_TEST(storage_file_open_lock) {
Storage* storage = furi_record_open(RECORD_STORAGE);
bool result = false;
FuriSemaphore* semaphore = furi_semaphore_alloc(1, 0);
File* file = storage_file_alloc(storage);
// file_locker thread start
FuriThread* locker_thread =
furi_thread_alloc_ex("StorageFileLocker", 2048, storage_file_locker, semaphore);
furi_thread_start(locker_thread);
// wait for file lock
furi_semaphore_acquire(semaphore, FuriWaitForever);
furi_semaphore_free(semaphore);
result = storage_file_open(file, STORAGE_LOCKED_FILE, FSAM_READ_WRITE, FSOM_OPEN_EXISTING);
storage_file_close(file);
// file_locker thread stop
mu_check(furi_thread_join(locker_thread));
furi_thread_free(locker_thread);
// clean data
storage_file_free(file);
furi_record_close(RECORD_STORAGE);
mu_assert(result, "cannot open locked file");
}
MU_TEST(storage_file_open_close) {
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file;
file = storage_file_alloc(storage);
mu_check(storage_file_open(file, STORAGE_LOCKED_FILE, FSAM_READ_WRITE, FSOM_OPEN_EXISTING));
storage_file_close(file);
storage_file_free(file);
for(size_t i = 0; i < 10; i++) {
file = storage_file_alloc(storage);
mu_check(
storage_file_open(file, STORAGE_LOCKED_FILE, FSAM_READ_WRITE, FSOM_OPEN_EXISTING));
storage_file_free(file);
}
furi_record_close(RECORD_STORAGE);
}
static bool storage_file_read_write_test(File* file, uint8_t* data, size_t test_size) {
const char* filename = UNIT_TESTS_PATH("storage_chunk.test");
// fill with pattern
for(size_t i = 0; i < test_size; i++) {
data[i] = (i % 113);
}
bool result = false;
do {
if(!storage_file_open(file, filename, FSAM_WRITE, FSOM_CREATE_ALWAYS)) break;
if(test_size != storage_file_write(file, data, test_size)) break;
storage_file_close(file);
// reset data
memset(data, 0, test_size);
if(!storage_file_open(file, filename, FSAM_READ, FSOM_OPEN_EXISTING)) break;
if(test_size != storage_file_read(file, data, test_size)) break;
storage_file_close(file);
// check that data is correct
for(size_t i = 0; i < test_size; i++) {
if(data[i] != (i % 113)) {
break;
}
}
result = true;
} while(false);
return result;
}
MU_TEST(storage_file_read_write_64k) {
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);
size_t size_1k = 1024;
size_t size_64k = size_1k + size_1k * 63;
size_t size_65k = size_64k + size_1k;
size_t size_max = size_65k + 8;
size_t max_ram_block = memmgr_heap_get_max_free_block();
if(max_ram_block < size_max) {
mu_warn("Not enough RAM for >64k block test");
} else {
uint8_t* data = malloc(size_max);
mu_check(storage_file_read_write_test(file, data, size_1k));
mu_check(storage_file_read_write_test(file, data, size_64k));
mu_check(storage_file_read_write_test(file, data, size_65k));
mu_check(storage_file_read_write_test(file, data, size_max));
free(data);
}
storage_file_free(file);
furi_record_close(RECORD_STORAGE);
}
MU_TEST_SUITE(storage_file) {
storage_file_open_lock_setup();
MU_RUN_TEST(storage_file_open_close);
MU_RUN_TEST(storage_file_open_lock);
storage_file_open_lock_teardown();
}
MU_TEST_SUITE(storage_file_64k) {
MU_RUN_TEST(storage_file_read_write_64k);
}
MU_TEST(storage_dir_open_close) {
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file;
file = storage_file_alloc(storage);
mu_check(storage_dir_open(file, STORAGE_LOCKED_DIR));
storage_dir_close(file);
storage_file_free(file);
for(size_t i = 0; i < 10; i++) {
file = storage_file_alloc(storage);
mu_check(storage_dir_open(file, STORAGE_LOCKED_DIR));
storage_file_free(file);
}
furi_record_close(RECORD_STORAGE);
}
static int32_t storage_dir_locker(void* ctx) {
Storage* storage = furi_record_open(RECORD_STORAGE);
FuriSemaphore* semaphore = ctx;
File* file = storage_file_alloc(storage);
furi_check(storage_dir_open(file, STORAGE_LOCKED_DIR));
furi_semaphore_release(semaphore);
furi_delay_ms(100);
furi_check(storage_dir_close(file));
furi_record_close(RECORD_STORAGE);
storage_file_free(file);
return 0;
}
MU_TEST(storage_dir_open_lock) {
Storage* storage = furi_record_open(RECORD_STORAGE);
bool result = false;
FuriSemaphore* semaphore = furi_semaphore_alloc(1, 0);
File* file = storage_file_alloc(storage);
// file_locker thread start
FuriThread* locker_thread =
furi_thread_alloc_ex("StorageDirLocker", 2048, storage_dir_locker, semaphore);
furi_thread_start(locker_thread);
// wait for dir lock
furi_semaphore_acquire(semaphore, FuriWaitForever);
furi_semaphore_free(semaphore);
result = storage_dir_open(file, STORAGE_LOCKED_DIR);
storage_dir_close(file);
// file_locker thread stop
mu_check(furi_thread_join(locker_thread));
furi_thread_free(locker_thread);
// clean data
storage_file_free(file);
furi_record_close(RECORD_STORAGE);
mu_assert(result, "cannot open locked dir");
}
MU_TEST(storage_dir_exists_test) {
Storage* storage = furi_record_open(RECORD_STORAGE);
mu_check(!storage_dir_exists(storage, STORAGE_TEST_DIR));
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, STORAGE_TEST_DIR));
mu_check(storage_dir_exists(storage, STORAGE_TEST_DIR));
mu_assert_int_eq(FSE_OK, storage_common_remove(storage, STORAGE_TEST_DIR));
furi_record_close(RECORD_STORAGE);
}
MU_TEST_SUITE(storage_dir) {
MU_RUN_TEST(storage_dir_open_close);
MU_RUN_TEST(storage_dir_open_lock);
MU_RUN_TEST(storage_dir_exists_test);
}
static const char* const storage_copy_test_paths[] = {
"1",
"11",
"111",
"1/2",
"1/22",
"1/222",
"11/1",
"111/2",
"111/22",
"111/22/33",
};
static const char* const storage_copy_test_files[] = {
"file.test",
"1/file.test",
"111/22/33/file.test",
};
static bool write_file_13DA(Storage* storage, const char* path) {
File* file = storage_file_alloc(storage);
bool result = false;
if(storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
result = storage_file_write(file, "13DA", 4) == 4;
}
storage_file_close(file);
storage_file_free(file);
return result;
}
static bool check_file_13DA(Storage* storage, const char* path) {
File* file = storage_file_alloc(storage);
bool result = false;
if(storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING)) {
char data[10] = {0};
result = storage_file_read(file, data, 4) == 4;
if(result) {
result = memcmp(data, "13DA", 4) == 0;
}
}
storage_file_close(file);
storage_file_free(file);
return result;
}
static void storage_dir_create(Storage* storage, const char* base) {
FuriString* path;
path = furi_string_alloc();
storage_common_mkdir(storage, base);
for(size_t i = 0; i < COUNT_OF(storage_copy_test_paths); i++) {
furi_string_printf(path, "%s/%s", base, storage_copy_test_paths[i]);
storage_common_mkdir(storage, furi_string_get_cstr(path));
}
for(size_t i = 0; i < COUNT_OF(storage_copy_test_files); i++) {
furi_string_printf(path, "%s/%s", base, storage_copy_test_files[i]);
write_file_13DA(storage, furi_string_get_cstr(path));
}
furi_string_free(path);
}
static void storage_dir_remove(Storage* storage, const char* base) {
storage_simply_remove_recursive(storage, base);
}
static bool storage_dir_rename_check(Storage* storage, const char* base) {
bool result = false;
FuriString* path;
path = furi_string_alloc();
result = (storage_common_stat(storage, base, NULL) == FSE_OK);
if(result) {
for(size_t i = 0; i < COUNT_OF(storage_copy_test_paths); i++) {
furi_string_printf(path, "%s/%s", base, storage_copy_test_paths[i]);
result = (storage_common_stat(storage, furi_string_get_cstr(path), NULL) == FSE_OK);
if(!result) {
break;
}
}
}
if(result) {
for(size_t i = 0; i < COUNT_OF(storage_copy_test_files); i++) {
furi_string_printf(path, "%s/%s", base, storage_copy_test_files[i]);
result = check_file_13DA(storage, furi_string_get_cstr(path));
if(!result) {
break;
}
}
}
furi_string_free(path);
return result;
}
MU_TEST(storage_file_rename) {
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);
mu_check(write_file_13DA(storage, EXT_PATH("file.old")));
mu_check(check_file_13DA(storage, EXT_PATH("file.old")));
mu_assert_int_eq(
FSE_OK, storage_common_rename(storage, EXT_PATH("file.old"), EXT_PATH("file.new")));
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, EXT_PATH("file.old"), NULL));
mu_assert_int_eq(FSE_OK, storage_common_stat(storage, EXT_PATH("file.new"), NULL));
mu_check(check_file_13DA(storage, EXT_PATH("file.new")));
mu_assert_int_eq(FSE_OK, storage_common_remove(storage, EXT_PATH("file.new")));
storage_file_free(file);
furi_record_close(RECORD_STORAGE);
}
MU_TEST(storage_dir_rename) {
Storage* storage = furi_record_open(RECORD_STORAGE);
storage_dir_create(storage, EXT_PATH("dir.old"));
mu_check(storage_dir_rename_check(storage, EXT_PATH("dir.old")));
mu_assert_int_eq(
FSE_OK, storage_common_rename(storage, EXT_PATH("dir.old"), EXT_PATH("dir.new")));
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, EXT_PATH("dir.old"), NULL));
mu_check(storage_dir_rename_check(storage, EXT_PATH("dir.new")));
storage_dir_remove(storage, EXT_PATH("dir.new"));
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, EXT_PATH("dir.new"), NULL));
furi_record_close(RECORD_STORAGE);
}
MU_TEST_SUITE(storage_rename) {
MU_RUN_TEST(storage_file_rename);
MU_RUN_TEST(storage_dir_rename);
Storage* storage = furi_record_open(RECORD_STORAGE);
storage_dir_remove(storage, EXT_PATH("dir.old"));
storage_dir_remove(storage, EXT_PATH("dir.new"));
furi_record_close(RECORD_STORAGE);
}
#define APPSDATA_APP_PATH(path) APPS_DATA_PATH "/" path
static const char* storage_test_apps[] = {
"-_twilight_-",
"-_rainbow_-",
"-_pinkie_-",
"-_apple_-",
"-_flutter_-",
"-_rare_-",
};
static size_t storage_test_apps_count = COUNT_OF(storage_test_apps);
static int32_t storage_test_app(void* arg) {
UNUSED(arg);
Storage* storage = furi_record_open(RECORD_STORAGE);
storage_common_remove(storage, "/data/test");
int32_t ret = storage_file_create(storage, "/data/test", "test");
furi_record_close(RECORD_STORAGE);
return ret;
}
MU_TEST(test_storage_data_path_apps) {
for(size_t i = 0; i < storage_test_apps_count; i++) {
FuriThread* thread =
furi_thread_alloc_ex(storage_test_apps[i], 1024, storage_test_app, NULL);
furi_thread_set_appid(thread, storage_test_apps[i]);
furi_thread_start(thread);
furi_thread_join(thread);
mu_assert_int_eq(true, furi_thread_get_return_code(thread));
// Check if app data dir and file exists
Storage* storage = furi_record_open(RECORD_STORAGE);
FuriString* expected = furi_string_alloc();
furi_string_printf(expected, APPSDATA_APP_PATH("%s"), storage_test_apps[i]);
mu_check(storage_dir_exists(storage, furi_string_get_cstr(expected)));
furi_string_cat(expected, "/test");
mu_check(storage_file_exists(storage, furi_string_get_cstr(expected)));
furi_string_printf(expected, APPSDATA_APP_PATH("%s"), storage_test_apps[i]);
storage_simply_remove_recursive(storage, furi_string_get_cstr(expected));
furi_record_close(RECORD_STORAGE);
furi_string_free(expected);
furi_thread_free(thread);
}
}
MU_TEST(test_storage_data_path) {
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);
mu_check(storage_dir_open(file, "/data"));
mu_check(storage_dir_close(file));
storage_file_free(file);
// check that appsdata folder exists
mu_check(storage_dir_exists(storage, APPS_DATA_PATH));
// check that cli folder exists
mu_check(storage_dir_exists(storage, APPSDATA_APP_PATH("cli")));
storage_simply_remove(storage, APPSDATA_APP_PATH("cli"));
furi_record_close(RECORD_STORAGE);
}
MU_TEST(test_storage_common_migrate) {
Storage* storage = furi_record_open(RECORD_STORAGE);
// Setup test folders
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
// Test migration from non existing
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
// Test migration from existing folder to non existing
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_old")));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file1"), "test1"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file2.ext"), "test2"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file3.ext.ext"), "test3"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file1")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file2.ext")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file3.ext.ext")));
mu_check(storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_old")));
// Test migration from existing folder to existing folder
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_old")));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file1"), "test1"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file2.ext"), "test2"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old/file3.ext.ext"), "test3"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file1")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file2.ext")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file3.ext.ext")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file11")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file21.ext")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new/file3.ext1.ext")));
mu_check(storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_old")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
// Test migration from empty folder to existing file
// Expected result: FSE_OK, folder removed, file untouched
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_old")));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_new"), "test1"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_old")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
// Test migration from empty folder to existing folder
// Expected result: FSE_OK, old folder removed, new folder untouched
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_old")));
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_new")));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_old")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
// Test migration from existing file to non existing, no extension
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old"), "test1"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_file_exists(storage, UNIT_TESTS_PATH("migrate_old")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
// Test migration from existing file to non existing, with extension
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old.file"), "test1"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old.file"), UNIT_TESTS_PATH("migrate_new.file")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new.file")));
mu_check(!storage_file_exists(storage, UNIT_TESTS_PATH("migrate_old.file")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old.file"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new.file"));
// Test migration from existing file to existing file, no extension
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old"), "test1"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_new"), "test2"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_file_exists(storage, UNIT_TESTS_PATH("migrate_old")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new1")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new1"));
// Test migration from existing file to existing file, with extension
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old.file"), "test1"));
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_new.file"), "test2"));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old.file"), UNIT_TESTS_PATH("migrate_new.file")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new.file")));
mu_check(!storage_file_exists(storage, UNIT_TESTS_PATH("migrate_old.file")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new1.file")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old.file"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new.file"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new1.file"));
// Test migration from existing file to existing folder
mu_check(storage_file_create(storage, UNIT_TESTS_PATH("migrate_old"), "test1"));
mu_assert_int_eq(FSE_OK, storage_common_mkdir(storage, UNIT_TESTS_PATH("migrate_new")));
mu_assert_int_eq(
FSE_OK,
storage_common_migrate(
storage, UNIT_TESTS_PATH("migrate_old"), UNIT_TESTS_PATH("migrate_new")));
mu_check(storage_dir_exists(storage, UNIT_TESTS_PATH("migrate_new")));
mu_check(!storage_file_exists(storage, UNIT_TESTS_PATH("migrate_old")));
mu_check(storage_file_exists(storage, UNIT_TESTS_PATH("migrate_new1")));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_old"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new"));
storage_simply_remove_recursive(storage, UNIT_TESTS_PATH("migrate_new1"));
furi_record_close(RECORD_STORAGE);
}
#define MD5_HASH_SIZE (16)
#include <lib/toolbox/md5_calc.h>
MU_TEST(test_md5_calc) {
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);
const char* path = UNIT_TESTS_PATH("storage/md5.txt");
const char* md5_cstr = "2a456fa43e75088fdde41c93159d62a2";
const uint8_t md5[MD5_HASH_SIZE] = {
0x2a,
0x45,
0x6f,
0xa4,
0x3e,
0x75,
0x08,
0x8f,
0xdd,
0xe4,
0x1c,
0x93,
0x15,
0x9d,
0x62,
0xa2,
};
uint8_t md5_output[MD5_HASH_SIZE];
FuriString* md5_output_str = furi_string_alloc();
memset(md5_output, 0, MD5_HASH_SIZE);
mu_check(md5_calc_file(file, path, md5_output, NULL));
mu_check(md5_string_calc_file(file, path, md5_output_str, NULL));
mu_assert_mem_eq(md5, md5_output, MD5_HASH_SIZE);
mu_assert_string_eq(md5_cstr, furi_string_get_cstr(md5_output_str));
storage_file_free(file);
furi_string_free(md5_output_str);
furi_record_close(RECORD_STORAGE);
}
MU_TEST_SUITE(test_data_path) {
MU_RUN_TEST(test_storage_data_path);
MU_RUN_TEST(test_storage_data_path_apps);
}
MU_TEST_SUITE(test_storage_common) {
MU_RUN_TEST(test_storage_common_migrate);
}
MU_TEST_SUITE(test_md5_calc_suite) {
MU_RUN_TEST(test_md5_calc);
}
int run_minunit_test_storage(void) {
MU_RUN_SUITE(storage_file);
MU_RUN_SUITE(storage_file_64k);
MU_RUN_SUITE(storage_dir);
MU_RUN_SUITE(storage_rename);
MU_RUN_SUITE(test_data_path);
MU_RUN_SUITE(test_storage_common);
MU_RUN_SUITE(test_md5_calc_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_storage)

View File

@@ -0,0 +1,534 @@
#include <furi.h>
#include <toolbox/stream/stream.h>
#include <toolbox/stream/string_stream.h>
#include <toolbox/stream/file_stream.h>
#include <toolbox/stream/buffered_file_stream.h>
#include <storage/storage.h>
#include "../test.h"
static const char* stream_test_data = "I write differently from what I speak, "
"I speak differently from what I think, "
"I think differently from the way I ought to think, "
"and so it all proceeds into deepest darkness.";
static const char* stream_test_left_data = "There are two cardinal human sins ";
static const char* stream_test_right_data =
"from which all others derive: impatience and indolence.";
MU_TEST_1(stream_composite_subtest, Stream* stream) {
const size_t data_size = 128;
uint8_t data[data_size];
FuriString* string_lee;
string_lee = furi_string_alloc_set("lee");
// test that stream is empty
// "" -> ""
mu_check(stream_size(stream) == 0);
mu_check(stream_eof(stream));
mu_check(stream_tell(stream) == 0);
mu_check(stream_read(stream, data, data_size) == 0);
mu_check(stream_eof(stream));
mu_check(stream_tell(stream) == 0);
// write char
// "" -> "2"
mu_check(stream_write_char(stream, '2') == 1);
mu_check(stream_size(stream) == 1);
mu_check(stream_tell(stream) == 1);
mu_check(stream_eof(stream));
// test rewind and eof
stream_rewind(stream);
mu_check(stream_size(stream) == 1);
mu_check(stream_tell(stream) == 0);
mu_check(!stream_eof(stream));
// add another char with replacement
// "2" -> "1"
mu_check(stream_write_char(stream, '1') == 1);
mu_check(stream_size(stream) == 1);
mu_check(stream_tell(stream) == 1);
mu_check(stream_eof(stream));
// write string
// "1" -> "1337_69"
mu_check(stream_write_cstring(stream, "337_69") == 6);
mu_check(stream_size(stream) == 7);
mu_check(stream_tell(stream) == 7);
mu_check(stream_eof(stream));
// read data
memset(data, 0, data_size);
stream_rewind(stream);
mu_check(stream_read(stream, data, data_size) == 7);
mu_check(strcmp((char*)data, "1337_69") == 0);
// test misc seeks
mu_check(stream_seek(stream, 2, StreamOffsetFromStart));
mu_check(stream_tell(stream) == 2);
mu_check(!stream_seek(stream, 9000, StreamOffsetFromStart));
mu_check(stream_tell(stream) == 7);
mu_check(stream_eof(stream));
mu_check(stream_seek(stream, -3, StreamOffsetFromEnd));
mu_check(stream_tell(stream) == 4);
// test seeks to char. content: '1337_69'
stream_rewind(stream);
mu_check(stream_seek_to_char(stream, '3', StreamDirectionForward));
mu_check(stream_tell(stream) == 1);
mu_check(stream_seek_to_char(stream, '3', StreamDirectionForward));
mu_check(stream_tell(stream) == 2);
mu_check(stream_seek_to_char(stream, '_', StreamDirectionForward));
mu_check(stream_tell(stream) == 4);
mu_check(stream_seek_to_char(stream, '9', StreamDirectionForward));
mu_check(stream_tell(stream) == 6);
mu_check(!stream_seek_to_char(stream, '9', StreamDirectionForward));
mu_check(stream_tell(stream) == 6);
mu_check(stream_seek_to_char(stream, '_', StreamDirectionBackward));
mu_check(stream_tell(stream) == 4);
mu_check(stream_seek_to_char(stream, '3', StreamDirectionBackward));
mu_check(stream_tell(stream) == 2);
mu_check(stream_seek_to_char(stream, '3', StreamDirectionBackward));
mu_check(stream_tell(stream) == 1);
mu_check(!stream_seek_to_char(stream, '3', StreamDirectionBackward));
mu_check(stream_tell(stream) == 1);
mu_check(stream_seek_to_char(stream, '1', StreamDirectionBackward));
mu_check(stream_tell(stream) == 0);
// write string with replacement
// "1337_69" -> "1337lee"
mu_check(stream_seek(stream, 4, StreamOffsetFromStart));
mu_check(stream_write_string(stream, string_lee) == 3);
mu_check(stream_size(stream) == 7);
mu_check(stream_tell(stream) == 7);
mu_check(stream_eof(stream));
// append char
// "1337lee" -> "1337leet"
mu_check(stream_write(stream, (uint8_t*)"t", 1) == 1);
mu_check(stream_size(stream) == 8);
mu_check(stream_tell(stream) == 8);
mu_check(stream_eof(stream));
// read data
memset(data, 0, data_size);
stream_rewind(stream);
mu_check(stream_read(stream, data, data_size) == 8);
mu_check(strcmp((char*)data, "1337leet") == 0);
mu_check(stream_tell(stream) == 8);
mu_check(stream_eof(stream));
// negative seek from current position -> clamp to 0
mu_check(!stream_seek(stream, -9000, StreamOffsetFromCurrent));
mu_check(stream_tell(stream) == 0);
// negative seek from start position -> clamp to 0
stream_rewind(stream);
mu_check(!stream_seek(stream, -3, StreamOffsetFromStart));
mu_check(stream_tell(stream) == 0);
// zero seek from current position -> clamp to stream size
mu_check(stream_seek(stream, 0, StreamOffsetFromEnd));
mu_check(stream_tell(stream) == 8);
// negative seek from end position -> clamp to 0
mu_check(!stream_seek(stream, -9000, StreamOffsetFromEnd));
mu_check(stream_tell(stream) == 0);
// clean stream
stream_clean(stream);
mu_check(stream_size(stream) == 0);
mu_check(stream_eof(stream));
mu_check(stream_tell(stream) == 0);
// write format
// "" -> "dio666"
mu_check(stream_write_format(stream, "%s%d", "dio", 666) == 6);
mu_check(stream_size(stream) == 6);
mu_check(stream_eof(stream));
mu_check(stream_tell(stream) == 6);
// read data
memset(data, 0, data_size);
stream_rewind(stream);
mu_check(stream_read(stream, data, data_size) == 6);
mu_check(strcmp((char*)data, "dio666") == 0);
// clean and write cstring
// "dio666" -> "" -> "1234567890"
stream_clean(stream);
mu_check(stream_write_cstring(stream, "1234567890") == 10);
// delete 4 bytes from 1 pos
// "1xxxx67890" -> "167890"
mu_check(stream_seek(stream, 1, StreamOffsetFromStart));
mu_check(stream_delete(stream, 4));
mu_assert_int_eq(6, stream_size(stream));
// read data
memset(data, 0, data_size);
stream_rewind(stream);
mu_assert_int_eq(6, stream_read(stream, data, data_size));
mu_check(strcmp((char*)data, "167890") == 0);
// write cstring
// "167890" -> "167890It Was Me, Dio!"
mu_check(stream_write_cstring(stream, "It Was Me, Dio!") == 15);
// delete 1337 bytes from 1 pos
// and check that we can delete only 20 bytes
// "1xxxxxxxxxxxxxxxxxxxx" -> "1"
mu_check(stream_seek(stream, 1, StreamOffsetFromStart));
mu_check(stream_delete(stream, 1337));
mu_assert_int_eq(1, stream_size(stream));
// read data
memset(data, 0, data_size);
stream_rewind(stream);
mu_check(stream_read(stream, data, data_size) == 1);
mu_check(strcmp((char*)data, "1") == 0);
// write cstring from 0 pos, replacing 1 byte
// "1" -> "Oh? You're roaching me?"
mu_check(stream_rewind(stream));
mu_assert_int_eq(23, stream_write_cstring(stream, "Oh? You're roaching me?"));
// insert 11 bytes to 0 pos
// "Oh? You're roaching me?" -> "Za Warudo! Oh? You're roaching me?"
mu_check(stream_rewind(stream));
mu_check(stream_insert(stream, (uint8_t*)"Za Warudo! ", 11));
mu_assert_int_eq(34, stream_size(stream));
// read data
memset(data, 0, data_size);
stream_rewind(stream);
mu_assert_int_eq(34, stream_read(stream, data, data_size));
mu_assert_string_eq("Za Warudo! Oh? You're roaching me?", (char*)data);
// insert cstring to 22 pos
// "Za Warudo! Oh? You're roaching me?" -> "Za Warudo! Oh? You're approaching me?"
mu_check(stream_seek(stream, 22, StreamOffsetFromStart));
mu_check(stream_insert_cstring(stream, "app"));
mu_assert_int_eq(37, stream_size(stream));
// read data
memset(data, 0, data_size);
stream_rewind(stream);
mu_assert_int_eq(37, stream_read(stream, data, data_size));
mu_assert_string_eq("Za Warudo! Oh? You're approaching me?", (char*)data);
// insert cstring to the end of the stream
// "Za Warudo! Oh? You're approaching me?" -> "Za Warudo! Oh? You're approaching me? It was me, Dio!"
mu_check(stream_seek(stream, 0, StreamOffsetFromEnd));
mu_check(stream_insert_cstring(stream, " It was me, Dio!"));
mu_assert_int_eq(53, stream_size(stream));
// read data
memset(data, 0, data_size);
stream_rewind(stream);
mu_assert_int_eq(53, stream_read(stream, data, data_size));
mu_assert_string_eq("Za Warudo! Oh? You're approaching me? It was me, Dio!", (char*)data);
// delete 168430090 bytes from stream
// and test that we can delete only 53
mu_check(stream_rewind(stream));
mu_check(stream_delete(stream, 0x0A0A0A0A));
mu_assert_int_eq(0, stream_size(stream));
mu_check(stream_eof(stream));
mu_assert_int_eq(0, stream_tell(stream));
// clean stream
stream_clean(stream);
mu_assert_int_eq(0, stream_size(stream));
mu_check(stream_eof(stream));
mu_assert_int_eq(0, stream_tell(stream));
// insert formatted string at the end of stream
// "" -> "dio666"
mu_check(stream_insert_format(stream, "%s%d", "dio", 666));
mu_assert_int_eq(6, stream_size(stream));
mu_check(stream_eof(stream));
mu_assert_int_eq(6, stream_tell(stream));
// insert formatted string at the end of stream
// "dio666" -> "dio666zlo555"
mu_check(stream_insert_format(stream, "%s%d", "zlo", 555));
mu_assert_int_eq(12, stream_size(stream));
mu_check(stream_eof(stream));
mu_assert_int_eq(12, stream_tell(stream));
// insert formatted string at the 6 pos
// "dio666" -> "dio666baba13zlo555"
mu_check(stream_seek(stream, 6, StreamOffsetFromStart));
mu_check(stream_insert_format(stream, "%s%d", "baba", 13));
mu_assert_int_eq(18, stream_size(stream));
mu_assert_int_eq(12, stream_tell(stream));
// read data
memset(data, 0, data_size);
stream_rewind(stream);
mu_assert_int_eq(18, stream_read(stream, data, data_size));
mu_assert_string_eq("dio666baba13zlo555", (char*)data);
// delete 6 chars from pos 6 and insert 1 chars
// "dio666baba13zlo555" -> "dio666xzlo555"
mu_check(stream_seek(stream, 6, StreamOffsetFromStart));
mu_check(stream_delete_and_insert_char(stream, 6, 'x'));
mu_assert_int_eq(13, stream_size(stream));
mu_assert_int_eq(7, stream_tell(stream));
// read data
memset(data, 0, data_size);
stream_rewind(stream);
mu_check(stream_read(stream, data, data_size) == 13);
mu_assert_string_eq("dio666xzlo555", (char*)data);
// delete 9000 chars from pos 6 and insert 3 chars from string
// "dio666xzlo555" -> "dio666777"
mu_check(stream_seek(stream, 6, StreamOffsetFromStart));
mu_check(stream_delete_and_insert_cstring(stream, 9000, "777"));
mu_assert_int_eq(9, stream_size(stream));
mu_assert_int_eq(9, stream_tell(stream));
mu_check(stream_eof(stream));
furi_string_free(string_lee);
}
MU_TEST(stream_composite_test) {
// test string stream
Stream* stream;
stream = string_stream_alloc();
MU_RUN_TEST_1(stream_composite_subtest, stream);
stream_free(stream);
// test file stream
Storage* storage = furi_record_open(RECORD_STORAGE);
stream = file_stream_alloc(storage);
mu_check(
file_stream_open(stream, EXT_PATH("filestream.str"), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS));
MU_RUN_TEST_1(stream_composite_subtest, stream);
stream_free(stream);
// test buffered file stream
stream = buffered_file_stream_alloc(storage);
mu_check(buffered_file_stream_open(
stream, EXT_PATH("filestream.str"), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS));
MU_RUN_TEST_1(stream_composite_subtest, stream);
stream_free(stream);
furi_record_close(RECORD_STORAGE);
}
MU_TEST_1(stream_write_subtest, Stream* stream) {
mu_assert_int_eq(strlen(stream_test_data), stream_write_cstring(stream, stream_test_data));
}
MU_TEST_1(stream_read_subtest, Stream* stream) {
uint8_t data[256] = {0};
mu_check(stream_rewind(stream));
mu_assert_int_eq(strlen(stream_test_data), stream_read(stream, data, 256));
mu_assert_string_eq(stream_test_data, (const char*)data);
}
MU_TEST(stream_write_read_save_load_test) {
Stream* stream_orig = string_stream_alloc();
Stream* stream_copy = string_stream_alloc();
Storage* storage = furi_record_open(RECORD_STORAGE);
// write, read
MU_RUN_TEST_1(stream_write_subtest, stream_orig);
MU_RUN_TEST_1(stream_read_subtest, stream_orig);
// copy, read
mu_assert_int_eq(strlen(stream_test_data), stream_copy_full(stream_orig, stream_copy));
MU_RUN_TEST_1(stream_read_subtest, stream_orig);
// save to file
mu_check(stream_seek(stream_orig, 0, StreamOffsetFromStart));
mu_assert_int_eq(
strlen(stream_test_data),
stream_save_to_file(stream_orig, storage, EXT_PATH("filestream.str"), FSOM_CREATE_ALWAYS));
stream_free(stream_copy);
stream_free(stream_orig);
// load from file, read
Stream* stream_new = string_stream_alloc();
mu_assert_int_eq(
strlen(stream_test_data),
stream_load_from_file(stream_new, storage, EXT_PATH("filestream.str")));
MU_RUN_TEST_1(stream_read_subtest, stream_new);
stream_free(stream_new);
furi_record_close(RECORD_STORAGE);
}
MU_TEST_1(stream_split_subtest, Stream* stream) {
stream_clean(stream);
stream_write_cstring(stream, stream_test_left_data);
stream_write_cstring(stream, stream_test_right_data);
Stream* stream_left = string_stream_alloc();
Stream* stream_right = string_stream_alloc();
mu_check(stream_seek(stream, strlen(stream_test_left_data), StreamOffsetFromStart));
mu_check(stream_split(stream, stream_left, stream_right));
uint8_t data[256] = {0};
mu_check(stream_rewind(stream_left));
mu_assert_int_eq(strlen(stream_test_left_data), stream_read(stream_left, data, 256));
mu_assert_string_eq(stream_test_left_data, (const char*)data);
mu_check(stream_rewind(stream_right));
mu_assert_int_eq(strlen(stream_test_right_data), stream_read(stream_right, data, 256));
mu_assert_string_eq(stream_test_right_data, (const char*)data);
stream_free(stream_right);
stream_free(stream_left);
}
MU_TEST(stream_split_test) {
// test string stream
Stream* stream;
stream = string_stream_alloc();
MU_RUN_TEST_1(stream_split_subtest, stream);
stream_free(stream);
// test file stream
Storage* storage = furi_record_open(RECORD_STORAGE);
stream = file_stream_alloc(storage);
mu_check(
file_stream_open(stream, EXT_PATH("filestream.str"), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS));
MU_RUN_TEST_1(stream_split_subtest, stream);
stream_free(stream);
// test buffered stream
stream = buffered_file_stream_alloc(storage);
mu_check(buffered_file_stream_open(
stream, EXT_PATH("filestream.str"), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS));
MU_RUN_TEST_1(stream_split_subtest, stream);
stream_free(stream);
furi_record_close(RECORD_STORAGE);
}
MU_TEST(stream_buffered_write_after_read_test) {
const char* prefix = "I write ";
const char* substr = "Hello there";
const size_t substr_len = strlen(substr);
const size_t prefix_len = strlen(prefix);
const size_t buf_size = substr_len + 1;
char buf[buf_size];
memset(buf, 0, buf_size);
Storage* storage = furi_record_open(RECORD_STORAGE);
Stream* stream = buffered_file_stream_alloc(storage);
mu_check(buffered_file_stream_open(
stream, EXT_PATH("filestream.str"), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS));
mu_assert_int_eq(strlen(stream_test_data), stream_write_cstring(stream, stream_test_data));
mu_check(stream_rewind(stream));
mu_assert_int_eq(prefix_len, stream_read(stream, (uint8_t*)buf, prefix_len));
mu_assert_string_eq(prefix, buf);
mu_assert_int_eq(substr_len, stream_write(stream, (uint8_t*)substr, substr_len));
mu_check(stream_seek(stream, prefix_len, StreamOffsetFromStart));
mu_assert_int_eq(substr_len, stream_read(stream, (uint8_t*)buf, substr_len));
mu_assert_string_eq(substr, buf);
stream_free(stream);
furi_record_close(RECORD_STORAGE);
}
MU_TEST(stream_buffered_large_file_test) {
FuriString* input_data;
FuriString* output_data;
input_data = furi_string_alloc();
output_data = furi_string_alloc();
Storage* storage = furi_record_open(RECORD_STORAGE);
// generate test data consisting of several identical lines
const size_t data_size = 4096;
const size_t line_size = strlen(stream_test_data);
const size_t rep_count = data_size / line_size + 1;
for(size_t i = 0; i < rep_count; ++i) {
furi_string_cat_printf(input_data, "%s\n", stream_test_data);
}
// write test data to file
Stream* stream = buffered_file_stream_alloc(storage);
mu_check(buffered_file_stream_open(
stream, EXT_PATH("filestream.str"), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS));
mu_assert_int_eq(0, stream_size(stream));
mu_assert_int_eq(furi_string_size(input_data), stream_write_string(stream, input_data));
mu_assert_int_eq(furi_string_size(input_data), stream_size(stream));
const size_t substr_start = 8;
const size_t substr_len = 11;
mu_check(stream_seek(stream, substr_start, StreamOffsetFromStart));
mu_assert_int_eq(substr_start, stream_tell(stream));
// copy one substring from test data
char test_substr[substr_len + 1];
memset(test_substr, 0, substr_len + 1);
memcpy(test_substr, stream_test_data + substr_start, substr_len);
char buf[substr_len + 1];
memset(buf, 0, substr_len + 1);
// read substring
mu_assert_int_eq(substr_len, stream_read(stream, (uint8_t*)buf, substr_len));
mu_assert_string_eq(test_substr, buf);
memset(buf, 0, substr_len + 1);
// forward seek to cause a cache miss
mu_check(stream_seek(
stream, (line_size + 1) * (rep_count - 1) - substr_len, StreamOffsetFromCurrent));
// read same substring from a different line
mu_assert_int_eq(substr_len, stream_read(stream, (uint8_t*)buf, substr_len));
mu_assert_string_eq(test_substr, buf);
memset(buf, 0, substr_len + 1);
// backward seek to cause a cache miss
mu_check(stream_seek(
stream, -((line_size + 1) * (rep_count - 1) + substr_len), StreamOffsetFromCurrent));
mu_assert_int_eq(substr_len, stream_read(stream, (uint8_t*)buf, substr_len));
mu_assert_string_eq(test_substr, buf);
// read the whole file
mu_check(stream_rewind(stream));
FuriString* tmp;
tmp = furi_string_alloc();
while(stream_read_line(stream, tmp)) {
furi_string_cat(output_data, tmp);
}
furi_string_free(tmp);
// check against generated data
mu_assert_int_eq(furi_string_size(input_data), furi_string_size(output_data));
mu_check(furi_string_equal(input_data, output_data));
mu_check(stream_eof(stream));
stream_free(stream);
furi_record_close(RECORD_STORAGE);
furi_string_free(input_data);
furi_string_free(output_data);
}
MU_TEST_SUITE(stream_suite) {
MU_RUN_TEST(stream_write_read_save_load_test);
MU_RUN_TEST(stream_composite_test);
MU_RUN_TEST(stream_split_test);
MU_RUN_TEST(stream_buffered_write_after_read_test);
MU_RUN_TEST(stream_buffered_large_file_test);
}
int run_minunit_test_stream(void) {
MU_RUN_SUITE(stream_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_stream)

View File

@@ -0,0 +1,918 @@
#include <furi.h>
#include <furi_hal.h>
#include "../test.h"
#include <lib/subghz/receiver.h>
#include <lib/subghz/transmitter.h>
#include <lib/subghz/subghz_keystore.h>
#include <lib/subghz/subghz_file_encoder_worker.h>
#include <lib/subghz/protocols/protocol_items.h>
#include <flipper_format/flipper_format_i.h>
#include <lib/subghz/devices/devices.h>
#include <lib/subghz/devices/cc1101_configs.h>
#define TAG "SubGhzTest"
#define KEYSTORE_DIR_NAME EXT_PATH("subghz/assets/keeloq_mfcodes")
#define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo")
#define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s")
#define ALUTECH_AT_4N_DIR_NAME EXT_PATH("subghz/assets/alutech_at_4n")
#define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub")
#define TEST_RANDOM_COUNT_PARSE 329
#define TEST_TIMEOUT 10000
static SubGhzEnvironment* environment_handler;
static SubGhzReceiver* receiver_handler;
//static SubGhzTransmitter* transmitter_handler;
static SubGhzFileEncoderWorker* file_worker_encoder_handler;
static uint16_t subghz_test_decoder_count = 0;
static void subghz_test_rx_callback(
SubGhzReceiver* receiver,
SubGhzProtocolDecoderBase* decoder_base,
void* context) {
UNUSED(receiver);
UNUSED(context);
FuriString* text;
text = furi_string_alloc();
subghz_protocol_decoder_base_get_string(decoder_base, text);
subghz_receiver_reset(receiver_handler);
FURI_LOG_T(TAG, "\r\n%s", furi_string_get_cstr(text));
furi_string_free(text);
subghz_test_decoder_count++;
}
static void subghz_test_init(void) {
environment_handler = subghz_environment_alloc();
subghz_environment_set_nice_flor_s_rainbow_table_file_name(
environment_handler, NICE_FLOR_S_DIR_NAME);
subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
environment_handler, ALUTECH_AT_4N_DIR_NAME);
subghz_environment_set_protocol_registry(
environment_handler, (void*)&subghz_protocol_registry);
subghz_devices_init();
receiver_handler = subghz_receiver_alloc_init(environment_handler);
subghz_receiver_set_filter(receiver_handler, SubGhzProtocolFlag_Decodable);
subghz_receiver_set_rx_callback(receiver_handler, subghz_test_rx_callback, NULL);
}
static void subghz_test_deinit(void) {
subghz_devices_deinit();
subghz_receiver_free(receiver_handler);
subghz_environment_free(environment_handler);
}
static bool subghz_decoder_test(const char* path, const char* name_decoder) {
subghz_test_decoder_count = 0;
uint32_t test_start = furi_get_tick();
SubGhzProtocolDecoderBase* decoder =
subghz_receiver_search_decoder_base_by_name(receiver_handler, name_decoder);
if(decoder) {
file_worker_encoder_handler = subghz_file_encoder_worker_alloc();
if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path, NULL)) {
// the worker needs a file in order to open and read part of the file
furi_delay_ms(100);
LevelDuration level_duration;
while(furi_get_tick() - test_start < TEST_TIMEOUT) {
level_duration =
subghz_file_encoder_worker_get_level_duration(file_worker_encoder_handler);
if(!level_duration_is_reset(level_duration)) {
bool level = level_duration_get_level(level_duration);
uint32_t duration = level_duration_get_duration(level_duration);
// Yield, to load data inside the worker
furi_thread_yield();
decoder->protocol->decoder->feed(decoder, level, duration);
} else {
break;
}
}
furi_delay_ms(10);
}
if(subghz_file_encoder_worker_is_running(file_worker_encoder_handler)) {
subghz_file_encoder_worker_stop(file_worker_encoder_handler);
}
subghz_file_encoder_worker_free(file_worker_encoder_handler);
}
FURI_LOG_T(TAG, "Decoder count parse %d", subghz_test_decoder_count);
if(furi_get_tick() - test_start > TEST_TIMEOUT) {
printf("Test decoder %s ERROR TimeOut\r\n", name_decoder);
return false;
} else {
return subghz_test_decoder_count ? true : false;
}
}
static bool subghz_decode_random_test(const char* path) {
subghz_test_decoder_count = 0;
subghz_receiver_reset(receiver_handler);
uint32_t test_start = furi_get_tick();
file_worker_encoder_handler = subghz_file_encoder_worker_alloc();
if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path, NULL)) {
// the worker needs a file in order to open and read part of the file
furi_delay_ms(100);
LevelDuration level_duration;
while(furi_get_tick() - test_start < TEST_TIMEOUT * 10) {
level_duration =
subghz_file_encoder_worker_get_level_duration(file_worker_encoder_handler);
if(!level_duration_is_reset(level_duration)) {
bool level = level_duration_get_level(level_duration);
uint32_t duration = level_duration_get_duration(level_duration);
// Yield, to load data inside the worker
furi_thread_yield();
subghz_receiver_decode(receiver_handler, level, duration);
} else {
break;
}
}
furi_delay_ms(10);
if(subghz_file_encoder_worker_is_running(file_worker_encoder_handler)) {
subghz_file_encoder_worker_stop(file_worker_encoder_handler);
}
subghz_file_encoder_worker_free(file_worker_encoder_handler);
}
FURI_LOG_D(TAG, "Decoder count parse %d", subghz_test_decoder_count);
if(furi_get_tick() - test_start > TEST_TIMEOUT * 10) {
printf("Random test ERROR TimeOut\r\n");
return false;
} else if(subghz_test_decoder_count == TEST_RANDOM_COUNT_PARSE) {
return true;
} else {
return false;
}
}
static bool subghz_encoder_test(const char* path) {
subghz_test_decoder_count = 0;
uint32_t test_start = furi_get_tick();
FuriString* temp_str;
temp_str = furi_string_alloc();
bool file_load = false;
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
do {
if(!flipper_format_file_open_existing(fff_data_file, path)) {
FURI_LOG_E(TAG, "Error open file %s", path);
break;
}
if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
FURI_LOG_E(TAG, "Missing Preset");
break;
}
if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
FURI_LOG_E(TAG, "Missing Protocol");
break;
}
file_load = true;
} while(false);
if(file_load) {
SubGhzTransmitter* transmitter =
subghz_transmitter_alloc_init(environment_handler, furi_string_get_cstr(temp_str));
subghz_transmitter_deserialize(transmitter, fff_data_file);
SubGhzProtocolDecoderBase* decoder = subghz_receiver_search_decoder_base_by_name(
receiver_handler, furi_string_get_cstr(temp_str));
if(decoder) {
LevelDuration level_duration;
while(furi_get_tick() - test_start < TEST_TIMEOUT) {
level_duration = subghz_transmitter_yield(transmitter);
if(!level_duration_is_reset(level_duration)) {
bool level = level_duration_get_level(level_duration);
uint32_t duration = level_duration_get_duration(level_duration);
decoder->protocol->decoder->feed(decoder, level, duration);
} else {
break;
}
}
furi_delay_ms(10);
}
subghz_transmitter_free(transmitter);
}
flipper_format_free(fff_data_file);
FURI_LOG_T(TAG, "Decoder count parse %d", subghz_test_decoder_count);
if(furi_get_tick() - test_start > TEST_TIMEOUT) {
printf("Test encoder %s ERROR TimeOut\r\n", furi_string_get_cstr(temp_str));
subghz_test_decoder_count = 0;
}
furi_string_free(temp_str);
return subghz_test_decoder_count ? true : false;
}
MU_TEST(subghz_keystore_test) {
mu_assert(
subghz_environment_load_keystore(environment_handler, KEYSTORE_DIR_NAME),
"Test keystore error");
}
typedef enum {
SubGhzHalAsyncTxTestTypeNormal,
SubGhzHalAsyncTxTestTypeInvalidStart,
SubGhzHalAsyncTxTestTypeInvalidMid,
SubGhzHalAsyncTxTestTypeInvalidEnd,
SubGhzHalAsyncTxTestTypeResetStart,
SubGhzHalAsyncTxTestTypeResetMid,
SubGhzHalAsyncTxTestTypeResetEnd,
} SubGhzHalAsyncTxTestType;
typedef struct {
SubGhzHalAsyncTxTestType type;
size_t pos;
} SubGhzHalAsyncTxTest;
#define SUBGHZ_HAL_TEST_DURATION 3
static LevelDuration subghz_hal_async_tx_test_yield(void* context) {
SubGhzHalAsyncTxTest* test = context;
bool is_odd = test->pos % 2;
if(test->type == SubGhzHalAsyncTxTestTypeNormal) {
if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_reset();
} else {
furi_crash("Yield after reset");
}
} else if(test->type == SubGhzHalAsyncTxTestTypeInvalidStart) {
if(test->pos == 0) {
test->pos++;
return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_reset();
} else {
furi_crash("Yield after reset");
}
} else if(test->type == SubGhzHalAsyncTxTestTypeInvalidMid) {
if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
test->pos++;
return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_reset();
} else {
furi_crash("Yield after reset");
}
} else if(test->type == SubGhzHalAsyncTxTestTypeInvalidEnd) {
if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) {
test->pos++;
return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_reset();
} else {
furi_crash("Yield after reset");
}
} else if(test->type == SubGhzHalAsyncTxTestTypeResetStart) {
if(test->pos == 0) {
test->pos++;
return level_duration_reset();
} else {
furi_crash("Yield after reset");
}
} else if(test->type == SubGhzHalAsyncTxTestTypeResetMid) {
if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
test->pos++;
return level_duration_reset();
} else {
furi_crash("Yield after reset");
}
} else if(test->type == SubGhzHalAsyncTxTestTypeResetEnd) {
if(test->pos < FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == FURI_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL) {
test->pos++;
return level_duration_reset();
} else {
furi_crash("Yield after reset");
}
} else {
furi_crash();
}
}
bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) {
SubGhzHalAsyncTxTest test = {0};
test.type = type;
furi_hal_subghz_reset();
furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs);
furi_hal_subghz_set_frequency_and_path(433920000);
if(!furi_hal_subghz_start_async_tx(subghz_hal_async_tx_test_yield, &test)) {
mu_warn("SubGHZ transmission is prohibited");
return false;
}
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(30000000);
while(!furi_hal_subghz_is_async_tx_complete()) {
if(furi_hal_cortex_timer_is_expired(timer)) {
furi_hal_subghz_stop_async_tx();
furi_hal_subghz_sleep();
return false;
}
furi_delay_ms(10);
}
furi_hal_subghz_stop_async_tx();
furi_hal_subghz_sleep();
return true;
}
MU_TEST(subghz_hal_async_tx_test) {
mu_assert(
subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeNormal),
"Test furi_hal_async_tx normal");
mu_assert(
subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeInvalidStart),
"Test furi_hal_async_tx invalid start");
mu_assert(
subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeInvalidMid),
"Test furi_hal_async_tx invalid mid");
mu_assert(
subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeInvalidEnd),
"Test furi_hal_async_tx invalid end");
mu_assert(
subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeResetStart),
"Test furi_hal_async_tx reset start");
mu_assert(
subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeResetMid),
"Test furi_hal_async_tx reset mid");
mu_assert(
subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeResetEnd),
"Test furi_hal_async_tx reset end");
}
//test decoders
MU_TEST(subghz_decoder_came_atomo_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/came_atomo_raw.sub"), SUBGHZ_PROTOCOL_CAME_ATOMO_NAME),
"Test decoder " SUBGHZ_PROTOCOL_CAME_ATOMO_NAME " error\r\n");
}
MU_TEST(subghz_decoder_came_test) {
mu_assert(
subghz_decoder_test(EXT_PATH("unit_tests/subghz/came_raw.sub"), SUBGHZ_PROTOCOL_CAME_NAME),
"Test decoder " SUBGHZ_PROTOCOL_CAME_NAME " error\r\n");
}
MU_TEST(subghz_decoder_came_twee_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/came_twee_raw.sub"), SUBGHZ_PROTOCOL_CAME_TWEE_NAME),
"Test decoder " SUBGHZ_PROTOCOL_CAME_TWEE_NAME " error\r\n");
}
MU_TEST(subghz_decoder_faac_slh_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/faac_slh_raw.sub"), SUBGHZ_PROTOCOL_FAAC_SLH_NAME),
"Test decoder " SUBGHZ_PROTOCOL_FAAC_SLH_NAME " error\r\n");
}
MU_TEST(subghz_decoder_gate_tx_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/gate_tx_raw.sub"), SUBGHZ_PROTOCOL_GATE_TX_NAME),
"Test decoder " SUBGHZ_PROTOCOL_GATE_TX_NAME " error\r\n");
}
MU_TEST(subghz_decoder_hormann_hsm_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/hormann_hsm_raw.sub"), SUBGHZ_PROTOCOL_HORMANN_HSM_NAME),
"Test decoder " SUBGHZ_PROTOCOL_HORMANN_HSM_NAME " error\r\n");
}
MU_TEST(subghz_decoder_ido_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/ido_117_111_raw.sub"), SUBGHZ_PROTOCOL_IDO_NAME),
"Test decoder " SUBGHZ_PROTOCOL_IDO_NAME " error\r\n");
}
MU_TEST(subghz_decoder_keeloq_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/doorhan_raw.sub"), SUBGHZ_PROTOCOL_KEELOQ_NAME),
"Test decoder " SUBGHZ_PROTOCOL_KEELOQ_NAME " error\r\n");
}
MU_TEST(subghz_decoder_kia_seed_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/kia_seed_raw.sub"), SUBGHZ_PROTOCOL_KIA_NAME),
"Test decoder " SUBGHZ_PROTOCOL_KIA_NAME " error\r\n");
}
MU_TEST(subghz_decoder_nero_radio_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/nero_radio_raw.sub"), SUBGHZ_PROTOCOL_NERO_RADIO_NAME),
"Test decoder " SUBGHZ_PROTOCOL_NERO_RADIO_NAME " error\r\n");
}
MU_TEST(subghz_decoder_nero_sketch_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/nero_sketch_raw.sub"), SUBGHZ_PROTOCOL_NERO_SKETCH_NAME),
"Test decoder " SUBGHZ_PROTOCOL_NERO_SKETCH_NAME " error\r\n");
}
MU_TEST(subghz_decoder_nice_flo_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/nice_flo_raw.sub"), SUBGHZ_PROTOCOL_NICE_FLO_NAME),
"Test decoder " SUBGHZ_PROTOCOL_NICE_FLO_NAME " error\r\n");
}
MU_TEST(subghz_decoder_nice_flor_s_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/nice_flor_s_raw.sub"), SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME),
"Test decoder " SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME " error\r\n");
}
MU_TEST(subghz_decoder_princeton_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/Princeton_raw.sub"), SUBGHZ_PROTOCOL_PRINCETON_NAME),
"Test decoder " SUBGHZ_PROTOCOL_PRINCETON_NAME " error\r\n");
}
MU_TEST(subghz_decoder_scher_khan_magic_code_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/scher_khan_magic_code.sub"),
SUBGHZ_PROTOCOL_SCHER_KHAN_NAME),
"Test decoder " SUBGHZ_PROTOCOL_SCHER_KHAN_NAME " error\r\n");
}
MU_TEST(subghz_decoder_somfy_keytis_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/Somfy_keytis_raw.sub"), SUBGHZ_PROTOCOL_SOMFY_KEYTIS_NAME),
"Test decoder " SUBGHZ_PROTOCOL_SOMFY_KEYTIS_NAME " error\r\n");
}
MU_TEST(subghz_decoder_somfy_telis_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/somfy_telis_raw.sub"), SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME),
"Test decoder " SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME " error\r\n");
}
MU_TEST(subghz_decoder_star_line_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/cenmax_raw.sub"), SUBGHZ_PROTOCOL_STAR_LINE_NAME),
"Test decoder " SUBGHZ_PROTOCOL_STAR_LINE_NAME " error\r\n");
}
MU_TEST(subghz_decoder_linear_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/linear_raw.sub"), SUBGHZ_PROTOCOL_LINEAR_NAME),
"Test decoder " SUBGHZ_PROTOCOL_LINEAR_NAME " error\r\n");
}
MU_TEST(subghz_decoder_linear_delta3_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/linear_delta3_raw.sub"),
SUBGHZ_PROTOCOL_LINEAR_DELTA3_NAME),
"Test decoder " SUBGHZ_PROTOCOL_LINEAR_DELTA3_NAME " error\r\n");
}
MU_TEST(subghz_decoder_megacode_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/megacode_raw.sub"), SUBGHZ_PROTOCOL_MEGACODE_NAME),
"Test decoder " SUBGHZ_PROTOCOL_MEGACODE_NAME " error\r\n");
}
MU_TEST(subghz_decoder_secplus_v1_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/security_pls_1_0_raw.sub"),
SUBGHZ_PROTOCOL_SECPLUS_V1_NAME),
"Test decoder " SUBGHZ_PROTOCOL_SECPLUS_V1_NAME " error\r\n");
}
MU_TEST(subghz_decoder_secplus_v2_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/security_pls_2_0_raw.sub"),
SUBGHZ_PROTOCOL_SECPLUS_V2_NAME),
"Test decoder " SUBGHZ_PROTOCOL_SECPLUS_V2_NAME " error\r\n");
}
MU_TEST(subghz_decoder_holtek_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/holtek_raw.sub"), SUBGHZ_PROTOCOL_HOLTEK_NAME),
"Test decoder " SUBGHZ_PROTOCOL_HOLTEK_NAME " error\r\n");
}
MU_TEST(subghz_decoder_power_smart_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/power_smart_raw.sub"), SUBGHZ_PROTOCOL_POWER_SMART_NAME),
"Test decoder " SUBGHZ_PROTOCOL_POWER_SMART_NAME " error\r\n");
}
MU_TEST(subghz_decoder_marantec_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/marantec_raw.sub"), SUBGHZ_PROTOCOL_MARANTEC_NAME),
"Test decoder " SUBGHZ_PROTOCOL_MARANTEC_NAME " error\r\n");
}
MU_TEST(subghz_decoder_bett_test) {
mu_assert(
subghz_decoder_test(EXT_PATH("unit_tests/subghz/bett_raw.sub"), SUBGHZ_PROTOCOL_BETT_NAME),
"Test decoder " SUBGHZ_PROTOCOL_BETT_NAME " error\r\n");
}
MU_TEST(subghz_decoder_doitrand_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/doitrand_raw.sub"), SUBGHZ_PROTOCOL_DOITRAND_NAME),
"Test decoder " SUBGHZ_PROTOCOL_DOITRAND_NAME " error\r\n");
}
MU_TEST(subghz_decoder_phoenix_v2_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/phoenix_v2_raw.sub"), SUBGHZ_PROTOCOL_PHOENIX_V2_NAME),
"Test decoder " SUBGHZ_PROTOCOL_PHOENIX_V2_NAME " error\r\n");
}
MU_TEST(subghz_decoder_honeywell_wdb_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/honeywell_wdb_raw.sub"),
SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME),
"Test decoder " SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME " error\r\n");
}
MU_TEST(subghz_decoder_magellan_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/magellan_raw.sub"), SUBGHZ_PROTOCOL_MAGELLAN_NAME),
"Test decoder " SUBGHZ_PROTOCOL_MAGELLAN_NAME " error\r\n");
}
MU_TEST(subghz_decoder_intertechno_v3_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/intertechno_v3_raw.sub"),
SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME),
"Test decoder " SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME " error\r\n");
}
MU_TEST(subghz_decoder_clemsa_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/clemsa_raw.sub"), SUBGHZ_PROTOCOL_CLEMSA_NAME),
"Test decoder " SUBGHZ_PROTOCOL_CLEMSA_NAME " error\r\n");
}
MU_TEST(subghz_decoder_ansonic_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/ansonic_raw.sub"), SUBGHZ_PROTOCOL_ANSONIC_NAME),
"Test decoder " SUBGHZ_PROTOCOL_ANSONIC_NAME " error\r\n");
}
MU_TEST(subghz_decoder_smc5326_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/smc5326_raw.sub"), SUBGHZ_PROTOCOL_SMC5326_NAME),
"Test decoder " SUBGHZ_PROTOCOL_SMC5326_NAME " error\r\n");
}
MU_TEST(subghz_decoder_holtek_ht12x_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/holtek_ht12x_raw.sub"), SUBGHZ_PROTOCOL_HOLTEK_HT12X_NAME),
"Test decoder " SUBGHZ_PROTOCOL_HOLTEK_HT12X_NAME " error\r\n");
}
MU_TEST(subghz_decoder_dooya_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/dooya_raw.sub"), SUBGHZ_PROTOCOL_DOOYA_NAME),
"Test decoder " SUBGHZ_PROTOCOL_DOOYA_NAME " error\r\n");
}
MU_TEST(subghz_decoder_alutech_at_4n_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/alutech_at_4n_raw.sub"),
SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME),
"Test decoder " SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME " error\r\n");
}
MU_TEST(subghz_decoder_nice_one_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/nice_one_raw.sub"), SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME),
"Test decoder " SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME " error\r\n");
}
MU_TEST(subghz_decoder_kinggates_stylo4k_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/kinggates_stylo4k_raw.sub"),
SUBGHZ_PROTOCOL_KINGGATES_STYLO_4K_NAME),
"Test decoder " SUBGHZ_PROTOCOL_KINGGATES_STYLO_4K_NAME " error\r\n");
}
MU_TEST(subghz_decoder_mastercode_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/mastercode_raw.sub"), SUBGHZ_PROTOCOL_MASTERCODE_NAME),
"Test decoder " SUBGHZ_PROTOCOL_MASTERCODE_NAME " error\r\n");
}
//test encoders
MU_TEST(subghz_encoder_princeton_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/princeton.sub")),
"Test encoder " SUBGHZ_PROTOCOL_PRINCETON_NAME " error\r\n");
}
MU_TEST(subghz_encoder_came_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/came.sub")),
"Test encoder " SUBGHZ_PROTOCOL_CAME_NAME " error\r\n");
}
MU_TEST(subghz_encoder_came_twee_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/came_twee.sub")),
"Test encoder " SUBGHZ_PROTOCOL_CAME_TWEE_NAME " error\r\n");
}
MU_TEST(subghz_encoder_gate_tx_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/gate_tx.sub")),
"Test encoder " SUBGHZ_PROTOCOL_GATE_TX_NAME " error\r\n");
}
MU_TEST(subghz_encoder_nice_flo_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/nice_flo.sub")),
"Test encoder " SUBGHZ_PROTOCOL_NICE_FLO_NAME " error\r\n");
}
MU_TEST(subghz_encoder_keeloq_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/doorhan.sub")),
"Test encoder " SUBGHZ_PROTOCOL_KEELOQ_NAME " error\r\n");
}
MU_TEST(subghz_encoder_linear_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/linear.sub")),
"Test encoder " SUBGHZ_PROTOCOL_LINEAR_NAME " error\r\n");
}
MU_TEST(subghz_encoder_linear_delta3_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/linear_delta3.sub")),
"Test encoder " SUBGHZ_PROTOCOL_LINEAR_DELTA3_NAME " error\r\n");
}
MU_TEST(subghz_encoder_megacode_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/megacode.sub")),
"Test encoder " SUBGHZ_PROTOCOL_MEGACODE_NAME " error\r\n");
}
MU_TEST(subghz_encoder_holtek_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/holtek.sub")),
"Test encoder " SUBGHZ_PROTOCOL_HOLTEK_NAME " error\r\n");
}
MU_TEST(subghz_encoder_secplus_v1_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/security_pls_1_0.sub")),
"Test encoder " SUBGHZ_PROTOCOL_SECPLUS_V1_NAME " error\r\n");
}
MU_TEST(subghz_encoder_secplus_v2_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/security_pls_2_0.sub")),
"Test encoder " SUBGHZ_PROTOCOL_SECPLUS_V2_NAME " error\r\n");
}
MU_TEST(subghz_encoder_power_smart_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/power_smart.sub")),
"Test encoder " SUBGHZ_PROTOCOL_POWER_SMART_NAME " error\r\n");
}
MU_TEST(subghz_encoder_marantec_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/marantec.sub")),
"Test encoder " SUBGHZ_PROTOCOL_MARANTEC_NAME " error\r\n");
}
MU_TEST(subghz_encoder_bett_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/bett.sub")),
"Test encoder " SUBGHZ_PROTOCOL_BETT_NAME " error\r\n");
}
MU_TEST(subghz_encoder_doitrand_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/doitrand.sub")),
"Test encoder " SUBGHZ_PROTOCOL_DOITRAND_NAME " error\r\n");
}
MU_TEST(subghz_encoder_phoenix_v2_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/phoenix_v2.sub")),
"Test encoder " SUBGHZ_PROTOCOL_PHOENIX_V2_NAME " error\r\n");
}
MU_TEST(subghz_encoder_honeywell_wdb_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/honeywell_wdb.sub")),
"Test encoder " SUBGHZ_PROTOCOL_HONEYWELL_WDB_NAME " error\r\n");
}
MU_TEST(subghz_encoder_magellan_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/magellan.sub")),
"Test encoder " SUBGHZ_PROTOCOL_MAGELLAN_NAME " error\r\n");
}
MU_TEST(subghz_encoder_intertechno_v3_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/intertechno_v3.sub")),
"Test encoder " SUBGHZ_PROTOCOL_INTERTECHNO_V3_NAME " error\r\n");
}
MU_TEST(subghz_encoder_clemsa_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/clemsa.sub")),
"Test encoder " SUBGHZ_PROTOCOL_CLEMSA_NAME " error\r\n");
}
MU_TEST(subghz_encoder_ansonic_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/ansonic.sub")),
"Test encoder " SUBGHZ_PROTOCOL_ANSONIC_NAME " error\r\n");
}
MU_TEST(subghz_encoder_smc5326_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/smc5326.sub")),
"Test encoder " SUBGHZ_PROTOCOL_SMC5326_NAME " error\r\n");
}
MU_TEST(subghz_encoder_holtek_ht12x_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/holtek_ht12x.sub")),
"Test encoder " SUBGHZ_PROTOCOL_HOLTEK_HT12X_NAME " error\r\n");
}
MU_TEST(subghz_encoder_dooya_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/dooya.sub")),
"Test encoder " SUBGHZ_PROTOCOL_DOOYA_NAME " error\r\n");
}
MU_TEST(subghz_encoder_mastercode_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/mastercode.sub")),
"Test encoder " SUBGHZ_PROTOCOL_MASTERCODE_NAME " error\r\n");
}
MU_TEST(subghz_decoder_acurite_592txr_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/acurite_592txr.sub"), WS_PROTOCOL_ACURITE_592TXR_NAME),
"Test decoder " WS_PROTOCOL_ACURITE_592TXR_NAME " error\r\n");
}
MU_TEST(subghz_random_test) {
mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n");
}
MU_TEST_SUITE(subghz) {
subghz_test_init();
MU_RUN_TEST(subghz_keystore_test);
MU_RUN_TEST(subghz_hal_async_tx_test);
MU_RUN_TEST(subghz_decoder_came_atomo_test);
MU_RUN_TEST(subghz_decoder_came_test);
MU_RUN_TEST(subghz_decoder_came_twee_test);
MU_RUN_TEST(subghz_decoder_faac_slh_test);
MU_RUN_TEST(subghz_decoder_gate_tx_test);
MU_RUN_TEST(subghz_decoder_hormann_hsm_test);
MU_RUN_TEST(subghz_decoder_ido_test);
MU_RUN_TEST(subghz_decoder_keeloq_test);
MU_RUN_TEST(subghz_decoder_kia_seed_test);
MU_RUN_TEST(subghz_decoder_nero_radio_test);
MU_RUN_TEST(subghz_decoder_nero_sketch_test);
MU_RUN_TEST(subghz_decoder_nice_flo_test);
MU_RUN_TEST(subghz_decoder_nice_flor_s_test);
MU_RUN_TEST(subghz_decoder_princeton_test);
MU_RUN_TEST(subghz_decoder_scher_khan_magic_code_test);
MU_RUN_TEST(subghz_decoder_somfy_keytis_test);
MU_RUN_TEST(subghz_decoder_somfy_telis_test);
MU_RUN_TEST(subghz_decoder_star_line_test);
MU_RUN_TEST(subghz_decoder_linear_test);
MU_RUN_TEST(subghz_decoder_linear_delta3_test);
MU_RUN_TEST(subghz_decoder_megacode_test);
MU_RUN_TEST(subghz_decoder_secplus_v1_test);
MU_RUN_TEST(subghz_decoder_secplus_v2_test);
MU_RUN_TEST(subghz_decoder_holtek_test);
MU_RUN_TEST(subghz_decoder_power_smart_test);
MU_RUN_TEST(subghz_decoder_marantec_test);
MU_RUN_TEST(subghz_decoder_bett_test);
MU_RUN_TEST(subghz_decoder_doitrand_test);
MU_RUN_TEST(subghz_decoder_phoenix_v2_test);
MU_RUN_TEST(subghz_decoder_honeywell_wdb_test);
MU_RUN_TEST(subghz_decoder_magellan_test);
MU_RUN_TEST(subghz_decoder_intertechno_v3_test);
MU_RUN_TEST(subghz_decoder_clemsa_test);
MU_RUN_TEST(subghz_decoder_ansonic_test);
MU_RUN_TEST(subghz_decoder_smc5326_test);
MU_RUN_TEST(subghz_decoder_holtek_ht12x_test);
MU_RUN_TEST(subghz_decoder_dooya_test);
MU_RUN_TEST(subghz_decoder_alutech_at_4n_test);
MU_RUN_TEST(subghz_decoder_nice_one_test);
MU_RUN_TEST(subghz_decoder_kinggates_stylo4k_test);
MU_RUN_TEST(subghz_decoder_mastercode_test);
MU_RUN_TEST(subghz_encoder_princeton_test);
MU_RUN_TEST(subghz_encoder_came_test);
MU_RUN_TEST(subghz_encoder_came_twee_test);
MU_RUN_TEST(subghz_encoder_gate_tx_test);
MU_RUN_TEST(subghz_encoder_nice_flo_test);
MU_RUN_TEST(subghz_encoder_keeloq_test);
MU_RUN_TEST(subghz_encoder_linear_test);
MU_RUN_TEST(subghz_encoder_linear_delta3_test);
MU_RUN_TEST(subghz_encoder_megacode_test);
MU_RUN_TEST(subghz_encoder_holtek_test);
MU_RUN_TEST(subghz_encoder_secplus_v1_test);
MU_RUN_TEST(subghz_encoder_secplus_v2_test);
MU_RUN_TEST(subghz_encoder_power_smart_test);
MU_RUN_TEST(subghz_encoder_marantec_test);
MU_RUN_TEST(subghz_encoder_bett_test);
MU_RUN_TEST(subghz_encoder_doitrand_test);
MU_RUN_TEST(subghz_encoder_phoenix_v2_test);
MU_RUN_TEST(subghz_encoder_honeywell_wdb_test);
MU_RUN_TEST(subghz_encoder_magellan_test);
MU_RUN_TEST(subghz_encoder_intertechno_v3_test);
MU_RUN_TEST(subghz_encoder_clemsa_test);
MU_RUN_TEST(subghz_encoder_ansonic_test);
MU_RUN_TEST(subghz_encoder_smc5326_test);
MU_RUN_TEST(subghz_encoder_holtek_ht12x_test);
MU_RUN_TEST(subghz_encoder_dooya_test);
MU_RUN_TEST(subghz_encoder_mastercode_test);
MU_RUN_TEST(subghz_decoder_acurite_592txr_test);
MU_RUN_TEST(subghz_random_test);
subghz_test_deinit();
}
int run_minunit_test_subghz(void) {
MU_RUN_SUITE(subghz);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_subghz)

View File

@@ -0,0 +1,12 @@
#pragma once
// Framework
#include "minunit.h"
#include "test_api.h"
int get_minunit_run(void);
int get_minunit_assert(void);
int get_minunit_status(void);

View File

@@ -0,0 +1,29 @@
#pragma once
#include <flipper_application/flipper_application.h>
#define APPID "UnitTest"
#define API_VERSION (0u)
typedef struct {
int (*run)(void);
int (*get_minunit_run)(void);
int (*get_minunit_assert)(void);
int (*get_minunit_status)(void);
} TestApi;
#define TEST_API_DEFINE(entrypoint) \
const TestApi test_api = { \
.run = entrypoint, \
.get_minunit_run = get_minunit_run, \
.get_minunit_assert = get_minunit_assert, \
.get_minunit_status = get_minunit_status, \
}; \
const FlipperAppPluginDescriptor app_descriptor = { \
.appid = APPID, \
.ep_api_version = API_VERSION, \
.entry_point = &test_api, \
}; \
const FlipperAppPluginDescriptor* get_api(void) { \
return &app_descriptor; \
}

View File

@@ -0,0 +1,92 @@
#include <furi.h>
#include <furi_hal.h>
#include "../test.h"
#include <toolbox/varint.h>
#include <toolbox/profiler.h>
MU_TEST(test_varint_basic_u) {
mu_assert_int_eq(1, varint_uint32_length(0));
mu_assert_int_eq(5, varint_uint32_length(UINT32_MAX));
uint8_t data[8] = {};
uint32_t out_value;
mu_assert_int_eq(1, varint_uint32_pack(0, data));
mu_assert_int_eq(1, varint_uint32_unpack(&out_value, data, 8));
mu_assert_int_eq(0, out_value);
mu_assert_int_eq(5, varint_uint32_pack(UINT32_MAX, data));
mu_assert_int_eq(5, varint_uint32_unpack(&out_value, data, 8));
mu_assert_int_eq(UINT32_MAX, out_value);
}
MU_TEST(test_varint_basic_i) {
mu_assert_int_eq(5, varint_int32_length(INT32_MIN / 2));
mu_assert_int_eq(1, varint_int32_length(0));
mu_assert_int_eq(5, varint_int32_length(INT32_MAX / 2));
mu_assert_int_eq(2, varint_int32_length(127));
mu_assert_int_eq(2, varint_int32_length(-127));
uint8_t data[8] = {};
int32_t out_value;
mu_assert_int_eq(1, varint_int32_pack(0, data));
mu_assert_int_eq(1, varint_int32_unpack(&out_value, data, 8));
mu_assert_int_eq(0, out_value);
mu_assert_int_eq(2, varint_int32_pack(127, data));
mu_assert_int_eq(2, varint_int32_unpack(&out_value, data, 8));
mu_assert_int_eq(127, out_value);
mu_assert_int_eq(2, varint_int32_pack(-127, data));
mu_assert_int_eq(2, varint_int32_unpack(&out_value, data, 8));
mu_assert_int_eq(-127, out_value);
mu_assert_int_eq(5, varint_int32_pack(INT32_MAX, data));
mu_assert_int_eq(5, varint_int32_unpack(&out_value, data, 8));
mu_assert_int_eq(INT32_MAX, out_value);
mu_assert_int_eq(5, varint_int32_pack(INT32_MIN / 2 + 1, data));
mu_assert_int_eq(5, varint_int32_unpack(&out_value, data, 8));
mu_assert_int_eq(INT32_MIN / 2 + 1, out_value);
}
MU_TEST(test_varint_rand_u) {
uint8_t data[8] = {};
uint32_t out_value;
for(size_t i = 0; i < 200000; i++) {
uint32_t rand_value = rand();
mu_assert_int_eq(
varint_uint32_pack(rand_value, data), varint_uint32_unpack(&out_value, data, 8));
mu_assert_int_eq(rand_value, out_value);
}
}
MU_TEST(test_varint_rand_i) {
uint8_t data[8] = {};
int32_t out_value;
for(size_t i = 0; i < 200000; i++) {
int32_t rand_value = rand() + (INT32_MIN / 2 + 1);
mu_assert_int_eq(
varint_int32_pack(rand_value, data), varint_int32_unpack(&out_value, data, 8));
mu_assert_int_eq(rand_value, out_value);
}
}
MU_TEST_SUITE(test_varint_suite) {
MU_RUN_TEST(test_varint_basic_u);
MU_RUN_TEST(test_varint_basic_i);
MU_RUN_TEST(test_varint_rand_u);
MU_RUN_TEST(test_varint_rand_i);
}
int run_minunit_test_varint(void) {
MU_RUN_SUITE(test_varint_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_varint)