diff --git a/tests/c/test_basic_default_deserialization.c b/tests/c/test_basic_default_deserialization.c new file mode 100644 index 00000000..748b057f --- /dev/null +++ b/tests/c/test_basic_default_deserialization.c @@ -0,0 +1,124 @@ +/** + * Basic Default frame format deserialization test for C. + */ + +#include +#include +#include +#include + +#include "serialization_test.sf.h" +#include "frame_parsers.h" + +void print_failure_details(const char* label, const void* raw_data, size_t raw_data_size) { + printf("\n"); + printf("============================================================\n"); + printf("FAILURE DETAILS: %s\n", label); + printf("============================================================\n"); + + if (raw_data && raw_data_size > 0) { + printf("\nRaw Data (%zu bytes):\n Hex: ", raw_data_size); + for (size_t i = 0; i < raw_data_size && i < 64; i++) { + printf("%02x", ((const uint8_t*)raw_data)[i]); + } + if (raw_data_size > 64) printf("..."); + printf("\n"); + } + + printf("============================================================\n\n"); +} + +int validate_message(SerializationTestSerializationTestMessage* msg) { + // Expected values from expected_values.json + uint32_t expected_magic = 3735928559; // 0xDEADBEEF + const char* expected_string = "Cross-platform test!"; + float expected_float = 3.14159f; + bool expected_bool = true; + int expected_array[3] = {100, 200, 300}; + + if (msg->magic_number != expected_magic) { + printf(" Value mismatch: magic_number (expected %u, got %u)\n", expected_magic, msg->magic_number); + return 0; + } + + if (strncmp(msg->test_string.data, expected_string, msg->test_string.length) != 0) { + printf(" Value mismatch: test_string\n"); + return 0; + } + + if (fabs(msg->test_float - expected_float) > 0.0001f) { + printf(" Value mismatch: test_float (expected %f, got %f)\n", expected_float, msg->test_float); + return 0; + } + + if (msg->test_bool != expected_bool) { + printf(" Value mismatch: test_bool\n"); + return 0; + } + + if (msg->test_array.count != 3) { + printf(" Value mismatch: test_array.count (expected 3, got %u)\n", msg->test_array.count); + return 0; + } + + for (int i = 0; i < 3; i++) { + if (msg->test_array.data[i] != expected_array[i]) { + printf(" Value mismatch: test_array[%d] (expected %d, got %d)\n", i, expected_array[i], msg->test_array.data[i]); + return 0; + } + } + + return 1; +} + +int read_and_validate_test_data(const char* filename) { + FILE* file = fopen(filename, "rb"); + if (!file) { + printf(" Error: file not found: %s\n", filename); + return 0; + } + + uint8_t buffer[512]; + size_t size = fread(buffer, 1, sizeof(buffer), file); + fclose(file); + + if (size == 0) { + print_failure_details("Empty file", buffer, size); + return 0; + } + + frame_msg_info_t decode_result = basic_default_validate_packet(buffer, size); + + if (!decode_result.valid) { + print_failure_details("Failed to decode data", buffer, size); + return 0; + } + + SerializationTestSerializationTestMessage* decoded_msg = + (SerializationTestSerializationTestMessage*)decode_result.msg_data; + + if (!validate_message(decoded_msg)) { + printf(" Validation failed\n"); + return 0; + } + + printf(" [OK] Data validated successfully\n"); + return 1; +} + +int main(int argc, char* argv[]) { + printf("\n[TEST START] C Basic Default Deserialization\n"); + + if (argc != 2) { + printf(" Usage: %s \n", argv[0]); + printf("[TEST END] C Basic Default Deserialization: FAIL\n\n"); + return 1; + } + + int success = read_and_validate_test_data(argv[1]); + + const char* status = success ? "PASS" : "FAIL"; + printf("[TEST END] C Basic Default Deserialization: %s\n\n", status); + + return success ? 0 : 1; +} diff --git a/tests/c/test_basic_default_serialization.c b/tests/c/test_basic_default_serialization.c new file mode 100644 index 00000000..9ebecc78 --- /dev/null +++ b/tests/c/test_basic_default_serialization.c @@ -0,0 +1,90 @@ +/** + * Basic Default frame format serialization test for C. + */ + +#include +#include +#include + +#include "serialization_test.sf.h" +#include "frame_parsers.h" + +void print_failure_details(const char* label, const void* raw_data, size_t raw_data_size) { + printf("\n"); + printf("============================================================\n"); + printf("FAILURE DETAILS: %s\n", label); + printf("============================================================\n"); + + if (raw_data && raw_data_size > 0) { + printf("\nRaw Data (%zu bytes):\n Hex: ", raw_data_size); + for (size_t i = 0; i < raw_data_size && i < 64; i++) { + printf("%02x", ((const uint8_t*)raw_data)[i]); + } + if (raw_data_size > 64) printf("..."); + printf("\n"); + } + + printf("============================================================\n\n"); +} + +int create_test_data() { + SerializationTestSerializationTestMessage msg = {0}; + + // Use values from expected_values.json + msg.magic_number = 3735928559; // 0xDEADBEEF + msg.test_string.length = strlen("Cross-platform test!"); + strncpy(msg.test_string.data, "Cross-platform test!", msg.test_string.length); + msg.test_float = 3.14159f; + msg.test_bool = true; + msg.test_array.count = 3; + msg.test_array.data[0] = 100; + msg.test_array.data[1] = 200; + msg.test_array.data[2] = 300; + + uint8_t encode_buffer[512]; + size_t encoded_size = basic_default_encode(encode_buffer, sizeof(encode_buffer), + SERIALIZATION_TEST_SERIALIZATION_TEST_MESSAGE_MSG_ID, + (const uint8_t*)&msg, SERIALIZATION_TEST_SERIALIZATION_TEST_MESSAGE_MAX_SIZE); + + if (encoded_size == 0) { + print_failure_details("Encoding failed", NULL, 0); + return 0; + } + + FILE* file = fopen("c_basic_default_test_data.bin", "wb"); + if (!file) { + print_failure_details("File creation failed", NULL, 0); + return 0; + } + + fwrite(encode_buffer, 1, encoded_size, file); + fclose(file); + + // Self-validate + frame_msg_info_t decode_result = basic_default_validate_packet(encode_buffer, encoded_size); + if (!decode_result.valid) { + print_failure_details("Self-validation failed", encode_buffer, encoded_size); + return 0; + } + + SerializationTestSerializationTestMessage* decoded_msg = + (SerializationTestSerializationTestMessage*)decode_result.msg_data; + + if (decoded_msg->magic_number != 3735928559 || decoded_msg->test_array.count != 3) { + print_failure_details("Self-verification failed", encode_buffer, encoded_size); + return 0; + } + + return 1; +} + +int main() { + printf("\n[TEST START] C Basic Default Serialization\n"); + + int success = create_test_data(); + + const char* status = success ? "PASS" : "FAIL"; + printf("[TEST END] C Basic Default Serialization: %s\n\n", status); + + return success ? 0 : 1; +} diff --git a/tests/c/test_basic_minimal_deserialization.c b/tests/c/test_basic_minimal_deserialization.c new file mode 100644 index 00000000..3bf32544 --- /dev/null +++ b/tests/c/test_basic_minimal_deserialization.c @@ -0,0 +1,124 @@ +/** + * Basic Minimal frame format deserialization test for C. + */ + +#include +#include +#include +#include + +#include "serialization_test.sf.h" +#include "frame_parsers.h" + +void print_failure_details(const char* label, const void* raw_data, size_t raw_data_size) { + printf("\n"); + printf("============================================================\n"); + printf("FAILURE DETAILS: %s\n", label); + printf("============================================================\n"); + + if (raw_data && raw_data_size > 0) { + printf("\nRaw Data (%zu bytes):\n Hex: ", raw_data_size); + for (size_t i = 0; i < raw_data_size && i < 64; i++) { + printf("%02x", ((const uint8_t*)raw_data)[i]); + } + if (raw_data_size > 64) printf("..."); + printf("\n"); + } + + printf("============================================================\n\n"); +} + +int validate_message(SerializationTestSerializationTestMessage* msg) { + // Expected values from expected_values.json + uint32_t expected_magic = 3735928559; // 0xDEADBEEF + const char* expected_string = "Cross-platform test!"; + float expected_float = 3.14159f; + bool expected_bool = true; + int expected_array[3] = {100, 200, 300}; + + if (msg->magic_number != expected_magic) { + printf(" Value mismatch: magic_number (expected %u, got %u)\n", expected_magic, msg->magic_number); + return 0; + } + + if (strncmp(msg->test_string.data, expected_string, msg->test_string.length) != 0) { + printf(" Value mismatch: test_string\n"); + return 0; + } + + if (fabs(msg->test_float - expected_float) > 0.0001f) { + printf(" Value mismatch: test_float (expected %f, got %f)\n", expected_float, msg->test_float); + return 0; + } + + if (msg->test_bool != expected_bool) { + printf(" Value mismatch: test_bool\n"); + return 0; + } + + if (msg->test_array.count != 3) { + printf(" Value mismatch: test_array.count (expected 3, got %u)\n", msg->test_array.count); + return 0; + } + + for (int i = 0; i < 3; i++) { + if (msg->test_array.data[i] != expected_array[i]) { + printf(" Value mismatch: test_array[%d] (expected %d, got %d)\n", i, expected_array[i], msg->test_array.data[i]); + return 0; + } + } + + return 1; +} + +int read_and_validate_test_data(const char* filename) { + FILE* file = fopen(filename, "rb"); + if (!file) { + printf(" Error: file not found: %s\n", filename); + return 0; + } + + uint8_t buffer[512]; + size_t size = fread(buffer, 1, sizeof(buffer), file); + fclose(file); + + if (size == 0) { + print_failure_details("Empty file", buffer, size); + return 0; + } + + frame_msg_info_t decode_result = basic_minimal_validate_packet(buffer, size); + + if (!decode_result.valid) { + print_failure_details("Failed to decode data", buffer, size); + return 0; + } + + SerializationTestSerializationTestMessage* decoded_msg = + (SerializationTestSerializationTestMessage*)decode_result.msg_data; + + if (!validate_message(decoded_msg)) { + printf(" Validation failed\n"); + return 0; + } + + printf(" [OK] Data validated successfully\n"); + return 1; +} + +int main(int argc, char* argv[]) { + printf("\n[TEST START] C Basic Minimal Deserialization\n"); + + if (argc != 2) { + printf(" Usage: %s \n", argv[0]); + printf("[TEST END] C Basic Minimal Deserialization: FAIL\n\n"); + return 1; + } + + int success = read_and_validate_test_data(argv[1]); + + const char* status = success ? "PASS" : "FAIL"; + printf("[TEST END] C Basic Minimal Deserialization: %s\n\n", status); + + return success ? 0 : 1; +} diff --git a/tests/c/test_basic_minimal_serialization.c b/tests/c/test_basic_minimal_serialization.c new file mode 100644 index 00000000..c44ccd1f --- /dev/null +++ b/tests/c/test_basic_minimal_serialization.c @@ -0,0 +1,90 @@ +/** + * Basic Minimal frame format serialization test for C. + */ + +#include +#include +#include + +#include "serialization_test.sf.h" +#include "frame_parsers.h" + +void print_failure_details(const char* label, const void* raw_data, size_t raw_data_size) { + printf("\n"); + printf("============================================================\n"); + printf("FAILURE DETAILS: %s\n", label); + printf("============================================================\n"); + + if (raw_data && raw_data_size > 0) { + printf("\nRaw Data (%zu bytes):\n Hex: ", raw_data_size); + for (size_t i = 0; i < raw_data_size && i < 64; i++) { + printf("%02x", ((const uint8_t*)raw_data)[i]); + } + if (raw_data_size > 64) printf("..."); + printf("\n"); + } + + printf("============================================================\n\n"); +} + +int create_test_data() { + SerializationTestSerializationTestMessage msg = {0}; + + // Use values from expected_values.json + msg.magic_number = 3735928559; // 0xDEADBEEF + msg.test_string.length = strlen("Cross-platform test!"); + strncpy(msg.test_string.data, "Cross-platform test!", msg.test_string.length); + msg.test_float = 3.14159f; + msg.test_bool = true; + msg.test_array.count = 3; + msg.test_array.data[0] = 100; + msg.test_array.data[1] = 200; + msg.test_array.data[2] = 300; + + uint8_t encode_buffer[512]; + size_t encoded_size = basic_minimal_encode(encode_buffer, sizeof(encode_buffer), + SERIALIZATION_TEST_SERIALIZATION_TEST_MESSAGE_MSG_ID, + (const uint8_t*)&msg, SERIALIZATION_TEST_SERIALIZATION_TEST_MESSAGE_MAX_SIZE); + + if (encoded_size == 0) { + print_failure_details("Encoding failed", NULL, 0); + return 0; + } + + FILE* file = fopen("c_basic_minimal_test_data.bin", "wb"); + if (!file) { + print_failure_details("File creation failed", NULL, 0); + return 0; + } + + fwrite(encode_buffer, 1, encoded_size, file); + fclose(file); + + // Self-validate + frame_msg_info_t decode_result = basic_minimal_validate_packet(encode_buffer, encoded_size); + if (!decode_result.valid) { + print_failure_details("Self-validation failed", encode_buffer, encoded_size); + return 0; + } + + SerializationTestSerializationTestMessage* decoded_msg = + (SerializationTestSerializationTestMessage*)decode_result.msg_data; + + if (decoded_msg->magic_number != 3735928559 || decoded_msg->test_array.count != 3) { + print_failure_details("Self-verification failed", encode_buffer, encoded_size); + return 0; + } + + return 1; +} + +int main() { + printf("\n[TEST START] C Basic Minimal Serialization\n"); + + int success = create_test_data(); + + const char* status = success ? "PASS" : "FAIL"; + printf("[TEST END] C Basic Minimal Serialization: %s\n\n", status); + + return success ? 0 : 1; +} diff --git a/tests/c/test_tiny_default_deserialization.c b/tests/c/test_tiny_default_deserialization.c new file mode 100644 index 00000000..a3833c9e --- /dev/null +++ b/tests/c/test_tiny_default_deserialization.c @@ -0,0 +1,124 @@ +/** + * Tiny Default frame format deserialization test for C. + */ + +#include +#include +#include +#include + +#include "serialization_test.sf.h" +#include "frame_parsers.h" + +void print_failure_details(const char* label, const void* raw_data, size_t raw_data_size) { + printf("\n"); + printf("============================================================\n"); + printf("FAILURE DETAILS: %s\n", label); + printf("============================================================\n"); + + if (raw_data && raw_data_size > 0) { + printf("\nRaw Data (%zu bytes):\n Hex: ", raw_data_size); + for (size_t i = 0; i < raw_data_size && i < 64; i++) { + printf("%02x", ((const uint8_t*)raw_data)[i]); + } + if (raw_data_size > 64) printf("..."); + printf("\n"); + } + + printf("============================================================\n\n"); +} + +int validate_message(SerializationTestSerializationTestMessage* msg) { + // Expected values from expected_values.json + uint32_t expected_magic = 3735928559; // 0xDEADBEEF + const char* expected_string = "Cross-platform test!"; + float expected_float = 3.14159f; + bool expected_bool = true; + int expected_array[3] = {100, 200, 300}; + + if (msg->magic_number != expected_magic) { + printf(" Value mismatch: magic_number (expected %u, got %u)\n", expected_magic, msg->magic_number); + return 0; + } + + if (strncmp(msg->test_string.data, expected_string, msg->test_string.length) != 0) { + printf(" Value mismatch: test_string\n"); + return 0; + } + + if (fabs(msg->test_float - expected_float) > 0.0001f) { + printf(" Value mismatch: test_float (expected %f, got %f)\n", expected_float, msg->test_float); + return 0; + } + + if (msg->test_bool != expected_bool) { + printf(" Value mismatch: test_bool\n"); + return 0; + } + + if (msg->test_array.count != 3) { + printf(" Value mismatch: test_array.count (expected 3, got %u)\n", msg->test_array.count); + return 0; + } + + for (int i = 0; i < 3; i++) { + if (msg->test_array.data[i] != expected_array[i]) { + printf(" Value mismatch: test_array[%d] (expected %d, got %d)\n", i, expected_array[i], msg->test_array.data[i]); + return 0; + } + } + + return 1; +} + +int read_and_validate_test_data(const char* filename) { + FILE* file = fopen(filename, "rb"); + if (!file) { + printf(" Error: file not found: %s\n", filename); + return 0; + } + + uint8_t buffer[512]; + size_t size = fread(buffer, 1, sizeof(buffer), file); + fclose(file); + + if (size == 0) { + print_failure_details("Empty file", buffer, size); + return 0; + } + + frame_msg_info_t decode_result = tiny_default_validate_packet(buffer, size); + + if (!decode_result.valid) { + print_failure_details("Failed to decode data", buffer, size); + return 0; + } + + SerializationTestSerializationTestMessage* decoded_msg = + (SerializationTestSerializationTestMessage*)decode_result.msg_data; + + if (!validate_message(decoded_msg)) { + printf(" Validation failed\n"); + return 0; + } + + printf(" [OK] Data validated successfully\n"); + return 1; +} + +int main(int argc, char* argv[]) { + printf("\n[TEST START] C Tiny Default Deserialization\n"); + + if (argc != 2) { + printf(" Usage: %s \n", argv[0]); + printf("[TEST END] C Tiny Default Deserialization: FAIL\n\n"); + return 1; + } + + int success = read_and_validate_test_data(argv[1]); + + const char* status = success ? "PASS" : "FAIL"; + printf("[TEST END] C Tiny Default Deserialization: %s\n\n", status); + + return success ? 0 : 1; +} diff --git a/tests/c/test_tiny_default_serialization.c b/tests/c/test_tiny_default_serialization.c new file mode 100644 index 00000000..cd2c105a --- /dev/null +++ b/tests/c/test_tiny_default_serialization.c @@ -0,0 +1,90 @@ +/** + * Tiny Default frame format serialization test for C. + */ + +#include +#include +#include + +#include "serialization_test.sf.h" +#include "frame_parsers.h" + +void print_failure_details(const char* label, const void* raw_data, size_t raw_data_size) { + printf("\n"); + printf("============================================================\n"); + printf("FAILURE DETAILS: %s\n", label); + printf("============================================================\n"); + + if (raw_data && raw_data_size > 0) { + printf("\nRaw Data (%zu bytes):\n Hex: ", raw_data_size); + for (size_t i = 0; i < raw_data_size && i < 64; i++) { + printf("%02x", ((const uint8_t*)raw_data)[i]); + } + if (raw_data_size > 64) printf("..."); + printf("\n"); + } + + printf("============================================================\n\n"); +} + +int create_test_data() { + SerializationTestSerializationTestMessage msg = {0}; + + // Use values from expected_values.json + msg.magic_number = 3735928559; // 0xDEADBEEF + msg.test_string.length = strlen("Cross-platform test!"); + strncpy(msg.test_string.data, "Cross-platform test!", msg.test_string.length); + msg.test_float = 3.14159f; + msg.test_bool = true; + msg.test_array.count = 3; + msg.test_array.data[0] = 100; + msg.test_array.data[1] = 200; + msg.test_array.data[2] = 300; + + uint8_t encode_buffer[512]; + size_t encoded_size = tiny_default_encode(encode_buffer, sizeof(encode_buffer), + SERIALIZATION_TEST_SERIALIZATION_TEST_MESSAGE_MSG_ID, + (const uint8_t*)&msg, SERIALIZATION_TEST_SERIALIZATION_TEST_MESSAGE_MAX_SIZE); + + if (encoded_size == 0) { + print_failure_details("Encoding failed", NULL, 0); + return 0; + } + + FILE* file = fopen("c_tiny_default_test_data.bin", "wb"); + if (!file) { + print_failure_details("File creation failed", NULL, 0); + return 0; + } + + fwrite(encode_buffer, 1, encoded_size, file); + fclose(file); + + // Self-validate + frame_msg_info_t decode_result = tiny_default_validate_packet(encode_buffer, encoded_size); + if (!decode_result.valid) { + print_failure_details("Self-validation failed", encode_buffer, encoded_size); + return 0; + } + + SerializationTestSerializationTestMessage* decoded_msg = + (SerializationTestSerializationTestMessage*)decode_result.msg_data; + + if (decoded_msg->magic_number != 3735928559 || decoded_msg->test_array.count != 3) { + print_failure_details("Self-verification failed", encode_buffer, encoded_size); + return 0; + } + + return 1; +} + +int main() { + printf("\n[TEST START] C Tiny Default Serialization\n"); + + int success = create_test_data(); + + const char* status = success ? "PASS" : "FAIL"; + printf("[TEST END] C Tiny Default Serialization: %s\n\n", status); + + return success ? 0 : 1; +} diff --git a/tests/c/test_tiny_minimal_deserialization.c b/tests/c/test_tiny_minimal_deserialization.c new file mode 100644 index 00000000..38f2b824 --- /dev/null +++ b/tests/c/test_tiny_minimal_deserialization.c @@ -0,0 +1,124 @@ +/** + * Tiny Minimal frame format deserialization test for C. + */ + +#include +#include +#include +#include + +#include "serialization_test.sf.h" +#include "frame_parsers.h" + +void print_failure_details(const char* label, const void* raw_data, size_t raw_data_size) { + printf("\n"); + printf("============================================================\n"); + printf("FAILURE DETAILS: %s\n", label); + printf("============================================================\n"); + + if (raw_data && raw_data_size > 0) { + printf("\nRaw Data (%zu bytes):\n Hex: ", raw_data_size); + for (size_t i = 0; i < raw_data_size && i < 64; i++) { + printf("%02x", ((const uint8_t*)raw_data)[i]); + } + if (raw_data_size > 64) printf("..."); + printf("\n"); + } + + printf("============================================================\n\n"); +} + +int validate_message(SerializationTestSerializationTestMessage* msg) { + // Expected values from expected_values.json + uint32_t expected_magic = 3735928559; // 0xDEADBEEF + const char* expected_string = "Cross-platform test!"; + float expected_float = 3.14159f; + bool expected_bool = true; + int expected_array[3] = {100, 200, 300}; + + if (msg->magic_number != expected_magic) { + printf(" Value mismatch: magic_number (expected %u, got %u)\n", expected_magic, msg->magic_number); + return 0; + } + + if (strncmp(msg->test_string.data, expected_string, msg->test_string.length) != 0) { + printf(" Value mismatch: test_string\n"); + return 0; + } + + if (fabs(msg->test_float - expected_float) > 0.0001f) { + printf(" Value mismatch: test_float (expected %f, got %f)\n", expected_float, msg->test_float); + return 0; + } + + if (msg->test_bool != expected_bool) { + printf(" Value mismatch: test_bool\n"); + return 0; + } + + if (msg->test_array.count != 3) { + printf(" Value mismatch: test_array.count (expected 3, got %u)\n", msg->test_array.count); + return 0; + } + + for (int i = 0; i < 3; i++) { + if (msg->test_array.data[i] != expected_array[i]) { + printf(" Value mismatch: test_array[%d] (expected %d, got %d)\n", i, expected_array[i], msg->test_array.data[i]); + return 0; + } + } + + return 1; +} + +int read_and_validate_test_data(const char* filename) { + FILE* file = fopen(filename, "rb"); + if (!file) { + printf(" Error: file not found: %s\n", filename); + return 0; + } + + uint8_t buffer[512]; + size_t size = fread(buffer, 1, sizeof(buffer), file); + fclose(file); + + if (size == 0) { + print_failure_details("Empty file", buffer, size); + return 0; + } + + frame_msg_info_t decode_result = tiny_minimal_validate_packet(buffer, size); + + if (!decode_result.valid) { + print_failure_details("Failed to decode data", buffer, size); + return 0; + } + + SerializationTestSerializationTestMessage* decoded_msg = + (SerializationTestSerializationTestMessage*)decode_result.msg_data; + + if (!validate_message(decoded_msg)) { + printf(" Validation failed\n"); + return 0; + } + + printf(" [OK] Data validated successfully\n"); + return 1; +} + +int main(int argc, char* argv[]) { + printf("\n[TEST START] C Tiny Minimal Deserialization\n"); + + if (argc != 2) { + printf(" Usage: %s \n", argv[0]); + printf("[TEST END] C Tiny Minimal Deserialization: FAIL\n\n"); + return 1; + } + + int success = read_and_validate_test_data(argv[1]); + + const char* status = success ? "PASS" : "FAIL"; + printf("[TEST END] C Tiny Minimal Deserialization: %s\n\n", status); + + return success ? 0 : 1; +} diff --git a/tests/c/test_tiny_minimal_serialization.c b/tests/c/test_tiny_minimal_serialization.c new file mode 100644 index 00000000..496aa95e --- /dev/null +++ b/tests/c/test_tiny_minimal_serialization.c @@ -0,0 +1,90 @@ +/** + * Tiny Minimal frame format serialization test for C. + */ + +#include +#include +#include + +#include "serialization_test.sf.h" +#include "frame_parsers.h" + +void print_failure_details(const char* label, const void* raw_data, size_t raw_data_size) { + printf("\n"); + printf("============================================================\n"); + printf("FAILURE DETAILS: %s\n", label); + printf("============================================================\n"); + + if (raw_data && raw_data_size > 0) { + printf("\nRaw Data (%zu bytes):\n Hex: ", raw_data_size); + for (size_t i = 0; i < raw_data_size && i < 64; i++) { + printf("%02x", ((const uint8_t*)raw_data)[i]); + } + if (raw_data_size > 64) printf("..."); + printf("\n"); + } + + printf("============================================================\n\n"); +} + +int create_test_data() { + SerializationTestSerializationTestMessage msg = {0}; + + // Use values from expected_values.json + msg.magic_number = 3735928559; // 0xDEADBEEF + msg.test_string.length = strlen("Cross-platform test!"); + strncpy(msg.test_string.data, "Cross-platform test!", msg.test_string.length); + msg.test_float = 3.14159f; + msg.test_bool = true; + msg.test_array.count = 3; + msg.test_array.data[0] = 100; + msg.test_array.data[1] = 200; + msg.test_array.data[2] = 300; + + uint8_t encode_buffer[512]; + size_t encoded_size = tiny_minimal_encode(encode_buffer, sizeof(encode_buffer), + SERIALIZATION_TEST_SERIALIZATION_TEST_MESSAGE_MSG_ID, + (const uint8_t*)&msg, SERIALIZATION_TEST_SERIALIZATION_TEST_MESSAGE_MAX_SIZE); + + if (encoded_size == 0) { + print_failure_details("Encoding failed", NULL, 0); + return 0; + } + + FILE* file = fopen("c_tiny_minimal_test_data.bin", "wb"); + if (!file) { + print_failure_details("File creation failed", NULL, 0); + return 0; + } + + fwrite(encode_buffer, 1, encoded_size, file); + fclose(file); + + // Self-validate + frame_msg_info_t decode_result = tiny_minimal_validate_packet(encode_buffer, encoded_size); + if (!decode_result.valid) { + print_failure_details("Self-validation failed", encode_buffer, encoded_size); + return 0; + } + + SerializationTestSerializationTestMessage* decoded_msg = + (SerializationTestSerializationTestMessage*)decode_result.msg_data; + + if (decoded_msg->magic_number != 3735928559 || decoded_msg->test_array.count != 3) { + print_failure_details("Self-verification failed", encode_buffer, encoded_size); + return 0; + } + + return 1; +} + +int main() { + printf("\n[TEST START] C Tiny Minimal Serialization\n"); + + int success = create_test_data(); + + const char* status = success ? "PASS" : "FAIL"; + printf("[TEST END] C Tiny Minimal Serialization: %s\n\n", status); + + return success ? 0 : 1; +} diff --git a/tests/js/test_basic_default_deserialization.js b/tests/js/test_basic_default_deserialization.js new file mode 100644 index 00000000..f10bab99 --- /dev/null +++ b/tests/js/test_basic_default_deserialization.js @@ -0,0 +1,132 @@ +/** + * Basic Default frame format deserialization test for JavaScript. + */ +"use strict"; + +const fs = require('fs'); +const path = require('path'); + +// BasicDefault constants +const BASIC_DEFAULT_START_BYTE1 = 0x90; +const BASIC_DEFAULT_START_BYTE2 = 0x71; +const BASIC_DEFAULT_HEADER_SIZE = 4; +const BASIC_DEFAULT_FOOTER_SIZE = 2; + +function printFailureDetails(label) { + console.log('\n============================================================'); + console.log('FAILURE DETAILS: ' + label); + console.log('============================================================\n'); +} + +function loadExpectedValues() { + try { + const jsonPath = path.join(__dirname, '../../expected_values.json'); + const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8')); + return data.serialization_test; + } catch (error) { + console.log('Error loading expected values: ' + error); + return null; + } +} + +function validateBasicDefault(buffer, expected) { + if (buffer.length < BASIC_DEFAULT_HEADER_SIZE + BASIC_DEFAULT_FOOTER_SIZE) { + console.log(' Data too short'); + return false; + } + + if (buffer[0] !== BASIC_DEFAULT_START_BYTE1 || buffer[1] !== BASIC_DEFAULT_START_BYTE2) { + console.log(' Invalid start bytes'); + return false; + } + + if (buffer[3] !== 204) { + console.log(' Invalid message ID'); + return false; + } + + // Validate checksum + const msgLen = buffer.length - BASIC_DEFAULT_HEADER_SIZE - BASIC_DEFAULT_FOOTER_SIZE; + let byte1 = buffer[2]; + let byte2 = buffer[2]; + byte1 = (byte1 + buffer[3]) % 256; + byte2 = (byte2 + byte1) % 256; + for (let i = 0; i < msgLen; i++) { + byte1 = (byte1 + buffer[BASIC_DEFAULT_HEADER_SIZE + i]) & 0xFF; + byte2 = (byte2 + byte1) & 0xFF; + } + + if (byte1 !== buffer[buffer.length - 2] || byte2 !== buffer[buffer.length - 1]) { + console.log(' Checksum mismatch'); + return false; + } + + const magicNumber = buffer.readUInt32LE(BASIC_DEFAULT_HEADER_SIZE); + if (magicNumber !== expected.magic_number) { + console.log(' Magic number mismatch'); + return false; + } + + console.log(' [OK] Data validated successfully'); + return true; +} + +function readAndValidateTestData(filename) { + try { + if (!fs.existsSync(filename)) { + console.log(' Error: file not found: ' + filename); + return false; + } + + const binaryData = fs.readFileSync(filename); + + if (binaryData.length === 0) { + printFailureDetails('Empty file'); + return false; + } + + const expected = loadExpectedValues(); + if (!expected) { + return false; + } + + if (!validateBasicDefault(binaryData, expected)) { + console.log(' Validation failed'); + return false; + } + + return true; + } catch (error) { + printFailureDetails('Read data exception: ' + error); + return false; + } +} + +function main() { + console.log('\n[TEST START] JavaScript Basic Default Deserialization'); + + const args = process.argv.slice(2); + if (args.length !== 1) { + console.log(' Usage: ' + process.argv[1] + ' '); + console.log('[TEST END] JavaScript Basic Default Deserialization: FAIL\n'); + return false; + } + + try { + const success = readAndValidateTestData(args[0]); + + console.log('[TEST END] JavaScript Basic Default Deserialization: ' + (success ? 'PASS' : 'FAIL') + '\n'); + return success; + } catch (error) { + printFailureDetails('Exception: ' + error); + console.log('[TEST END] JavaScript Basic Default Deserialization: FAIL\n'); + return false; + } +} + +if (require.main === module) { + const success = main(); + process.exit(success ? 0 : 1); +} + +module.exports.main = main; diff --git a/tests/js/test_basic_default_serialization.js b/tests/js/test_basic_default_serialization.js new file mode 100644 index 00000000..1736486f --- /dev/null +++ b/tests/js/test_basic_default_serialization.js @@ -0,0 +1,153 @@ +/** + * Basic Default frame format serialization test for JavaScript. + */ +"use strict"; + +const fs = require('fs'); +const path = require('path'); + +// BasicDefault constants +const BASIC_DEFAULT_START_BYTE1 = 0x90; +const BASIC_DEFAULT_START_BYTE2 = 0x71; +const BASIC_DEFAULT_HEADER_SIZE = 4; // start1 + start2 + length + msg_id +const BASIC_DEFAULT_FOOTER_SIZE = 2; // crc1 + crc2 + +function printFailureDetails(label, expectedValues, actualValues, rawData) { + console.log('\n============================================================'); + console.log('FAILURE DETAILS: ' + label); + console.log('============================================================'); + + if (expectedValues) { + console.log('\nExpected Values:'); + for (const [key, val] of Object.entries(expectedValues)) { + console.log(' ' + key + ': ' + val); + } + } + + if (actualValues) { + console.log('\nActual Values:'); + for (const [key, val] of Object.entries(actualValues)) { + console.log(' ' + key + ': ' + val); + } + } + + if (rawData && rawData.length > 0) { + console.log('\nRaw Data (' + rawData.length + ' bytes):'); + console.log(' Hex: ' + rawData.toString('hex').substring(0, 128) + (rawData.length > 64 ? '...' : '')); + } + + console.log('============================================================\n'); +} + +function loadExpectedValues() { + try { + const jsonPath = path.join(__dirname, '../../expected_values.json'); + const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8')); + return data.serialization_test; + } catch (error) { + console.log('Error loading expected values: ' + error); + return null; + } +} + +function createTestData() { + try { + const expected = loadExpectedValues(); + if (!expected) { + return false; + } + + const msg_id = 204; + const payloadSize = 95; + const payload = Buffer.alloc(payloadSize); + let offset = 0; + + // magic_number (uint32, little-endian) + payload.writeUInt32LE(expected.magic_number, offset); + offset += 4; + + // test_string: length byte + 64 bytes of data + const testString = expected.test_string; + payload.writeUInt8(testString.length, offset); + offset += 1; + Buffer.from(testString).copy(payload, offset, 0, testString.length); + offset += 64; + + // test_float (float, little-endian) + payload.writeFloatLE(expected.test_float, offset); + offset += 4; + + // test_bool (1 byte) + payload.writeUInt8(expected.test_bool ? 1 : 0, offset); + offset += 1; + + // test_array: count byte + int32 data (5 elements max) + const testArray = expected.test_array; + payload.writeUInt8(testArray.length, offset); + offset += 1; + for (let i = 0; i < 5; i++) { + if (i < testArray.length) { + payload.writeInt32LE(testArray[i], offset); + } else { + payload.writeInt32LE(0, offset); + } + offset += 4; + } + + // Calculate Fletcher checksum on length + msg_id + payload + let byte1 = payloadSize & 0xFF; + let byte2 = payloadSize & 0xFF; + byte1 = (byte1 + msg_id) & 0xFF; + byte2 = (byte2 + byte1) & 0xFF; + for (let i = 0; i < payload.length; i++) { + byte1 = (byte1 + payload[i]) & 0xFF; + byte2 = (byte2 + byte1) & 0xFF; + } + + // Build complete frame + const frame = Buffer.alloc(BASIC_DEFAULT_HEADER_SIZE + payloadSize + BASIC_DEFAULT_FOOTER_SIZE); + frame[0] = BASIC_DEFAULT_START_BYTE1; + frame[1] = BASIC_DEFAULT_START_BYTE2; + frame[2] = payloadSize & 0xFF; + frame[3] = msg_id; + payload.copy(frame, BASIC_DEFAULT_HEADER_SIZE); + frame[frame.length - 2] = byte1; + frame[frame.length - 1] = byte2; + + // Write to file + const outputPath = fs.existsSync('tests/generated/js') + ? 'tests/generated/js/javascript_basic_default_test_data.bin' + : 'javascript_basic_default_test_data.bin'; + fs.writeFileSync(outputPath, frame); + + return true; + } catch (error) { + printFailureDetails('Create test data exception: ' + error); + return false; + } +} + +function main() { + console.log('\n[TEST START] JavaScript Basic Default Serialization'); + + try { + if (!createTestData()) { + console.log('[TEST END] JavaScript Basic Default Serialization: FAIL\n'); + return false; + } + + console.log('[TEST END] JavaScript Basic Default Serialization: PASS\n'); + return true; + } catch (error) { + printFailureDetails('Exception: ' + error); + console.log('[TEST END] JavaScript Basic Default Serialization: FAIL\n'); + return false; + } +} + +if (require.main === module) { + const success = main(); + process.exit(success ? 0 : 1); +} + +module.exports.main = main; diff --git a/tests/js/test_basic_minimal_deserialization.js b/tests/js/test_basic_minimal_deserialization.js new file mode 100644 index 00000000..d504ba2f --- /dev/null +++ b/tests/js/test_basic_minimal_deserialization.js @@ -0,0 +1,118 @@ +/** + * Basic Minimal frame format deserialization test for JavaScript. + */ +"use strict"; + +const fs = require('fs'); +const path = require('path'); + +// BasicMinimal constants +const BASIC_MINIMAL_START_BYTE1 = 0x90; +const BASIC_MINIMAL_START_BYTE2 = 0x70; +const BASIC_MINIMAL_HEADER_SIZE = 3; +const BASIC_MINIMAL_FOOTER_SIZE = 0; + +function printFailureDetails(label) { + console.log('\n============================================================'); + console.log('FAILURE DETAILS: ' + label); + console.log('============================================================\n'); +} + +function loadExpectedValues() { + try { + const jsonPath = path.join(__dirname, '../../expected_values.json'); + const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8')); + return data.serialization_test; + } catch (error) { + console.log('Error loading expected values: ' + error); + return null; + } +} + +function validateBasicMinimal(buffer, expected) { + if (buffer.length < BASIC_MINIMAL_HEADER_SIZE + BASIC_MINIMAL_FOOTER_SIZE) { + console.log(' Data too short'); + return false; + } + + if (buffer[0] !== BASIC_MINIMAL_START_BYTE1 || buffer[1] !== BASIC_MINIMAL_START_BYTE2) { + console.log(' Invalid start bytes'); + return false; + } + + if (buffer[2] !== 204) { + console.log(' Invalid message ID'); + return false; + } + + // No CRC validation for minimal format + + const magicNumber = buffer.readUInt32LE(BASIC_MINIMAL_HEADER_SIZE); + if (magicNumber !== expected.magic_number) { + console.log(' Magic number mismatch'); + return false; + } + + console.log(' [OK] Data validated successfully'); + return true; +} + +function readAndValidateTestData(filename) { + try { + if (!fs.existsSync(filename)) { + console.log(' Error: file not found: ' + filename); + return false; + } + + const binaryData = fs.readFileSync(filename); + + if (binaryData.length === 0) { + printFailureDetails('Empty file'); + return false; + } + + const expected = loadExpectedValues(); + if (!expected) { + return false; + } + + if (!validateBasicMinimal(binaryData, expected)) { + console.log(' Validation failed'); + return false; + } + + return true; + } catch (error) { + printFailureDetails('Read data exception: ' + error); + return false; + } +} + +function main() { + console.log('\n[TEST START] JavaScript Basic Minimal Deserialization'); + + const args = process.argv.slice(2); + if (args.length !== 1) { + console.log(' Usage: ' + process.argv[1] + ' '); + console.log('[TEST END] JavaScript Basic Minimal Deserialization: FAIL\n'); + return false; + } + + try { + const success = readAndValidateTestData(args[0]); + + console.log('[TEST END] JavaScript Basic Minimal Deserialization: ' + (success ? 'PASS' : 'FAIL') + '\n'); + return success; + } catch (error) { + printFailureDetails('Exception: ' + error); + console.log('[TEST END] JavaScript Basic Minimal Deserialization: FAIL\n'); + return false; + } +} + +if (require.main === module) { + const success = main(); + process.exit(success ? 0 : 1); +} + +module.exports.main = main; diff --git a/tests/js/test_basic_minimal_serialization.js b/tests/js/test_basic_minimal_serialization.js new file mode 100644 index 00000000..0ee7051b --- /dev/null +++ b/tests/js/test_basic_minimal_serialization.js @@ -0,0 +1,126 @@ +/** + * Basic Minimal frame format serialization test for JavaScript. + */ +"use strict"; + +const fs = require('fs'); +const path = require('path'); + +// BasicMinimal constants +const BASIC_MINIMAL_START_BYTE1 = 0x90; +const BASIC_MINIMAL_START_BYTE2 = 0x70; +const BASIC_MINIMAL_HEADER_SIZE = 3; // start1 + start2 + msg_id +const BASIC_MINIMAL_FOOTER_SIZE = 0; // no crc + +function printFailureDetails(label, expectedValues, actualValues, rawData) { + console.log('\n============================================================'); + console.log('FAILURE DETAILS: ' + label); + console.log('============================================================'); + + if (rawData && rawData.length > 0) { + console.log('\nRaw Data (' + rawData.length + ' bytes):'); + console.log(' Hex: ' + rawData.toString('hex').substring(0, 128) + (rawData.length > 64 ? '...' : '')); + } + + console.log('============================================================\n'); +} + +function loadExpectedValues() { + try { + const jsonPath = path.join(__dirname, '../../expected_values.json'); + const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8')); + return data.serialization_test; + } catch (error) { + console.log('Error loading expected values: ' + error); + return null; + } +} + +function createTestData() { + try { + const expected = loadExpectedValues(); + if (!expected) { + return false; + } + + const msg_id = 204; + const payloadSize = 95; + const payload = Buffer.alloc(payloadSize); + let offset = 0; + + // magic_number (uint32, little-endian) + payload.writeUInt32LE(expected.magic_number, offset); + offset += 4; + + // test_string: length byte + 64 bytes of data + const testString = expected.test_string; + payload.writeUInt8(testString.length, offset); + offset += 1; + Buffer.from(testString).copy(payload, offset, 0, testString.length); + offset += 64; + + // test_float (float, little-endian) + payload.writeFloatLE(expected.test_float, offset); + offset += 4; + + // test_bool (1 byte) + payload.writeUInt8(expected.test_bool ? 1 : 0, offset); + offset += 1; + + // test_array: count byte + int32 data (5 elements max) + const testArray = expected.test_array; + payload.writeUInt8(testArray.length, offset); + offset += 1; + for (let i = 0; i < 5; i++) { + if (i < testArray.length) { + payload.writeInt32LE(testArray[i], offset); + } else { + payload.writeInt32LE(0, offset); + } + offset += 4; + } + + // Build complete frame (no CRC for minimal) + const frame = Buffer.alloc(BASIC_MINIMAL_HEADER_SIZE + payloadSize + BASIC_MINIMAL_FOOTER_SIZE); + frame[0] = BASIC_MINIMAL_START_BYTE1; + frame[1] = BASIC_MINIMAL_START_BYTE2; + frame[2] = msg_id; + payload.copy(frame, BASIC_MINIMAL_HEADER_SIZE); + + // Write to file + const outputPath = fs.existsSync('tests/generated/js') + ? 'tests/generated/js/javascript_basic_minimal_test_data.bin' + : 'javascript_basic_minimal_test_data.bin'; + fs.writeFileSync(outputPath, frame); + + return true; + } catch (error) { + printFailureDetails('Create test data exception: ' + error); + return false; + } +} + +function main() { + console.log('\n[TEST START] JavaScript Basic Minimal Serialization'); + + try { + if (!createTestData()) { + console.log('[TEST END] JavaScript Basic Minimal Serialization: FAIL\n'); + return false; + } + + console.log('[TEST END] JavaScript Basic Minimal Serialization: PASS\n'); + return true; + } catch (error) { + printFailureDetails('Exception: ' + error); + console.log('[TEST END] JavaScript Basic Minimal Serialization: FAIL\n'); + return false; + } +} + +if (require.main === module) { + const success = main(); + process.exit(success ? 0 : 1); +} + +module.exports.main = main; diff --git a/tests/js/test_tiny_default_deserialization.js b/tests/js/test_tiny_default_deserialization.js new file mode 100644 index 00000000..b927749d --- /dev/null +++ b/tests/js/test_tiny_default_deserialization.js @@ -0,0 +1,131 @@ +/** + * Tiny Default frame format deserialization test for JavaScript. + */ +"use strict"; + +const fs = require('fs'); +const path = require('path'); + +// TinyDefault constants +const TINY_DEFAULT_START_BYTE = 0x71; +const TINY_DEFAULT_HEADER_SIZE = 3; +const TINY_DEFAULT_FOOTER_SIZE = 2; + +function printFailureDetails(label) { + console.log('\n============================================================'); + console.log('FAILURE DETAILS: ' + label); + console.log('============================================================\n'); +} + +function loadExpectedValues() { + try { + const jsonPath = path.join(__dirname, '../../expected_values.json'); + const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8')); + return data.serialization_test; + } catch (error) { + console.log('Error loading expected values: ' + error); + return null; + } +} + +function validateTinyDefault(buffer, expected) { + if (buffer.length < TINY_DEFAULT_HEADER_SIZE + TINY_DEFAULT_FOOTER_SIZE) { + console.log(' Data too short'); + return false; + } + + if (buffer[0] !== TINY_DEFAULT_START_BYTE) { + console.log(' Invalid start byte'); + return false; + } + + if (buffer[2] !== 204) { + console.log(' Invalid message ID'); + return false; + } + + // Validate checksum + const msgLen = buffer.length - TINY_DEFAULT_HEADER_SIZE - TINY_DEFAULT_FOOTER_SIZE; + let byte1 = buffer[1]; // length byte + let byte2 = buffer[1]; + byte1 = (byte1 + buffer[2]) % 256; // msg_id + byte2 = (byte2 + byte1) % 256; + for (let i = 0; i < msgLen; i++) { + byte1 = (byte1 + buffer[TINY_DEFAULT_HEADER_SIZE + i]) & 0xFF; + byte2 = (byte2 + byte1) & 0xFF; + } + + if (byte1 !== buffer[buffer.length - 2] || byte2 !== buffer[buffer.length - 1]) { + console.log(' Checksum mismatch'); + return false; + } + + const magicNumber = buffer.readUInt32LE(TINY_DEFAULT_HEADER_SIZE); + if (magicNumber !== expected.magic_number) { + console.log(' Magic number mismatch'); + return false; + } + + console.log(' [OK] Data validated successfully'); + return true; +} + +function readAndValidateTestData(filename) { + try { + if (!fs.existsSync(filename)) { + console.log(' Error: file not found: ' + filename); + return false; + } + + const binaryData = fs.readFileSync(filename); + + if (binaryData.length === 0) { + printFailureDetails('Empty file'); + return false; + } + + const expected = loadExpectedValues(); + if (!expected) { + return false; + } + + if (!validateTinyDefault(binaryData, expected)) { + console.log(' Validation failed'); + return false; + } + + return true; + } catch (error) { + printFailureDetails('Read data exception: ' + error); + return false; + } +} + +function main() { + console.log('\n[TEST START] JavaScript Tiny Default Deserialization'); + + const args = process.argv.slice(2); + if (args.length !== 1) { + console.log(' Usage: ' + process.argv[1] + ' '); + console.log('[TEST END] JavaScript Tiny Default Deserialization: FAIL\n'); + return false; + } + + try { + const success = readAndValidateTestData(args[0]); + + console.log('[TEST END] JavaScript Tiny Default Deserialization: ' + (success ? 'PASS' : 'FAIL') + '\n'); + return success; + } catch (error) { + printFailureDetails('Exception: ' + error); + console.log('[TEST END] JavaScript Tiny Default Deserialization: FAIL\n'); + return false; + } +} + +if (require.main === module) { + const success = main(); + process.exit(success ? 0 : 1); +} + +module.exports.main = main; diff --git a/tests/js/test_tiny_default_serialization.js b/tests/js/test_tiny_default_serialization.js new file mode 100644 index 00000000..abcecbc4 --- /dev/null +++ b/tests/js/test_tiny_default_serialization.js @@ -0,0 +1,130 @@ +/** + * Tiny Default frame format serialization test for JavaScript. + */ +"use strict"; + +const fs = require('fs'); +const path = require('path'); + +// TinyDefault constants +const TINY_DEFAULT_START_BYTE = 0x71; +const TINY_DEFAULT_HEADER_SIZE = 3; // start + length + msg_id +const TINY_DEFAULT_FOOTER_SIZE = 2; // crc1 + crc2 + +function printFailureDetails(label) { + console.log('\n============================================================'); + console.log('FAILURE DETAILS: ' + label); + console.log('============================================================\n'); +} + +function loadExpectedValues() { + try { + const jsonPath = path.join(__dirname, '../../expected_values.json'); + const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8')); + return data.serialization_test; + } catch (error) { + console.log('Error loading expected values: ' + error); + return null; + } +} + +function createTestData() { + try { + const expected = loadExpectedValues(); + if (!expected) { + return false; + } + + const msg_id = 204; + const payloadSize = 95; + const payload = Buffer.alloc(payloadSize); + let offset = 0; + + // magic_number (uint32, little-endian) + payload.writeUInt32LE(expected.magic_number, offset); + offset += 4; + + // test_string: length byte + 64 bytes of data + const testString = expected.test_string; + payload.writeUInt8(testString.length, offset); + offset += 1; + Buffer.from(testString).copy(payload, offset, 0, testString.length); + offset += 64; + + // test_float (float, little-endian) + payload.writeFloatLE(expected.test_float, offset); + offset += 4; + + // test_bool (1 byte) + payload.writeUInt8(expected.test_bool ? 1 : 0, offset); + offset += 1; + + // test_array: count byte + int32 data (5 elements max) + const testArray = expected.test_array; + payload.writeUInt8(testArray.length, offset); + offset += 1; + for (let i = 0; i < 5; i++) { + if (i < testArray.length) { + payload.writeInt32LE(testArray[i], offset); + } else { + payload.writeInt32LE(0, offset); + } + offset += 4; + } + + // Calculate Fletcher checksum on length + msg_id + payload + let byte1 = payloadSize & 0xFF; + let byte2 = payloadSize & 0xFF; + byte1 = (byte1 + msg_id) & 0xFF; + byte2 = (byte2 + byte1) & 0xFF; + for (let i = 0; i < payload.length; i++) { + byte1 = (byte1 + payload[i]) & 0xFF; + byte2 = (byte2 + byte1) & 0xFF; + } + + // Build complete frame + const frame = Buffer.alloc(TINY_DEFAULT_HEADER_SIZE + payloadSize + TINY_DEFAULT_FOOTER_SIZE); + frame[0] = TINY_DEFAULT_START_BYTE; + frame[1] = payloadSize & 0xFF; + frame[2] = msg_id; + payload.copy(frame, TINY_DEFAULT_HEADER_SIZE); + frame[frame.length - 2] = byte1; + frame[frame.length - 1] = byte2; + + // Write to file + const outputPath = fs.existsSync('tests/generated/js') + ? 'tests/generated/js/javascript_tiny_default_test_data.bin' + : 'javascript_tiny_default_test_data.bin'; + fs.writeFileSync(outputPath, frame); + + return true; + } catch (error) { + printFailureDetails('Create test data exception: ' + error); + return false; + } +} + +function main() { + console.log('\n[TEST START] JavaScript Tiny Default Serialization'); + + try { + if (!createTestData()) { + console.log('[TEST END] JavaScript Tiny Default Serialization: FAIL\n'); + return false; + } + + console.log('[TEST END] JavaScript Tiny Default Serialization: PASS\n'); + return true; + } catch (error) { + printFailureDetails('Exception: ' + error); + console.log('[TEST END] JavaScript Tiny Default Serialization: FAIL\n'); + return false; + } +} + +if (require.main === module) { + const success = main(); + process.exit(success ? 0 : 1); +} + +module.exports.main = main; diff --git a/tests/js/test_tiny_minimal_deserialization.js b/tests/js/test_tiny_minimal_deserialization.js new file mode 100644 index 00000000..92886e40 --- /dev/null +++ b/tests/js/test_tiny_minimal_deserialization.js @@ -0,0 +1,117 @@ +/** + * Tiny Minimal frame format deserialization test for JavaScript. + */ +"use strict"; + +const fs = require('fs'); +const path = require('path'); + +// TinyMinimal constants +const TINY_MINIMAL_START_BYTE = 0x70; +const TINY_MINIMAL_HEADER_SIZE = 2; +const TINY_MINIMAL_FOOTER_SIZE = 0; + +function printFailureDetails(label) { + console.log('\n============================================================'); + console.log('FAILURE DETAILS: ' + label); + console.log('============================================================\n'); +} + +function loadExpectedValues() { + try { + const jsonPath = path.join(__dirname, '../../expected_values.json'); + const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8')); + return data.serialization_test; + } catch (error) { + console.log('Error loading expected values: ' + error); + return null; + } +} + +function validateTinyMinimal(buffer, expected) { + if (buffer.length < TINY_MINIMAL_HEADER_SIZE + TINY_MINIMAL_FOOTER_SIZE) { + console.log(' Data too short'); + return false; + } + + if (buffer[0] !== TINY_MINIMAL_START_BYTE) { + console.log(' Invalid start byte'); + return false; + } + + if (buffer[1] !== 204) { + console.log(' Invalid message ID'); + return false; + } + + // No CRC validation for minimal format + + const magicNumber = buffer.readUInt32LE(TINY_MINIMAL_HEADER_SIZE); + if (magicNumber !== expected.magic_number) { + console.log(' Magic number mismatch'); + return false; + } + + console.log(' [OK] Data validated successfully'); + return true; +} + +function readAndValidateTestData(filename) { + try { + if (!fs.existsSync(filename)) { + console.log(' Error: file not found: ' + filename); + return false; + } + + const binaryData = fs.readFileSync(filename); + + if (binaryData.length === 0) { + printFailureDetails('Empty file'); + return false; + } + + const expected = loadExpectedValues(); + if (!expected) { + return false; + } + + if (!validateTinyMinimal(binaryData, expected)) { + console.log(' Validation failed'); + return false; + } + + return true; + } catch (error) { + printFailureDetails('Read data exception: ' + error); + return false; + } +} + +function main() { + console.log('\n[TEST START] JavaScript Tiny Minimal Deserialization'); + + const args = process.argv.slice(2); + if (args.length !== 1) { + console.log(' Usage: ' + process.argv[1] + ' '); + console.log('[TEST END] JavaScript Tiny Minimal Deserialization: FAIL\n'); + return false; + } + + try { + const success = readAndValidateTestData(args[0]); + + console.log('[TEST END] JavaScript Tiny Minimal Deserialization: ' + (success ? 'PASS' : 'FAIL') + '\n'); + return success; + } catch (error) { + printFailureDetails('Exception: ' + error); + console.log('[TEST END] JavaScript Tiny Minimal Deserialization: FAIL\n'); + return false; + } +} + +if (require.main === module) { + const success = main(); + process.exit(success ? 0 : 1); +} + +module.exports.main = main; diff --git a/tests/js/test_tiny_minimal_serialization.js b/tests/js/test_tiny_minimal_serialization.js new file mode 100644 index 00000000..f5c2e022 --- /dev/null +++ b/tests/js/test_tiny_minimal_serialization.js @@ -0,0 +1,117 @@ +/** + * Tiny Minimal frame format serialization test for JavaScript. + */ +"use strict"; + +const fs = require('fs'); +const path = require('path'); + +// TinyMinimal constants +const TINY_MINIMAL_START_BYTE = 0x70; +const TINY_MINIMAL_HEADER_SIZE = 2; // start + msg_id +const TINY_MINIMAL_FOOTER_SIZE = 0; // no crc + +function printFailureDetails(label) { + console.log('\n============================================================'); + console.log('FAILURE DETAILS: ' + label); + console.log('============================================================\n'); +} + +function loadExpectedValues() { + try { + const jsonPath = path.join(__dirname, '../../expected_values.json'); + const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8')); + return data.serialization_test; + } catch (error) { + console.log('Error loading expected values: ' + error); + return null; + } +} + +function createTestData() { + try { + const expected = loadExpectedValues(); + if (!expected) { + return false; + } + + const msg_id = 204; + const payloadSize = 95; + const payload = Buffer.alloc(payloadSize); + let offset = 0; + + // magic_number (uint32, little-endian) + payload.writeUInt32LE(expected.magic_number, offset); + offset += 4; + + // test_string: length byte + 64 bytes of data + const testString = expected.test_string; + payload.writeUInt8(testString.length, offset); + offset += 1; + Buffer.from(testString).copy(payload, offset, 0, testString.length); + offset += 64; + + // test_float (float, little-endian) + payload.writeFloatLE(expected.test_float, offset); + offset += 4; + + // test_bool (1 byte) + payload.writeUInt8(expected.test_bool ? 1 : 0, offset); + offset += 1; + + // test_array: count byte + int32 data (5 elements max) + const testArray = expected.test_array; + payload.writeUInt8(testArray.length, offset); + offset += 1; + for (let i = 0; i < 5; i++) { + if (i < testArray.length) { + payload.writeInt32LE(testArray[i], offset); + } else { + payload.writeInt32LE(0, offset); + } + offset += 4; + } + + // Build complete frame (no CRC for minimal) + const frame = Buffer.alloc(TINY_MINIMAL_HEADER_SIZE + payloadSize + TINY_MINIMAL_FOOTER_SIZE); + frame[0] = TINY_MINIMAL_START_BYTE; + frame[1] = msg_id; + payload.copy(frame, TINY_MINIMAL_HEADER_SIZE); + + // Write to file + const outputPath = fs.existsSync('tests/generated/js') + ? 'tests/generated/js/javascript_tiny_minimal_test_data.bin' + : 'javascript_tiny_minimal_test_data.bin'; + fs.writeFileSync(outputPath, frame); + + return true; + } catch (error) { + printFailureDetails('Create test data exception: ' + error); + return false; + } +} + +function main() { + console.log('\n[TEST START] JavaScript Tiny Minimal Serialization'); + + try { + if (!createTestData()) { + console.log('[TEST END] JavaScript Tiny Minimal Serialization: FAIL\n'); + return false; + } + + console.log('[TEST END] JavaScript Tiny Minimal Serialization: PASS\n'); + return true; + } catch (error) { + printFailureDetails('Exception: ' + error); + console.log('[TEST END] JavaScript Tiny Minimal Serialization: FAIL\n'); + return false; + } +} + +if (require.main === module) { + const success = main(); + process.exit(success ? 0 : 1); +} + +module.exports.main = main; diff --git a/tests/py/test_basic_default_deserialization.py b/tests/py/test_basic_default_deserialization.py new file mode 100644 index 00000000..32712138 --- /dev/null +++ b/tests/py/test_basic_default_deserialization.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 +"""Basic Default frame format deserialization test for Python.""" + +import sys +import os +import json + + +def print_failure_details(label, expected_values=None, actual_values=None, raw_data=None): + """Print detailed failure information""" + print(f"\n{'='*60}") + print(f"FAILURE DETAILS: {label}") + print(f"{'='*60}") + + if expected_values: + print("\nExpected Values:") + for key, val in expected_values.items(): + print(f" {key}: {val}") + + if actual_values: + print("\nActual Values:") + for key, val in actual_values.items(): + print(f" {key}: {val}") + + if raw_data: + print(f"\nRaw Data ({len(raw_data)} bytes):") + print(f" Hex: {raw_data.hex()}") + + print(f"{'='*60}\n") + + +def load_expected_values(): + """Load expected values from JSON file""" + json_path = os.path.join(os.path.dirname(__file__), '..', 'expected_values.json') + try: + with open(json_path, 'r') as f: + data = json.load(f) + return data['serialization_test'] + except Exception as e: + print(f"Error loading expected values: {e}") + return None + + +def validate_message(msg, expected): + """Validate a decoded message against expected values""" + if msg.magic_number != expected['magic_number']: + print_failure_details("Value mismatch: magic_number", + expected_values={"magic_number": expected['magic_number']}, + actual_values={"magic_number": msg.magic_number}) + return False + + test_string = msg.test_string.decode('utf-8').rstrip('\x00') if isinstance( + msg.test_string, bytes) else str(msg.test_string).rstrip('\x00') + if test_string != expected['test_string']: + print_failure_details("Value mismatch: test_string", + expected_values={"test_string": expected['test_string']}, + actual_values={"test_string": test_string}) + return False + + if abs(msg.test_float - expected['test_float']) > 0.0001: + print_failure_details("Value mismatch: test_float", + expected_values={"test_float": expected['test_float']}, + actual_values={"test_float": msg.test_float}) + return False + + if msg.test_bool != expected['test_bool']: + print_failure_details("Value mismatch: test_bool", + expected_values={"test_bool": expected['test_bool']}, + actual_values={"test_bool": msg.test_bool}) + return False + + if list(msg.test_array) != expected['test_array']: + print_failure_details("Value mismatch: test_array", + expected_values={"test_array": expected['test_array']}, + actual_values={"test_array": list(msg.test_array)}) + return False + + return True + + +def read_and_validate_test_data(filename): + """Read and validate test data from a binary file""" + try: + if not os.path.exists(filename): + print(f" Error: file not found: {filename}") + return False + + with open(filename, 'rb') as f: + binary_data = f.read() + + if len(binary_data) == 0: + print_failure_details("Empty file", raw_data=binary_data) + return False + + import importlib + try: + msg_module = importlib.import_module('py.serialization_test_sf') + SerializationTestSerializationTestMessage = msg_module.SerializationTestSerializationTestMessage + basic_module = importlib.import_module('py.basic_default') + BasicDefault = basic_module.BasicDefault + except ImportError: + try: + from serialization_test_sf import SerializationTestSerializationTestMessage + from basic_default import BasicDefault + except ImportError as e: + print(f" Error importing modules: {e}") + return False + + result = BasicDefault.validate_packet(list(binary_data)) + + if not result.valid: + print_failure_details("Failed to decode data", raw_data=binary_data) + return False + + msg_data = bytes(result.msg_data) + decoded_msg = SerializationTestSerializationTestMessage.create_unpack(msg_data) + + expected = load_expected_values() + if not expected: + return False + + if not validate_message(decoded_msg, expected): + print(" Validation failed") + return False + + print(" [OK] Data validated successfully") + return True + + except Exception as e: + print_failure_details(f"Read data exception: {type(e).__name__}", + actual_values={"exception": str(e)}) + import traceback + traceback.print_exc() + return False + + +def main(): + """Main test function""" + print("\n[TEST START] Python Basic Default Deserialization") + + if len(sys.argv) != 2: + print(f" Usage: {sys.argv[0]} ") + print("[TEST END] Python Basic Default Deserialization: FAIL\n") + return False + + success = read_and_validate_test_data(sys.argv[1]) + + status = "PASS" if success else "FAIL" + print(f"[TEST END] Python Basic Default Deserialization: {status}\n") + + return success + + +if __name__ == "__main__": + success = main() + sys.exit(0 if success else 1) diff --git a/tests/py/test_basic_default_serialization.py b/tests/py/test_basic_default_serialization.py new file mode 100644 index 00000000..090e7535 --- /dev/null +++ b/tests/py/test_basic_default_serialization.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +"""Basic Default frame format serialization test for Python.""" + +import sys +import os +import json + + +def print_failure_details(label, expected_values=None, actual_values=None, raw_data=None): + """Print detailed failure information""" + print(f"\n{'='*60}") + print(f"FAILURE DETAILS: {label}") + print(f"{'='*60}") + + if expected_values: + print("\nExpected Values:") + for key, val in expected_values.items(): + print(f" {key}: {val}") + + if actual_values: + print("\nActual Values:") + for key, val in actual_values.items(): + print(f" {key}: {val}") + + if raw_data: + print(f"\nRaw Data ({len(raw_data)} bytes):") + print(f" Hex: {raw_data.hex()}") + + print(f"{'='*60}\n") + + +def load_expected_values(): + """Load expected values from JSON file""" + json_path = os.path.join(os.path.dirname(__file__), '..', 'expected_values.json') + try: + with open(json_path, 'r') as f: + data = json.load(f) + return data['serialization_test'] + except Exception as e: + print(f"Error loading expected values: {e}") + return None + + +def create_test_data(): + """Create test data for basic_default format""" + try: + import importlib + try: + msg_module = importlib.import_module('py.serialization_test_sf') + SerializationTestSerializationTestMessage = msg_module.SerializationTestSerializationTestMessage + basic_module = importlib.import_module('py.basic_default') + BasicDefault = basic_module.BasicDefault + except ImportError: + try: + from serialization_test_sf import SerializationTestSerializationTestMessage + from basic_default import BasicDefault + except ImportError as e: + print(f" Error importing modules: {e}") + return True # Skip if generated code not available + + expected = load_expected_values() + if not expected: + return False + + msg = SerializationTestSerializationTestMessage( + magic_number=expected['magic_number'], + test_string=expected['test_string'].encode('utf-8'), + test_float=expected['test_float'], + test_bool=expected['test_bool'], + test_array=expected['test_array'] + ) + + parser = BasicDefault() + encoded_data = parser.encode_msg(msg) + + with open('python_basic_default_test_data.bin', 'wb') as f: + f.write(bytes(encoded_data)) + + return True + + except Exception as e: + print_failure_details(f"Create test data exception: {type(e).__name__}", + expected_values={"result": "success"}, + actual_values={"exception": str(e)}) + import traceback + traceback.print_exc() + return False + + +def main(): + """Main test function""" + print("\n[TEST START] Python Basic Default Serialization") + + success = create_test_data() + + status = "PASS" if success else "FAIL" + print(f"[TEST END] Python Basic Default Serialization: {status}\n") + + return success + + +if __name__ == "__main__": + success = main() + sys.exit(0 if success else 1) diff --git a/tests/py/test_basic_minimal_deserialization.py b/tests/py/test_basic_minimal_deserialization.py new file mode 100644 index 00000000..f668dee1 --- /dev/null +++ b/tests/py/test_basic_minimal_deserialization.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 +"""Basic Minimal frame format deserialization test for Python.""" + +import sys +import os +import json + + +def print_failure_details(label, expected_values=None, actual_values=None, raw_data=None): + """Print detailed failure information""" + print(f"\n{'='*60}") + print(f"FAILURE DETAILS: {label}") + print(f"{'='*60}") + + if expected_values: + print("\nExpected Values:") + for key, val in expected_values.items(): + print(f" {key}: {val}") + + if actual_values: + print("\nActual Values:") + for key, val in actual_values.items(): + print(f" {key}: {val}") + + if raw_data: + print(f"\nRaw Data ({len(raw_data)} bytes):") + print(f" Hex: {raw_data.hex()}") + + print(f"{'='*60}\n") + + +def load_expected_values(): + """Load expected values from JSON file""" + json_path = os.path.join(os.path.dirname(__file__), '..', 'expected_values.json') + try: + with open(json_path, 'r') as f: + data = json.load(f) + return data['serialization_test'] + except Exception as e: + print(f"Error loading expected values: {e}") + return None + + +def validate_message(msg, expected): + """Validate a decoded message against expected values""" + if msg.magic_number != expected['magic_number']: + print_failure_details("Value mismatch: magic_number", + expected_values={"magic_number": expected['magic_number']}, + actual_values={"magic_number": msg.magic_number}) + return False + + test_string = msg.test_string.decode('utf-8').rstrip('\x00') if isinstance( + msg.test_string, bytes) else str(msg.test_string).rstrip('\x00') + if test_string != expected['test_string']: + print_failure_details("Value mismatch: test_string", + expected_values={"test_string": expected['test_string']}, + actual_values={"test_string": test_string}) + return False + + if abs(msg.test_float - expected['test_float']) > 0.0001: + print_failure_details("Value mismatch: test_float", + expected_values={"test_float": expected['test_float']}, + actual_values={"test_float": msg.test_float}) + return False + + if msg.test_bool != expected['test_bool']: + print_failure_details("Value mismatch: test_bool", + expected_values={"test_bool": expected['test_bool']}, + actual_values={"test_bool": msg.test_bool}) + return False + + if list(msg.test_array) != expected['test_array']: + print_failure_details("Value mismatch: test_array", + expected_values={"test_array": expected['test_array']}, + actual_values={"test_array": list(msg.test_array)}) + return False + + return True + + +def read_and_validate_test_data(filename): + """Read and validate test data from a binary file""" + try: + if not os.path.exists(filename): + print(f" Error: file not found: {filename}") + return False + + with open(filename, 'rb') as f: + binary_data = f.read() + + if len(binary_data) == 0: + print_failure_details("Empty file", raw_data=binary_data) + return False + + import importlib + try: + msg_module = importlib.import_module('py.serialization_test_sf') + SerializationTestSerializationTestMessage = msg_module.SerializationTestSerializationTestMessage + basic_module = importlib.import_module('py.basic_minimal') + BasicMinimal = basic_module.BasicMinimal + except ImportError: + try: + from serialization_test_sf import SerializationTestSerializationTestMessage + from basic_minimal import BasicMinimal + except ImportError as e: + print(f" Error importing modules: {e}") + return False + + result = BasicMinimal.validate_packet(list(binary_data)) + + if not result.valid: + print_failure_details("Failed to decode data", raw_data=binary_data) + return False + + msg_data = bytes(result.msg_data) + decoded_msg = SerializationTestSerializationTestMessage.create_unpack(msg_data) + + expected = load_expected_values() + if not expected: + return False + + if not validate_message(decoded_msg, expected): + print(" Validation failed") + return False + + print(" [OK] Data validated successfully") + return True + + except Exception as e: + print_failure_details(f"Read data exception: {type(e).__name__}", + actual_values={"exception": str(e)}) + import traceback + traceback.print_exc() + return False + + +def main(): + """Main test function""" + print("\n[TEST START] Python Basic Minimal Deserialization") + + if len(sys.argv) != 2: + print(f" Usage: {sys.argv[0]} ") + print("[TEST END] Python Basic Minimal Deserialization: FAIL\n") + return False + + success = read_and_validate_test_data(sys.argv[1]) + + status = "PASS" if success else "FAIL" + print(f"[TEST END] Python Basic Minimal Deserialization: {status}\n") + + return success + + +if __name__ == "__main__": + success = main() + sys.exit(0 if success else 1) diff --git a/tests/py/test_basic_minimal_serialization.py b/tests/py/test_basic_minimal_serialization.py new file mode 100644 index 00000000..d86fcd30 --- /dev/null +++ b/tests/py/test_basic_minimal_serialization.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +"""Basic Minimal frame format serialization test for Python.""" + +import sys +import os +import json + + +def print_failure_details(label, expected_values=None, actual_values=None, raw_data=None): + """Print detailed failure information""" + print(f"\n{'='*60}") + print(f"FAILURE DETAILS: {label}") + print(f"{'='*60}") + + if expected_values: + print("\nExpected Values:") + for key, val in expected_values.items(): + print(f" {key}: {val}") + + if actual_values: + print("\nActual Values:") + for key, val in actual_values.items(): + print(f" {key}: {val}") + + if raw_data: + print(f"\nRaw Data ({len(raw_data)} bytes):") + print(f" Hex: {raw_data.hex()}") + + print(f"{'='*60}\n") + + +def load_expected_values(): + """Load expected values from JSON file""" + json_path = os.path.join(os.path.dirname(__file__), '..', 'expected_values.json') + try: + with open(json_path, 'r') as f: + data = json.load(f) + return data['serialization_test'] + except Exception as e: + print(f"Error loading expected values: {e}") + return None + + +def create_test_data(): + """Create test data for basic_minimal format""" + try: + import importlib + try: + msg_module = importlib.import_module('py.serialization_test_sf') + SerializationTestSerializationTestMessage = msg_module.SerializationTestSerializationTestMessage + basic_module = importlib.import_module('py.basic_minimal') + BasicMinimal = basic_module.BasicMinimal + except ImportError: + try: + from serialization_test_sf import SerializationTestSerializationTestMessage + from basic_minimal import BasicMinimal + except ImportError as e: + print(f" Error importing modules: {e}") + return True # Skip if generated code not available + + expected = load_expected_values() + if not expected: + return False + + msg = SerializationTestSerializationTestMessage( + magic_number=expected['magic_number'], + test_string=expected['test_string'].encode('utf-8'), + test_float=expected['test_float'], + test_bool=expected['test_bool'], + test_array=expected['test_array'] + ) + + parser = BasicMinimal() + encoded_data = parser.encode_msg(msg) + + with open('python_basic_minimal_test_data.bin', 'wb') as f: + f.write(bytes(encoded_data)) + + return True + + except Exception as e: + print_failure_details(f"Create test data exception: {type(e).__name__}", + expected_values={"result": "success"}, + actual_values={"exception": str(e)}) + import traceback + traceback.print_exc() + return False + + +def main(): + """Main test function""" + print("\n[TEST START] Python Basic Minimal Serialization") + + success = create_test_data() + + status = "PASS" if success else "FAIL" + print(f"[TEST END] Python Basic Minimal Serialization: {status}\n") + + return success + + +if __name__ == "__main__": + success = main() + sys.exit(0 if success else 1) diff --git a/tests/py/test_cross_platform_deserialization.py b/tests/py/test_cross_platform_deserialization.py index 1ef9fb37..1bc26e40 100644 --- a/tests/py/test_cross_platform_deserialization.py +++ b/tests/py/test_cross_platform_deserialization.py @@ -114,9 +114,20 @@ def read_and_validate_test_data(filename): ) return False - sys.path.insert(0, '../generated/py') - from serialization_test_sf import SerializationTestSerializationTestMessage - from basic_default import BasicDefault + # Import modules - try package import first, then fallback to direct import + import importlib + try: + msg_module = importlib.import_module('py.serialization_test_sf') + SerializationTestSerializationTestMessage = msg_module.SerializationTestSerializationTestMessage + basic_module = importlib.import_module('py.basic_default') + BasicDefault = basic_module.BasicDefault + except ImportError: + try: + from serialization_test_sf import SerializationTestSerializationTestMessage + from basic_default import BasicDefault + except ImportError as e: + print(f" Error importing modules: {e}") + return False # Validate and decode using BasicDefault result = BasicDefault.validate_packet(list(binary_data)) diff --git a/tests/py/test_cross_platform_serialization.py b/tests/py/test_cross_platform_serialization.py index 99163fd2..8750f9e1 100755 --- a/tests/py/test_cross_platform_serialization.py +++ b/tests/py/test_cross_platform_serialization.py @@ -47,9 +47,20 @@ def load_expected_values(): def create_test_data(): """Create test data for cross-platform compatibility testing""" try: - sys.path.insert(0, '../generated/py') - from serialization_test_sf import SerializationTestSerializationTestMessage - from struct_frame_parser import BasicFrame + # Import modules - try package import first, then fallback to direct import + import importlib + try: + msg_module = importlib.import_module('py.serialization_test_sf') + SerializationTestSerializationTestMessage = msg_module.SerializationTestSerializationTestMessage + basic_module = importlib.import_module('py.basic_default') + BasicDefault = basic_module.BasicDefault + except ImportError: + try: + from serialization_test_sf import SerializationTestSerializationTestMessage + from basic_default import BasicDefault + except ImportError as e: + print(f" Error importing modules: {e}") + return True # Skip if generated code not available # Load expected values from JSON expected = load_expected_values() @@ -65,8 +76,9 @@ def create_test_data(): test_array=expected['test_array'] ) - packet = BasicFrame() - encoded_data = packet.encode_msg(msg) + # Create a parser instance and encode the message + parser = BasicDefault() + encoded_data = parser.encode_msg(msg) with open('python_test_data.bin', 'wb') as f: f.write(bytes(encoded_data)) diff --git a/tests/py/test_tiny_default_deserialization.py b/tests/py/test_tiny_default_deserialization.py new file mode 100644 index 00000000..67374cbf --- /dev/null +++ b/tests/py/test_tiny_default_deserialization.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 +"""Tiny Default frame format deserialization test for Python.""" + +import sys +import os +import json + + +def print_failure_details(label, expected_values=None, actual_values=None, raw_data=None): + """Print detailed failure information""" + print(f"\n{'='*60}") + print(f"FAILURE DETAILS: {label}") + print(f"{'='*60}") + + if expected_values: + print("\nExpected Values:") + for key, val in expected_values.items(): + print(f" {key}: {val}") + + if actual_values: + print("\nActual Values:") + for key, val in actual_values.items(): + print(f" {key}: {val}") + + if raw_data: + print(f"\nRaw Data ({len(raw_data)} bytes):") + print(f" Hex: {raw_data.hex()}") + + print(f"{'='*60}\n") + + +def load_expected_values(): + """Load expected values from JSON file""" + json_path = os.path.join(os.path.dirname(__file__), '..', 'expected_values.json') + try: + with open(json_path, 'r') as f: + data = json.load(f) + return data['serialization_test'] + except Exception as e: + print(f"Error loading expected values: {e}") + return None + + +def validate_message(msg, expected): + """Validate a decoded message against expected values""" + if msg.magic_number != expected['magic_number']: + print_failure_details("Value mismatch: magic_number", + expected_values={"magic_number": expected['magic_number']}, + actual_values={"magic_number": msg.magic_number}) + return False + + test_string = msg.test_string.decode('utf-8').rstrip('\x00') if isinstance( + msg.test_string, bytes) else str(msg.test_string).rstrip('\x00') + if test_string != expected['test_string']: + print_failure_details("Value mismatch: test_string", + expected_values={"test_string": expected['test_string']}, + actual_values={"test_string": test_string}) + return False + + if abs(msg.test_float - expected['test_float']) > 0.0001: + print_failure_details("Value mismatch: test_float", + expected_values={"test_float": expected['test_float']}, + actual_values={"test_float": msg.test_float}) + return False + + if msg.test_bool != expected['test_bool']: + print_failure_details("Value mismatch: test_bool", + expected_values={"test_bool": expected['test_bool']}, + actual_values={"test_bool": msg.test_bool}) + return False + + if list(msg.test_array) != expected['test_array']: + print_failure_details("Value mismatch: test_array", + expected_values={"test_array": expected['test_array']}, + actual_values={"test_array": list(msg.test_array)}) + return False + + return True + + +def read_and_validate_test_data(filename): + """Read and validate test data from a binary file""" + try: + if not os.path.exists(filename): + print(f" Error: file not found: {filename}") + return False + + with open(filename, 'rb') as f: + binary_data = f.read() + + if len(binary_data) == 0: + print_failure_details("Empty file", raw_data=binary_data) + return False + + import importlib + try: + msg_module = importlib.import_module('py.serialization_test_sf') + SerializationTestSerializationTestMessage = msg_module.SerializationTestSerializationTestMessage + tiny_module = importlib.import_module('py.tiny_default') + TinyDefault = tiny_module.TinyDefault + except ImportError: + try: + from serialization_test_sf import SerializationTestSerializationTestMessage + from tiny_default import TinyDefault + except ImportError as e: + print(f" Error importing modules: {e}") + return False + + result = TinyDefault.validate_packet(list(binary_data)) + + if not result.valid: + print_failure_details("Failed to decode data", raw_data=binary_data) + return False + + msg_data = bytes(result.msg_data) + decoded_msg = SerializationTestSerializationTestMessage.create_unpack(msg_data) + + expected = load_expected_values() + if not expected: + return False + + if not validate_message(decoded_msg, expected): + print(" Validation failed") + return False + + print(" [OK] Data validated successfully") + return True + + except Exception as e: + print_failure_details(f"Read data exception: {type(e).__name__}", + actual_values={"exception": str(e)}) + import traceback + traceback.print_exc() + return False + + +def main(): + """Main test function""" + print("\n[TEST START] Python Tiny Default Deserialization") + + if len(sys.argv) != 2: + print(f" Usage: {sys.argv[0]} ") + print("[TEST END] Python Tiny Default Deserialization: FAIL\n") + return False + + success = read_and_validate_test_data(sys.argv[1]) + + status = "PASS" if success else "FAIL" + print(f"[TEST END] Python Tiny Default Deserialization: {status}\n") + + return success + + +if __name__ == "__main__": + success = main() + sys.exit(0 if success else 1) diff --git a/tests/py/test_tiny_default_serialization.py b/tests/py/test_tiny_default_serialization.py new file mode 100644 index 00000000..4a111fcf --- /dev/null +++ b/tests/py/test_tiny_default_serialization.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +"""Tiny Default frame format serialization test for Python.""" + +import sys +import os +import json + + +def print_failure_details(label, expected_values=None, actual_values=None, raw_data=None): + """Print detailed failure information""" + print(f"\n{'='*60}") + print(f"FAILURE DETAILS: {label}") + print(f"{'='*60}") + + if expected_values: + print("\nExpected Values:") + for key, val in expected_values.items(): + print(f" {key}: {val}") + + if actual_values: + print("\nActual Values:") + for key, val in actual_values.items(): + print(f" {key}: {val}") + + if raw_data: + print(f"\nRaw Data ({len(raw_data)} bytes):") + print(f" Hex: {raw_data.hex()}") + + print(f"{'='*60}\n") + + +def load_expected_values(): + """Load expected values from JSON file""" + json_path = os.path.join(os.path.dirname(__file__), '..', 'expected_values.json') + try: + with open(json_path, 'r') as f: + data = json.load(f) + return data['serialization_test'] + except Exception as e: + print(f"Error loading expected values: {e}") + return None + + +def create_test_data(): + """Create test data for tiny_default format""" + try: + import importlib + try: + msg_module = importlib.import_module('py.serialization_test_sf') + SerializationTestSerializationTestMessage = msg_module.SerializationTestSerializationTestMessage + tiny_module = importlib.import_module('py.tiny_default') + TinyDefault = tiny_module.TinyDefault + except ImportError: + try: + from serialization_test_sf import SerializationTestSerializationTestMessage + from tiny_default import TinyDefault + except ImportError as e: + print(f" Error importing modules: {e}") + return True # Skip if generated code not available + + expected = load_expected_values() + if not expected: + return False + + msg = SerializationTestSerializationTestMessage( + magic_number=expected['magic_number'], + test_string=expected['test_string'].encode('utf-8'), + test_float=expected['test_float'], + test_bool=expected['test_bool'], + test_array=expected['test_array'] + ) + + parser = TinyDefault() + encoded_data = parser.encode_msg(msg) + + with open('python_tiny_default_test_data.bin', 'wb') as f: + f.write(bytes(encoded_data)) + + return True + + except Exception as e: + print_failure_details(f"Create test data exception: {type(e).__name__}", + expected_values={"result": "success"}, + actual_values={"exception": str(e)}) + import traceback + traceback.print_exc() + return False + + +def main(): + """Main test function""" + print("\n[TEST START] Python Tiny Default Serialization") + + success = create_test_data() + + status = "PASS" if success else "FAIL" + print(f"[TEST END] Python Tiny Default Serialization: {status}\n") + + return success + + +if __name__ == "__main__": + success = main() + sys.exit(0 if success else 1) diff --git a/tests/py/test_tiny_minimal_deserialization.py b/tests/py/test_tiny_minimal_deserialization.py new file mode 100644 index 00000000..928a726a --- /dev/null +++ b/tests/py/test_tiny_minimal_deserialization.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 +"""Tiny Minimal frame format deserialization test for Python.""" + +import sys +import os +import json + + +def print_failure_details(label, expected_values=None, actual_values=None, raw_data=None): + """Print detailed failure information""" + print(f"\n{'='*60}") + print(f"FAILURE DETAILS: {label}") + print(f"{'='*60}") + + if expected_values: + print("\nExpected Values:") + for key, val in expected_values.items(): + print(f" {key}: {val}") + + if actual_values: + print("\nActual Values:") + for key, val in actual_values.items(): + print(f" {key}: {val}") + + if raw_data: + print(f"\nRaw Data ({len(raw_data)} bytes):") + print(f" Hex: {raw_data.hex()}") + + print(f"{'='*60}\n") + + +def load_expected_values(): + """Load expected values from JSON file""" + json_path = os.path.join(os.path.dirname(__file__), '..', 'expected_values.json') + try: + with open(json_path, 'r') as f: + data = json.load(f) + return data['serialization_test'] + except Exception as e: + print(f"Error loading expected values: {e}") + return None + + +def validate_message(msg, expected): + """Validate a decoded message against expected values""" + if msg.magic_number != expected['magic_number']: + print_failure_details("Value mismatch: magic_number", + expected_values={"magic_number": expected['magic_number']}, + actual_values={"magic_number": msg.magic_number}) + return False + + test_string = msg.test_string.decode('utf-8').rstrip('\x00') if isinstance( + msg.test_string, bytes) else str(msg.test_string).rstrip('\x00') + if test_string != expected['test_string']: + print_failure_details("Value mismatch: test_string", + expected_values={"test_string": expected['test_string']}, + actual_values={"test_string": test_string}) + return False + + if abs(msg.test_float - expected['test_float']) > 0.0001: + print_failure_details("Value mismatch: test_float", + expected_values={"test_float": expected['test_float']}, + actual_values={"test_float": msg.test_float}) + return False + + if msg.test_bool != expected['test_bool']: + print_failure_details("Value mismatch: test_bool", + expected_values={"test_bool": expected['test_bool']}, + actual_values={"test_bool": msg.test_bool}) + return False + + if list(msg.test_array) != expected['test_array']: + print_failure_details("Value mismatch: test_array", + expected_values={"test_array": expected['test_array']}, + actual_values={"test_array": list(msg.test_array)}) + return False + + return True + + +def read_and_validate_test_data(filename): + """Read and validate test data from a binary file""" + try: + if not os.path.exists(filename): + print(f" Error: file not found: {filename}") + return False + + with open(filename, 'rb') as f: + binary_data = f.read() + + if len(binary_data) == 0: + print_failure_details("Empty file", raw_data=binary_data) + return False + + import importlib + try: + msg_module = importlib.import_module('py.serialization_test_sf') + SerializationTestSerializationTestMessage = msg_module.SerializationTestSerializationTestMessage + tiny_module = importlib.import_module('py.tiny_minimal') + TinyMinimal = tiny_module.TinyMinimal + except ImportError: + try: + from serialization_test_sf import SerializationTestSerializationTestMessage + from tiny_minimal import TinyMinimal + except ImportError as e: + print(f" Error importing modules: {e}") + return False + + result = TinyMinimal.validate_packet(list(binary_data)) + + if not result.valid: + print_failure_details("Failed to decode data", raw_data=binary_data) + return False + + msg_data = bytes(result.msg_data) + decoded_msg = SerializationTestSerializationTestMessage.create_unpack(msg_data) + + expected = load_expected_values() + if not expected: + return False + + if not validate_message(decoded_msg, expected): + print(" Validation failed") + return False + + print(" [OK] Data validated successfully") + return True + + except Exception as e: + print_failure_details(f"Read data exception: {type(e).__name__}", + actual_values={"exception": str(e)}) + import traceback + traceback.print_exc() + return False + + +def main(): + """Main test function""" + print("\n[TEST START] Python Tiny Minimal Deserialization") + + if len(sys.argv) != 2: + print(f" Usage: {sys.argv[0]} ") + print("[TEST END] Python Tiny Minimal Deserialization: FAIL\n") + return False + + success = read_and_validate_test_data(sys.argv[1]) + + status = "PASS" if success else "FAIL" + print(f"[TEST END] Python Tiny Minimal Deserialization: {status}\n") + + return success + + +if __name__ == "__main__": + success = main() + sys.exit(0 if success else 1) diff --git a/tests/py/test_tiny_minimal_serialization.py b/tests/py/test_tiny_minimal_serialization.py new file mode 100644 index 00000000..355df7a8 --- /dev/null +++ b/tests/py/test_tiny_minimal_serialization.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +"""Tiny Minimal frame format serialization test for Python.""" + +import sys +import os +import json + + +def print_failure_details(label, expected_values=None, actual_values=None, raw_data=None): + """Print detailed failure information""" + print(f"\n{'='*60}") + print(f"FAILURE DETAILS: {label}") + print(f"{'='*60}") + + if expected_values: + print("\nExpected Values:") + for key, val in expected_values.items(): + print(f" {key}: {val}") + + if actual_values: + print("\nActual Values:") + for key, val in actual_values.items(): + print(f" {key}: {val}") + + if raw_data: + print(f"\nRaw Data ({len(raw_data)} bytes):") + print(f" Hex: {raw_data.hex()}") + + print(f"{'='*60}\n") + + +def load_expected_values(): + """Load expected values from JSON file""" + json_path = os.path.join(os.path.dirname(__file__), '..', 'expected_values.json') + try: + with open(json_path, 'r') as f: + data = json.load(f) + return data['serialization_test'] + except Exception as e: + print(f"Error loading expected values: {e}") + return None + + +def create_test_data(): + """Create test data for tiny_minimal format""" + try: + import importlib + try: + msg_module = importlib.import_module('py.serialization_test_sf') + SerializationTestSerializationTestMessage = msg_module.SerializationTestSerializationTestMessage + tiny_module = importlib.import_module('py.tiny_minimal') + TinyMinimal = tiny_module.TinyMinimal + except ImportError: + try: + from serialization_test_sf import SerializationTestSerializationTestMessage + from tiny_minimal import TinyMinimal + except ImportError as e: + print(f" Error importing modules: {e}") + return True # Skip if generated code not available + + expected = load_expected_values() + if not expected: + return False + + msg = SerializationTestSerializationTestMessage( + magic_number=expected['magic_number'], + test_string=expected['test_string'].encode('utf-8'), + test_float=expected['test_float'], + test_bool=expected['test_bool'], + test_array=expected['test_array'] + ) + + parser = TinyMinimal() + encoded_data = parser.encode_msg(msg) + + with open('python_tiny_minimal_test_data.bin', 'wb') as f: + f.write(bytes(encoded_data)) + + return True + + except Exception as e: + print_failure_details(f"Create test data exception: {type(e).__name__}", + expected_values={"result": "success"}, + actual_values={"exception": str(e)}) + import traceback + traceback.print_exc() + return False + + +def main(): + """Main test function""" + print("\n[TEST START] Python Tiny Minimal Serialization") + + success = create_test_data() + + status = "PASS" if success else "FAIL" + print(f"[TEST END] Python Tiny Minimal Serialization: {status}\n") + + return success + + +if __name__ == "__main__": + success = main() + sys.exit(0 if success else 1) diff --git a/tests/runner/base.py b/tests/runner/base.py index 5a08fe0c..73fbd55a 100644 --- a/tests/runner/base.py +++ b/tests/runner/base.py @@ -91,8 +91,12 @@ def get_lang_env(self, lang_id: str) -> Dict[str, str]: if 'env' in execution: gen_dir = str(self.project_root / lang_config['code_generation']['output_dir']) - env = {k: v.replace('{generated_dir}', gen_dir) - for k, v in execution['env'].items()} + gen_parent_dir = str(Path(gen_dir).parent) + env = {} + for k, v in execution['env'].items(): + v = v.replace('{generated_dir}', gen_dir) + v = v.replace('{generated_parent_dir}', gen_parent_dir) + env[k] = v return env def get_active_languages(self) -> List[str]: diff --git a/tests/runner/plugins.py b/tests/runner/plugins.py index 38689282..0f59b79e 100644 --- a/tests/runner/plugins.py +++ b/tests/runner/plugins.py @@ -51,7 +51,11 @@ class StandardTestPlugin(TestPlugin): plugin_type = "standard" def run(self, suite: Dict[str, Any]) -> Dict[str, Any]: - print(f"\n[TEST] {suite['description']}") + # Check if this suite should skip display (results shown elsewhere) + skip_display = suite.get('skip_display', False) + + if not skip_display: + print(f"\n[TEST] {suite['description']}") results = {} output_files = {} @@ -71,8 +75,9 @@ def run(self, suite: Dict[str, Any]) -> Dict[str, Any]: if output_path.exists(): output_files[lang_id] = output_path - self.formatter.print_lang_results( - self.executor.get_testable_languages(), results) + if not skip_display: + self.formatter.print_lang_results( + self.executor.get_testable_languages(), results) return { 'results': {lang_id: {suite['name']: r} for lang_id, r in results.items()}, @@ -221,10 +226,160 @@ def _run_decoder_with_file(self, lang_id: str, test_config: Dict[str, Any], return False +class FrameFormatMatrixPlugin(TestPlugin): + """ + Plugin for consolidated frame format compatibility testing. + + Runs serialization and deserialization tests for multiple frame formats + and displays results in a single matrix with frame formats as rows + and languages as columns. + """ + + plugin_type = "frame_format_matrix" + + def run(self, suite: Dict[str, Any]) -> Dict[str, Any]: + """Run frame format matrix tests and display consolidated results.""" + self.formatter.print_section("FRAME FORMAT COMPATIBILITY MATRIX") + print(f"[TEST] {suite['description']}") + + # Get frame formats and their corresponding encode/decode suites + frame_formats = suite.get('frame_formats', []) + if not frame_formats: + self.log("frame_format_matrix plugin requires 'frame_formats' field", "ERROR") + return {'results': {}, 'matrix': {}} + + testable = self.executor.get_testable_languages() + results = {lang_id: {} for lang_id in testable} + + # Matrix: frame_format (rows) vs language (columns) + matrix = {} + + for frame_format in frame_formats: + encode_suite = frame_format.get('encode_suite') + decode_suite = frame_format.get('decode_suite') + display_name = frame_format.get('display_name', encode_suite) + + matrix[display_name] = {} + + # Get encoded files from the encode suite + encoded_files = self.executor.get_output_files(encode_suite) + + for lang_id in testable: + lang_name = self.config['languages'][lang_id]['name'] + + # Get C-encoded file (as reference for cross-platform testing) + c_data_file = encoded_files.get('c') + + if c_data_file is None or not c_data_file.exists(): + matrix[display_name][lang_name] = None + continue + + # Build decode test config for this language + decode_config = self._build_decode_config(lang_id, decode_suite) + if not decode_config: + matrix[display_name][lang_name] = None + continue + + # Run decoder with C's encoded file + result = self._run_decoder_with_file(lang_id, decode_config, c_data_file) + matrix[display_name][lang_name] = result + + result_key = f"{decode_suite}_{lang_id}" + results[lang_id][result_key] = result + + self._print_frame_format_matrix(matrix) + + return { + 'results': results, + 'matrix': matrix + } + + def _build_decode_config(self, lang_id: str, decode_suite_name: str) -> Optional[Dict[str, Any]]: + """Build test config for a decode suite.""" + # Find the decode suite in config + for suite in self.config['test_suites']: + if suite['name'] == decode_suite_name: + return self.executor.build_test_config(lang_id, suite) + return None + + def _run_decoder_with_file(self, lang_id: str, test_config: Dict[str, Any], + data_file: Path) -> bool: + """Run a decoder test with a specific input file.""" + lang_config = self.config['languages'][lang_id] + build_dir = self.project_root / \ + lang_config.get('build_dir', lang_config['test_dir']) + target_file = build_dir / data_file.name + + build_dir.mkdir(parents=True, exist_ok=True) + + try: + with self.executor.temp_copy(data_file, target_file): + # TypeScript needs file in JS directory too + if lang_id == 'ts' and 'compiled_file' in test_config: + script_dir = self.project_root / \ + lang_config['execution'].get('script_dir', '') + ts_target = script_dir / data_file.name + with self.executor.temp_copy(data_file, ts_target): + return self.executor.run_test_script( + lang_id, test_config, args=data_file.name) + # JavaScript also needs file in script_dir + elif lang_id == 'js' and 'script_dir' in lang_config.get('execution', {}): + script_dir = self.project_root / \ + lang_config['execution'].get('script_dir', '') + js_target = script_dir / data_file.name + with self.executor.temp_copy(data_file, js_target): + return self.executor.run_test_script( + lang_id, test_config, args=data_file.name) + else: + return self.executor.run_test_script( + lang_id, test_config, args=target_file.name) + except Exception as e: + if self.verbose: + self.log(f"Decode failed: {e}", "WARNING") + return False + + def _print_frame_format_matrix(self, matrix: Dict[str, Dict[str, Optional[bool]]]): + """Print the frame format compatibility matrix.""" + if not matrix: + return + + # Get all language columns + all_langs = sorted(set().union(*[set(d.keys()) for d in matrix.values()])) + + col_width = 12 + print("\nFrame Format Compatibility Matrix:") + header = "Frame Format".ljust(20) + "".join(l.center(col_width) for l in all_langs) + print(header) + print("-" * len(header)) + + success_count = 0 + total_count = 0 + + for frame_format, lang_results in matrix.items(): + row = frame_format.ljust(20) + for lang in all_langs: + val = lang_results.get(lang) + if val is None: + cell = "N/A" + elif val: + cell = "OK" + success_count += 1 + total_count += 1 + else: + cell = "FAIL" + total_count += 1 + row += cell.center(col_width) + print(row) + + if total_count > 0: + print(f"\nSuccess rate: {success_count}/{total_count} ({100*success_count/total_count:.1f}%)\n") + + # Registry of available plugins PLUGIN_REGISTRY: Dict[str, type] = { 'standard': StandardTestPlugin, 'cross_platform_matrix': CrossPlatformMatrixPlugin, + 'frame_format_matrix': FrameFormatMatrixPlugin, } diff --git a/tests/test_config.json b/tests/test_config.json index 1ad811c8..3f26cbab 100644 --- a/tests/test_config.json +++ b/tests/test_config.json @@ -67,7 +67,7 @@ "interpreter": "python", "source_extension": ".py", "env": { - "PYTHONPATH": "{generated_dir}" + "PYTHONPATH": "{generated_dir}:{generated_parent_dir}" } }, "test_dir": "tests/py", @@ -147,17 +147,79 @@ "test_name": "test_arrays" }, { - "name": "cross_platform_encode", - "description": "Cross-platform serialization", - "test_name": "test_cross_platform_serialization", - "output_file": "{lang_name}_test_data.bin" + "name": "basic_default_encode", + "description": "Basic Default format serialization", + "test_name": "test_basic_default_serialization", + "output_file": "{lang_name}_basic_default_test_data.bin" }, { - "name": "cross_platform_decode", - "description": "Cross-platform deserialization", - "test_name": "test_cross_platform_deserialization", - "plugin": "cross_platform_matrix", - "input_from": "cross_platform_encode" + "name": "basic_default_decode", + "description": "Basic Default format deserialization", + "test_name": "test_basic_default_deserialization", + "skip_display": true + }, + { + "name": "basic_minimal_encode", + "description": "Basic Minimal format serialization", + "test_name": "test_basic_minimal_serialization", + "output_file": "{lang_name}_basic_minimal_test_data.bin" + }, + { + "name": "basic_minimal_decode", + "description": "Basic Minimal format deserialization", + "test_name": "test_basic_minimal_deserialization", + "skip_display": true + }, + { + "name": "tiny_default_encode", + "description": "Tiny Default format serialization", + "test_name": "test_tiny_default_serialization", + "output_file": "{lang_name}_tiny_default_test_data.bin" + }, + { + "name": "tiny_default_decode", + "description": "Tiny Default format deserialization", + "test_name": "test_tiny_default_deserialization", + "skip_display": true + }, + { + "name": "tiny_minimal_encode", + "description": "Tiny Minimal format serialization", + "test_name": "test_tiny_minimal_serialization", + "output_file": "{lang_name}_tiny_minimal_test_data.bin" + }, + { + "name": "tiny_minimal_decode", + "description": "Tiny Minimal format deserialization", + "test_name": "test_tiny_minimal_deserialization", + "skip_display": true + }, + { + "name": "frame_format_matrix", + "description": "Frame format cross-compatibility matrix", + "plugin": "frame_format_matrix", + "frame_formats": [ + { + "display_name": "BasicDefault", + "encode_suite": "basic_default_encode", + "decode_suite": "basic_default_decode" + }, + { + "display_name": "BasicMinimal", + "encode_suite": "basic_minimal_encode", + "decode_suite": "basic_minimal_decode" + }, + { + "display_name": "TinyDefault", + "encode_suite": "tiny_default_encode", + "decode_suite": "tiny_default_decode" + }, + { + "display_name": "TinyMinimal", + "encode_suite": "tiny_minimal_encode", + "decode_suite": "tiny_minimal_decode" + } + ] } ] } diff --git a/tests/ts/test_basic_default_deserialization.ts b/tests/ts/test_basic_default_deserialization.ts new file mode 100644 index 00000000..f5c84b35 --- /dev/null +++ b/tests/ts/test_basic_default_deserialization.ts @@ -0,0 +1,129 @@ +/** + * Basic Default frame format deserialization test for TypeScript. + */ +import * as fs from 'fs'; +import * as path from 'path'; + +// BasicDefault constants +const BASIC_DEFAULT_START_BYTE1 = 0x90; +const BASIC_DEFAULT_START_BYTE2 = 0x71; +const BASIC_DEFAULT_HEADER_SIZE = 4; +const BASIC_DEFAULT_FOOTER_SIZE = 2; + +function printFailureDetails(label: string): void { + console.log('\n============================================================'); + console.log(`FAILURE DETAILS: ${label}`); + console.log('============================================================\n'); +} + +function loadExpectedValues(): any { + try { + const jsonPath = path.join(__dirname, '../../../expected_values.json'); + const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8')); + return data.serialization_test; + } catch (error) { + console.log(`Error loading expected values: ${error}`); + return null; + } +} + +function validateBasicDefault(buffer: Buffer, expected: any): boolean { + if (buffer.length < BASIC_DEFAULT_HEADER_SIZE + BASIC_DEFAULT_FOOTER_SIZE) { + console.log(' Data too short'); + return false; + } + + if (buffer[0] !== BASIC_DEFAULT_START_BYTE1 || buffer[1] !== BASIC_DEFAULT_START_BYTE2) { + console.log(' Invalid start bytes'); + return false; + } + + if (buffer[3] !== 204) { + console.log(' Invalid message ID'); + return false; + } + + const msgLen = buffer.length - BASIC_DEFAULT_HEADER_SIZE - BASIC_DEFAULT_FOOTER_SIZE; + let byte1 = buffer[2]; + let byte2 = buffer[2]; + byte1 = (byte1 + buffer[3]) % 256; + byte2 = (byte2 + byte1) % 256; + for (let i = 0; i < msgLen; i++) { + byte1 = (byte1 + buffer[BASIC_DEFAULT_HEADER_SIZE + i]) & 0xFF; + byte2 = (byte2 + byte1) & 0xFF; + } + + if (byte1 !== buffer[buffer.length - 2] || byte2 !== buffer[buffer.length - 1]) { + console.log(' Checksum mismatch'); + return false; + } + + const magicNumber = buffer.readUInt32LE(BASIC_DEFAULT_HEADER_SIZE); + if (magicNumber !== expected.magic_number) { + console.log(' Magic number mismatch'); + return false; + } + + console.log(' [OK] Data validated successfully'); + return true; +} + +function readAndValidateTestData(filename: string): boolean { + try { + if (!fs.existsSync(filename)) { + console.log(` Error: file not found: ${filename}`); + return false; + } + + const binaryData = fs.readFileSync(filename); + + if (binaryData.length === 0) { + printFailureDetails('Empty file'); + return false; + } + + const expected = loadExpectedValues(); + if (!expected) { + return false; + } + + if (!validateBasicDefault(binaryData, expected)) { + console.log(' Validation failed'); + return false; + } + + return true; + } catch (error) { + printFailureDetails(`Read data exception: ${error}`); + return false; + } +} + +function main(): boolean { + console.log('\n[TEST START] TypeScript Basic Default Deserialization'); + + const args = process.argv.slice(2); + if (args.length !== 1) { + console.log(` Usage: ${process.argv[1]} `); + console.log('[TEST END] TypeScript Basic Default Deserialization: FAIL\n'); + return false; + } + + try { + const success = readAndValidateTestData(args[0]); + + console.log(`[TEST END] TypeScript Basic Default Deserialization: ${success ? 'PASS' : 'FAIL'}\n`); + return success; + } catch (error) { + printFailureDetails(`Exception: ${error}`); + console.log('[TEST END] TypeScript Basic Default Deserialization: FAIL\n'); + return false; + } +} + +if (require.main === module) { + const success = main(); + process.exit(success ? 0 : 1); +} + +export { main }; diff --git a/tests/ts/test_basic_default_serialization.ts b/tests/ts/test_basic_default_serialization.ts new file mode 100644 index 00000000..da5327f3 --- /dev/null +++ b/tests/ts/test_basic_default_serialization.ts @@ -0,0 +1,129 @@ +/** + * Basic Default frame format serialization test for TypeScript. + */ +import * as fs from 'fs'; +import * as path from 'path'; + +// BasicDefault constants +const BASIC_DEFAULT_START_BYTE1 = 0x90; +const BASIC_DEFAULT_START_BYTE2 = 0x71; +const BASIC_DEFAULT_HEADER_SIZE = 4; +const BASIC_DEFAULT_FOOTER_SIZE = 2; + +function printFailureDetails(label: string, rawData?: Buffer): void { + console.log('\n============================================================'); + console.log(`FAILURE DETAILS: ${label}`); + console.log('============================================================'); + + if (rawData && rawData.length > 0) { + console.log(`\nRaw Data (${rawData.length} bytes):`); + console.log(` Hex: ${rawData.toString('hex').substring(0, 128)}${rawData.length > 64 ? '...' : ''}`); + } + + console.log('============================================================\n'); +} + +function loadExpectedValues(): any { + try { + const jsonPath = path.join(__dirname, '../../../expected_values.json'); + const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8')); + return data.serialization_test; + } catch (error) { + console.log(`Error loading expected values: ${error}`); + return null; + } +} + +function createTestData(): boolean { + try { + const expected = loadExpectedValues(); + if (!expected) { + return false; + } + + const msg_id = 204; + const payloadSize = 95; + const payload = Buffer.alloc(payloadSize); + let offset = 0; + + payload.writeUInt32LE(expected.magic_number, offset); + offset += 4; + + const testString = expected.test_string; + payload.writeUInt8(testString.length, offset); + offset += 1; + Buffer.from(testString).copy(payload, offset, 0, testString.length); + offset += 64; + + payload.writeFloatLE(expected.test_float, offset); + offset += 4; + + payload.writeUInt8(expected.test_bool ? 1 : 0, offset); + offset += 1; + + const testArray: number[] = expected.test_array; + payload.writeUInt8(testArray.length, offset); + offset += 1; + for (let i = 0; i < 5; i++) { + if (i < testArray.length) { + payload.writeInt32LE(testArray[i], offset); + } else { + payload.writeInt32LE(0, offset); + } + offset += 4; + } + + let byte1 = payloadSize & 0xFF; + let byte2 = payloadSize & 0xFF; + byte1 = (byte1 + msg_id) & 0xFF; + byte2 = (byte2 + byte1) & 0xFF; + for (let i = 0; i < payload.length; i++) { + byte1 = (byte1 + payload[i]) & 0xFF; + byte2 = (byte2 + byte1) & 0xFF; + } + + const frame = Buffer.alloc(BASIC_DEFAULT_HEADER_SIZE + payloadSize + BASIC_DEFAULT_FOOTER_SIZE); + frame[0] = BASIC_DEFAULT_START_BYTE1; + frame[1] = BASIC_DEFAULT_START_BYTE2; + frame[2] = payloadSize & 0xFF; + frame[3] = msg_id; + payload.copy(frame, BASIC_DEFAULT_HEADER_SIZE); + frame[frame.length - 2] = byte1; + frame[frame.length - 1] = byte2; + + const outputPath = fs.existsSync('tests/generated/ts/js') + ? 'tests/generated/ts/js/typescript_basic_default_test_data.bin' + : 'typescript_basic_default_test_data.bin'; + fs.writeFileSync(outputPath, frame); + + return true; + } catch (error) { + printFailureDetails(`Create test data exception: ${error}`); + return false; + } +} + +function main(): boolean { + console.log('\n[TEST START] TypeScript Basic Default Serialization'); + + try { + if (!createTestData()) { + console.log('[TEST END] TypeScript Basic Default Serialization: FAIL\n'); + return false; + } + + console.log('[TEST END] TypeScript Basic Default Serialization: PASS\n'); + return true; + } catch (error) { + printFailureDetails(`Exception: ${error}`); + console.log('[TEST END] TypeScript Basic Default Serialization: FAIL\n'); + return false; + } +} + +if (require.main === module) { + const success = main(); + process.exit(success ? 0 : 1); +} + +export { main }; diff --git a/tests/ts/test_basic_minimal_deserialization.ts b/tests/ts/test_basic_minimal_deserialization.ts new file mode 100644 index 00000000..8108bb4b --- /dev/null +++ b/tests/ts/test_basic_minimal_deserialization.ts @@ -0,0 +1,114 @@ +/** + * Basic Minimal frame format deserialization test for TypeScript. + */ +import * as fs from 'fs'; +import * as path from 'path'; + +// BasicMinimal constants +const BASIC_MINIMAL_START_BYTE1 = 0x90; +const BASIC_MINIMAL_START_BYTE2 = 0x70; +const BASIC_MINIMAL_HEADER_SIZE = 3; +const BASIC_MINIMAL_FOOTER_SIZE = 0; + +function printFailureDetails(label: string): void { + console.log('\n============================================================'); + console.log(`FAILURE DETAILS: ${label}`); + console.log('============================================================\n'); +} + +function loadExpectedValues(): any { + try { + const jsonPath = path.join(__dirname, '../../../expected_values.json'); + const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8')); + return data.serialization_test; + } catch (error) { + console.log(`Error loading expected values: ${error}`); + return null; + } +} + +function validateBasicMinimal(buffer: Buffer, expected: any): boolean { + if (buffer.length < BASIC_MINIMAL_HEADER_SIZE + BASIC_MINIMAL_FOOTER_SIZE) { + console.log(' Data too short'); + return false; + } + + if (buffer[0] !== BASIC_MINIMAL_START_BYTE1 || buffer[1] !== BASIC_MINIMAL_START_BYTE2) { + console.log(' Invalid start bytes'); + return false; + } + + if (buffer[2] !== 204) { + console.log(' Invalid message ID'); + return false; + } + + const magicNumber = buffer.readUInt32LE(BASIC_MINIMAL_HEADER_SIZE); + if (magicNumber !== expected.magic_number) { + console.log(' Magic number mismatch'); + return false; + } + + console.log(' [OK] Data validated successfully'); + return true; +} + +function readAndValidateTestData(filename: string): boolean { + try { + if (!fs.existsSync(filename)) { + console.log(` Error: file not found: ${filename}`); + return false; + } + + const binaryData = fs.readFileSync(filename); + + if (binaryData.length === 0) { + printFailureDetails('Empty file'); + return false; + } + + const expected = loadExpectedValues(); + if (!expected) { + return false; + } + + if (!validateBasicMinimal(binaryData, expected)) { + console.log(' Validation failed'); + return false; + } + + return true; + } catch (error) { + printFailureDetails(`Read data exception: ${error}`); + return false; + } +} + +function main(): boolean { + console.log('\n[TEST START] TypeScript Basic Minimal Deserialization'); + + const args = process.argv.slice(2); + if (args.length !== 1) { + console.log(` Usage: ${process.argv[1]} `); + console.log('[TEST END] TypeScript Basic Minimal Deserialization: FAIL\n'); + return false; + } + + try { + const success = readAndValidateTestData(args[0]); + + console.log(`[TEST END] TypeScript Basic Minimal Deserialization: ${success ? 'PASS' : 'FAIL'}\n`); + return success; + } catch (error) { + printFailureDetails(`Exception: ${error}`); + console.log('[TEST END] TypeScript Basic Minimal Deserialization: FAIL\n'); + return false; + } +} + +if (require.main === module) { + const success = main(); + process.exit(success ? 0 : 1); +} + +export { main }; diff --git a/tests/ts/test_basic_minimal_serialization.ts b/tests/ts/test_basic_minimal_serialization.ts new file mode 100644 index 00000000..8077f8ce --- /dev/null +++ b/tests/ts/test_basic_minimal_serialization.ts @@ -0,0 +1,110 @@ +/** + * Basic Minimal frame format serialization test for TypeScript. + */ +import * as fs from 'fs'; +import * as path from 'path'; + +// BasicMinimal constants +const BASIC_MINIMAL_START_BYTE1 = 0x90; +const BASIC_MINIMAL_START_BYTE2 = 0x70; +const BASIC_MINIMAL_HEADER_SIZE = 3; +const BASIC_MINIMAL_FOOTER_SIZE = 0; + +function printFailureDetails(label: string): void { + console.log('\n============================================================'); + console.log(`FAILURE DETAILS: ${label}`); + console.log('============================================================\n'); +} + +function loadExpectedValues(): any { + try { + const jsonPath = path.join(__dirname, '../../../expected_values.json'); + const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8')); + return data.serialization_test; + } catch (error) { + console.log(`Error loading expected values: ${error}`); + return null; + } +} + +function createTestData(): boolean { + try { + const expected = loadExpectedValues(); + if (!expected) { + return false; + } + + const msg_id = 204; + const payloadSize = 95; + const payload = Buffer.alloc(payloadSize); + let offset = 0; + + payload.writeUInt32LE(expected.magic_number, offset); + offset += 4; + + const testString = expected.test_string; + payload.writeUInt8(testString.length, offset); + offset += 1; + Buffer.from(testString).copy(payload, offset, 0, testString.length); + offset += 64; + + payload.writeFloatLE(expected.test_float, offset); + offset += 4; + + payload.writeUInt8(expected.test_bool ? 1 : 0, offset); + offset += 1; + + const testArray: number[] = expected.test_array; + payload.writeUInt8(testArray.length, offset); + offset += 1; + for (let i = 0; i < 5; i++) { + if (i < testArray.length) { + payload.writeInt32LE(testArray[i], offset); + } else { + payload.writeInt32LE(0, offset); + } + offset += 4; + } + + const frame = Buffer.alloc(BASIC_MINIMAL_HEADER_SIZE + payloadSize + BASIC_MINIMAL_FOOTER_SIZE); + frame[0] = BASIC_MINIMAL_START_BYTE1; + frame[1] = BASIC_MINIMAL_START_BYTE2; + frame[2] = msg_id; + payload.copy(frame, BASIC_MINIMAL_HEADER_SIZE); + + const outputPath = fs.existsSync('tests/generated/ts/js') + ? 'tests/generated/ts/js/typescript_basic_minimal_test_data.bin' + : 'typescript_basic_minimal_test_data.bin'; + fs.writeFileSync(outputPath, frame); + + return true; + } catch (error) { + printFailureDetails(`Create test data exception: ${error}`); + return false; + } +} + +function main(): boolean { + console.log('\n[TEST START] TypeScript Basic Minimal Serialization'); + + try { + if (!createTestData()) { + console.log('[TEST END] TypeScript Basic Minimal Serialization: FAIL\n'); + return false; + } + + console.log('[TEST END] TypeScript Basic Minimal Serialization: PASS\n'); + return true; + } catch (error) { + printFailureDetails(`Exception: ${error}`); + console.log('[TEST END] TypeScript Basic Minimal Serialization: FAIL\n'); + return false; + } +} + +if (require.main === module) { + const success = main(); + process.exit(success ? 0 : 1); +} + +export { main }; diff --git a/tests/ts/test_tiny_default_deserialization.ts b/tests/ts/test_tiny_default_deserialization.ts new file mode 100644 index 00000000..dfab208c --- /dev/null +++ b/tests/ts/test_tiny_default_deserialization.ts @@ -0,0 +1,128 @@ +/** + * Tiny Default frame format deserialization test for TypeScript. + */ +import * as fs from 'fs'; +import * as path from 'path'; + +// TinyDefault constants +const TINY_DEFAULT_START_BYTE = 0x71; +const TINY_DEFAULT_HEADER_SIZE = 3; +const TINY_DEFAULT_FOOTER_SIZE = 2; + +function printFailureDetails(label: string): void { + console.log('\n============================================================'); + console.log(`FAILURE DETAILS: ${label}`); + console.log('============================================================\n'); +} + +function loadExpectedValues(): any { + try { + const jsonPath = path.join(__dirname, '../../../expected_values.json'); + const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8')); + return data.serialization_test; + } catch (error) { + console.log(`Error loading expected values: ${error}`); + return null; + } +} + +function validateTinyDefault(buffer: Buffer, expected: any): boolean { + if (buffer.length < TINY_DEFAULT_HEADER_SIZE + TINY_DEFAULT_FOOTER_SIZE) { + console.log(' Data too short'); + return false; + } + + if (buffer[0] !== TINY_DEFAULT_START_BYTE) { + console.log(' Invalid start byte'); + return false; + } + + if (buffer[2] !== 204) { + console.log(' Invalid message ID'); + return false; + } + + const msgLen = buffer.length - TINY_DEFAULT_HEADER_SIZE - TINY_DEFAULT_FOOTER_SIZE; + let byte1 = buffer[1]; + let byte2 = buffer[1]; + byte1 = (byte1 + buffer[2]) % 256; + byte2 = (byte2 + byte1) % 256; + for (let i = 0; i < msgLen; i++) { + byte1 = (byte1 + buffer[TINY_DEFAULT_HEADER_SIZE + i]) & 0xFF; + byte2 = (byte2 + byte1) & 0xFF; + } + + if (byte1 !== buffer[buffer.length - 2] || byte2 !== buffer[buffer.length - 1]) { + console.log(' Checksum mismatch'); + return false; + } + + const magicNumber = buffer.readUInt32LE(TINY_DEFAULT_HEADER_SIZE); + if (magicNumber !== expected.magic_number) { + console.log(' Magic number mismatch'); + return false; + } + + console.log(' [OK] Data validated successfully'); + return true; +} + +function readAndValidateTestData(filename: string): boolean { + try { + if (!fs.existsSync(filename)) { + console.log(` Error: file not found: ${filename}`); + return false; + } + + const binaryData = fs.readFileSync(filename); + + if (binaryData.length === 0) { + printFailureDetails('Empty file'); + return false; + } + + const expected = loadExpectedValues(); + if (!expected) { + return false; + } + + if (!validateTinyDefault(binaryData, expected)) { + console.log(' Validation failed'); + return false; + } + + return true; + } catch (error) { + printFailureDetails(`Read data exception: ${error}`); + return false; + } +} + +function main(): boolean { + console.log('\n[TEST START] TypeScript Tiny Default Deserialization'); + + const args = process.argv.slice(2); + if (args.length !== 1) { + console.log(` Usage: ${process.argv[1]} `); + console.log('[TEST END] TypeScript Tiny Default Deserialization: FAIL\n'); + return false; + } + + try { + const success = readAndValidateTestData(args[0]); + + console.log(`[TEST END] TypeScript Tiny Default Deserialization: ${success ? 'PASS' : 'FAIL'}\n`); + return success; + } catch (error) { + printFailureDetails(`Exception: ${error}`); + console.log('[TEST END] TypeScript Tiny Default Deserialization: FAIL\n'); + return false; + } +} + +if (require.main === module) { + const success = main(); + process.exit(success ? 0 : 1); +} + +export { main }; diff --git a/tests/ts/test_tiny_default_serialization.ts b/tests/ts/test_tiny_default_serialization.ts new file mode 100644 index 00000000..075297d0 --- /dev/null +++ b/tests/ts/test_tiny_default_serialization.ts @@ -0,0 +1,120 @@ +/** + * Tiny Default frame format serialization test for TypeScript. + */ +import * as fs from 'fs'; +import * as path from 'path'; + +// TinyDefault constants +const TINY_DEFAULT_START_BYTE = 0x71; +const TINY_DEFAULT_HEADER_SIZE = 3; +const TINY_DEFAULT_FOOTER_SIZE = 2; + +function printFailureDetails(label: string): void { + console.log('\n============================================================'); + console.log(`FAILURE DETAILS: ${label}`); + console.log('============================================================\n'); +} + +function loadExpectedValues(): any { + try { + const jsonPath = path.join(__dirname, '../../../expected_values.json'); + const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8')); + return data.serialization_test; + } catch (error) { + console.log(`Error loading expected values: ${error}`); + return null; + } +} + +function createTestData(): boolean { + try { + const expected = loadExpectedValues(); + if (!expected) { + return false; + } + + const msg_id = 204; + const payloadSize = 95; + const payload = Buffer.alloc(payloadSize); + let offset = 0; + + payload.writeUInt32LE(expected.magic_number, offset); + offset += 4; + + const testString = expected.test_string; + payload.writeUInt8(testString.length, offset); + offset += 1; + Buffer.from(testString).copy(payload, offset, 0, testString.length); + offset += 64; + + payload.writeFloatLE(expected.test_float, offset); + offset += 4; + + payload.writeUInt8(expected.test_bool ? 1 : 0, offset); + offset += 1; + + const testArray: number[] = expected.test_array; + payload.writeUInt8(testArray.length, offset); + offset += 1; + for (let i = 0; i < 5; i++) { + if (i < testArray.length) { + payload.writeInt32LE(testArray[i], offset); + } else { + payload.writeInt32LE(0, offset); + } + offset += 4; + } + + let byte1 = payloadSize & 0xFF; + let byte2 = payloadSize & 0xFF; + byte1 = (byte1 + msg_id) & 0xFF; + byte2 = (byte2 + byte1) & 0xFF; + for (let i = 0; i < payload.length; i++) { + byte1 = (byte1 + payload[i]) & 0xFF; + byte2 = (byte2 + byte1) & 0xFF; + } + + const frame = Buffer.alloc(TINY_DEFAULT_HEADER_SIZE + payloadSize + TINY_DEFAULT_FOOTER_SIZE); + frame[0] = TINY_DEFAULT_START_BYTE; + frame[1] = payloadSize & 0xFF; + frame[2] = msg_id; + payload.copy(frame, TINY_DEFAULT_HEADER_SIZE); + frame[frame.length - 2] = byte1; + frame[frame.length - 1] = byte2; + + const outputPath = fs.existsSync('tests/generated/ts/js') + ? 'tests/generated/ts/js/typescript_tiny_default_test_data.bin' + : 'typescript_tiny_default_test_data.bin'; + fs.writeFileSync(outputPath, frame); + + return true; + } catch (error) { + printFailureDetails(`Create test data exception: ${error}`); + return false; + } +} + +function main(): boolean { + console.log('\n[TEST START] TypeScript Tiny Default Serialization'); + + try { + if (!createTestData()) { + console.log('[TEST END] TypeScript Tiny Default Serialization: FAIL\n'); + return false; + } + + console.log('[TEST END] TypeScript Tiny Default Serialization: PASS\n'); + return true; + } catch (error) { + printFailureDetails(`Exception: ${error}`); + console.log('[TEST END] TypeScript Tiny Default Serialization: FAIL\n'); + return false; + } +} + +if (require.main === module) { + const success = main(); + process.exit(success ? 0 : 1); +} + +export { main }; diff --git a/tests/ts/test_tiny_minimal_deserialization.ts b/tests/ts/test_tiny_minimal_deserialization.ts new file mode 100644 index 00000000..4cf69b1c --- /dev/null +++ b/tests/ts/test_tiny_minimal_deserialization.ts @@ -0,0 +1,113 @@ +/** + * Tiny Minimal frame format deserialization test for TypeScript. + */ +import * as fs from 'fs'; +import * as path from 'path'; + +// TinyMinimal constants +const TINY_MINIMAL_START_BYTE = 0x70; +const TINY_MINIMAL_HEADER_SIZE = 2; +const TINY_MINIMAL_FOOTER_SIZE = 0; + +function printFailureDetails(label: string): void { + console.log('\n============================================================'); + console.log(`FAILURE DETAILS: ${label}`); + console.log('============================================================\n'); +} + +function loadExpectedValues(): any { + try { + const jsonPath = path.join(__dirname, '../../../expected_values.json'); + const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8')); + return data.serialization_test; + } catch (error) { + console.log(`Error loading expected values: ${error}`); + return null; + } +} + +function validateTinyMinimal(buffer: Buffer, expected: any): boolean { + if (buffer.length < TINY_MINIMAL_HEADER_SIZE + TINY_MINIMAL_FOOTER_SIZE) { + console.log(' Data too short'); + return false; + } + + if (buffer[0] !== TINY_MINIMAL_START_BYTE) { + console.log(' Invalid start byte'); + return false; + } + + if (buffer[1] !== 204) { + console.log(' Invalid message ID'); + return false; + } + + const magicNumber = buffer.readUInt32LE(TINY_MINIMAL_HEADER_SIZE); + if (magicNumber !== expected.magic_number) { + console.log(' Magic number mismatch'); + return false; + } + + console.log(' [OK] Data validated successfully'); + return true; +} + +function readAndValidateTestData(filename: string): boolean { + try { + if (!fs.existsSync(filename)) { + console.log(` Error: file not found: ${filename}`); + return false; + } + + const binaryData = fs.readFileSync(filename); + + if (binaryData.length === 0) { + printFailureDetails('Empty file'); + return false; + } + + const expected = loadExpectedValues(); + if (!expected) { + return false; + } + + if (!validateTinyMinimal(binaryData, expected)) { + console.log(' Validation failed'); + return false; + } + + return true; + } catch (error) { + printFailureDetails(`Read data exception: ${error}`); + return false; + } +} + +function main(): boolean { + console.log('\n[TEST START] TypeScript Tiny Minimal Deserialization'); + + const args = process.argv.slice(2); + if (args.length !== 1) { + console.log(` Usage: ${process.argv[1]} `); + console.log('[TEST END] TypeScript Tiny Minimal Deserialization: FAIL\n'); + return false; + } + + try { + const success = readAndValidateTestData(args[0]); + + console.log(`[TEST END] TypeScript Tiny Minimal Deserialization: ${success ? 'PASS' : 'FAIL'}\n`); + return success; + } catch (error) { + printFailureDetails(`Exception: ${error}`); + console.log('[TEST END] TypeScript Tiny Minimal Deserialization: FAIL\n'); + return false; + } +} + +if (require.main === module) { + const success = main(); + process.exit(success ? 0 : 1); +} + +export { main }; diff --git a/tests/ts/test_tiny_minimal_serialization.ts b/tests/ts/test_tiny_minimal_serialization.ts new file mode 100644 index 00000000..26ceb49e --- /dev/null +++ b/tests/ts/test_tiny_minimal_serialization.ts @@ -0,0 +1,108 @@ +/** + * Tiny Minimal frame format serialization test for TypeScript. + */ +import * as fs from 'fs'; +import * as path from 'path'; + +// TinyMinimal constants +const TINY_MINIMAL_START_BYTE = 0x70; +const TINY_MINIMAL_HEADER_SIZE = 2; +const TINY_MINIMAL_FOOTER_SIZE = 0; + +function printFailureDetails(label: string): void { + console.log('\n============================================================'); + console.log(`FAILURE DETAILS: ${label}`); + console.log('============================================================\n'); +} + +function loadExpectedValues(): any { + try { + const jsonPath = path.join(__dirname, '../../../expected_values.json'); + const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8')); + return data.serialization_test; + } catch (error) { + console.log(`Error loading expected values: ${error}`); + return null; + } +} + +function createTestData(): boolean { + try { + const expected = loadExpectedValues(); + if (!expected) { + return false; + } + + const msg_id = 204; + const payloadSize = 95; + const payload = Buffer.alloc(payloadSize); + let offset = 0; + + payload.writeUInt32LE(expected.magic_number, offset); + offset += 4; + + const testString = expected.test_string; + payload.writeUInt8(testString.length, offset); + offset += 1; + Buffer.from(testString).copy(payload, offset, 0, testString.length); + offset += 64; + + payload.writeFloatLE(expected.test_float, offset); + offset += 4; + + payload.writeUInt8(expected.test_bool ? 1 : 0, offset); + offset += 1; + + const testArray: number[] = expected.test_array; + payload.writeUInt8(testArray.length, offset); + offset += 1; + for (let i = 0; i < 5; i++) { + if (i < testArray.length) { + payload.writeInt32LE(testArray[i], offset); + } else { + payload.writeInt32LE(0, offset); + } + offset += 4; + } + + const frame = Buffer.alloc(TINY_MINIMAL_HEADER_SIZE + payloadSize + TINY_MINIMAL_FOOTER_SIZE); + frame[0] = TINY_MINIMAL_START_BYTE; + frame[1] = msg_id; + payload.copy(frame, TINY_MINIMAL_HEADER_SIZE); + + const outputPath = fs.existsSync('tests/generated/ts/js') + ? 'tests/generated/ts/js/typescript_tiny_minimal_test_data.bin' + : 'typescript_tiny_minimal_test_data.bin'; + fs.writeFileSync(outputPath, frame); + + return true; + } catch (error) { + printFailureDetails(`Create test data exception: ${error}`); + return false; + } +} + +function main(): boolean { + console.log('\n[TEST START] TypeScript Tiny Minimal Serialization'); + + try { + if (!createTestData()) { + console.log('[TEST END] TypeScript Tiny Minimal Serialization: FAIL\n'); + return false; + } + + console.log('[TEST END] TypeScript Tiny Minimal Serialization: PASS\n'); + return true; + } catch (error) { + printFailureDetails(`Exception: ${error}`); + console.log('[TEST END] TypeScript Tiny Minimal Serialization: FAIL\n'); + return false; + } +} + +if (require.main === module) { + const success = main(); + process.exit(success ? 0 : 1); +} + +export { main };