-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathllm_cache.json
More file actions
4 lines (4 loc) · 38.1 KB
/
llm_cache.json
File metadata and controls
4 lines (4 loc) · 38.1 KB
1
2
3
4
{
"\n You are an expert C unit testing engineer. Your task is to write a complete C test file that implements the following approved test plan for the source code in `spi.c`.\n\n **Implement this EXACT test plan:**\n # SPI Driver Test Plan\n\nThis test plan outlines the test cases for the functions defined in `spi.c`, based on both the provided source code and the specified functional requirements.\n\n---\n\n## 1. `spi_init`\n\n### Test Cases\n\n- **Initialization Success**\n - Verify that `spi_init` returns `SPI_SUCCESS` when the SPI driver is uninitialized.\n - Confirm that after successful initialization, the driver state is set to `SPI_STATE_INITIALIZED`.\n - Confirm that default config values are set: `mode = 0`, `speed_hz = 1000000`.\n\n- **Already Initialized Error**\n - Call `spi_init` after it has already been called (state is `SPI_STATE_INITIALIZED`).\n - Verify that it returns `SPI_ERROR_ALREADY_INITIALIZED`.\n - Confirm that internal config/state does not change on subsequent calls.\n\n---\n\n## 2. `spi_set_config`\n\n### Test Cases\n\n- **Set Config Success - All Valid Modes/Speeds**\n - For each valid combination of mode (0, 1, 2, 3) and speed (1000000, 4000000, 8000000):\n - Initialize SPI.\n - Create a valid `spi_config_t` with chosen mode and speed.\n - Call `spi_set_config` and verify it returns `SPI_SUCCESS`.\n - Confirm that the internal config is updated accordingly.\n\n- **Error: Not Initialized**\n - Call `spi_set_config` before `spi_init`.\n - Verify that it returns `SPI_ERROR_NOT_INITIALIZED`.\n\n- **Error: Null Pointer**\n - Initialize SPI.\n - Call `spi_set_config` with `NULL` pointer.\n - Verify that it returns `SPI_ERROR_NULL_POINTER`.\n\n- **Error: Invalid Mode**\n - Initialize SPI.\n - Provide a `spi_config_t` with `mode = 4` (invalid value).\n - Verify that it returns `SPI_ERROR_INVALID_ARG`.\n\n- **Error: Invalid Speed**\n - Initialize SPI.\n - Provide a `spi_config_t` with valid mode and unsupported speed (e.g., 500000).\n - Verify that it returns `SPI_ERROR_INVALID_ARG`.\n\n---\n\n## 3. `spi_transfer`\n\n### Test Cases\n\n- **Transfer Success: Normal Operation**\n - Initialize SPI.\n - Allocate `tx_buffer` and `rx_buffer` of a valid length (e.g., 16).\n - Call `spi_transfer` and verify it returns `SPI_SUCCESS`.\n - Confirm that data is transferred correctly: rx receives copied values.\n - Validate correct SPI state transitions (set to BUSY during, restored to INITIALIZED after).\n\n- **Transmit Only (rx_buffer = NULL)**\n - Provide non-NULL `tx_buffer`, set `rx_buffer` to NULL.\n - Verify transfer success, no crash.\n\n- **Receive Only (tx_buffer = NULL)**\n - Provide non-NULL `rx_buffer`, set `tx_buffer` to NULL.\n - Verify transfer success, `rx_buffer` should be filled with default value (0xFF).\n\n- **Error: Driver Not Initialized**\n - Call `spi_transfer` before calling `spi_init`.\n - Verify that it returns `SPI_ERROR_NOT_INITIALIZED`.\n\n- **Error: Both Buffers NULL**\n - Initialize SPI.\n - Call `spi_transfer` with both `tx_buffer` and `rx_buffer` NULL.\n - Verify that it returns `SPI_ERROR_INVALID_ARG`.\n\n- **Error: Length is Zero**\n - Initialize SPI.\n - Call `spi_transfer` with valid buffers but length = 0.\n - Verify that it returns `SPI_ERROR_INVALID_LENGTH`.\n\n- **Error: Length Exceeds Maximum**\n - Initialize SPI.\n - Call `spi_transfer` with length > 2048 (e.g., 2049).\n - Verify that it returns `SPI_ERROR_INVALID_LENGTH`.\n\n---\n\n## 4. **Edge & State Cases**\n\n- **Multiple Sequential Transfers**\n - Perform multiple sequential transfers and confirm state resets to `SPI_STATE_INITIALIZED` each time.\n\n- **Concurrent Operations**\n - Attempt configuration changes or re-initialization while transfer is \"in progress\" (simulate by manipulating state) and ensure proper error handling (if state model is strictly enforced).\n\n---\n\n## 5. **Code Coverage**\n\n- Ensure all error and success branches in `spi_init`, `spi_set_config`, and `spi_transfer` are exercised.\n- Cover test-only helper implementations (`test_spi_get_state`, `test_spi_get_config`) by checking state/config after operations.\n\n---\n\n# End of Test Plan\n\n **Base the tests on this source code:**\n ```c\n #include \"spi.h\"\n#include <stdbool.h>\n\n#ifdef TEST\nspi_state_t g_spi_state = SPI_STATE_UNINITIALIZED;\nspi_config_t g_spi_config;\n#else\nstatic spi_state_t g_spi_state = SPI_STATE_UNINITIALIZED;\nstatic spi_config_t g_spi_config;\n#endif\n// --- END OF FIX ---\n\n\nstatic bool is_valid_speed(uint32_t speed) {\n return (speed == 1000000 || speed == 4000000 || speed == 8000000);\n}\n\nint spi_init(void) {\n if (g_spi_state != SPI_STATE_UNINITIALIZED) {\n return SPI_ERROR_ALREADY_INITIALIZED;\n }\n g_spi_config.mode = 0;\n g_spi_config.speed_hz = 1000000;\n g_spi_state = SPI_STATE_INITIALIZED;\n return SPI_SUCCESS;\n}\n\nint spi_set_config(const spi_config_t* config) {\n if (g_spi_state == SPI_STATE_UNINITIALIZED) {\n return SPI_ERROR_NOT_INITIALIZED;\n }\n if (config == NULL) {\n return SPI_ERROR_NULL_POINTER;\n }\n if (config->mode > 3) {\n return SPI_ERROR_INVALID_ARG;\n }\n if (!is_valid_speed(config->speed_hz)) {\n return SPI_ERROR_INVALID_ARG;\n }\n g_spi_config = *config;\n return SPI_SUCCESS;\n}\n\nint spi_transfer(const uint8_t* tx_buffer, uint8_t* rx_buffer, uint16_t len) {\n if (g_spi_state == SPI_STATE_UNINITIALIZED) {\n return SPI_ERROR_NOT_INITIALIZED;\n }\n if (tx_buffer == NULL && rx_buffer == NULL) {\n return SPI_ERROR_INVALID_ARG;\n }\n if (len == 0 || len > 2048) {\n return SPI_ERROR_INVALID_LENGTH;\n }\n g_spi_state = SPI_STATE_BUSY;\n for (uint16_t i = 0; i < len; ++i) {\n uint8_t tx_byte = (tx_buffer) ? tx_buffer[i] : 0xFF;\n uint8_t rx_byte = tx_byte;\n if (rx_buffer) {\n rx_buffer[i] = rx_byte;\n }\n }\n g_spi_state = SPI_STATE_INITIALIZED;\n return SPI_SUCCESS;\n}\n\n// --- Test-only helper implementations ---\n#ifdef TEST\nspi_state_t test_spi_get_state(void) {\n return g_spi_state;\n}\nspi_config_t test_spi_get_config(void) {\n return g_spi_config;\n}\n#endif\n ```\n \n **CRITICAL INSTRUCTIONS:**\n 1. Write a complete C file containing Unity tests. The code must be complete and syntactically correct.\n 2. Include the necessary headers: `#include \"unity.h\"`, `#include \"spi.h\"`.\n 3. **To access the internal state for testing, you MUST declare the global variables from `spi.c` as `extern`. Add these lines at the top of the test file:**\n ```c\n extern spi_state_t g_spi_state;\n extern spi_config_t g_spi_config;\n ```\n 4. Implement the `setUp()` function to reset the state before each test.\n ": "```c\n// test_spi.c\n\n#define TEST\n\n#include \"unity.h\"\n#include \"spi.h\"\n#include <string.h>\n#include <stdint.h>\n\nextern spi_state_t g_spi_state;\nextern spi_config_t g_spi_config;\n\n// Test-only helpers (provided in source when TEST is defined)\nspi_state_t test_spi_get_state(void);\nspi_config_t test_spi_get_config(void);\n\n// Utility: All valid combinations for tests\nstatic const uint8_t valid_modes[] = {0, 1, 2, 3};\nstatic const uint32_t valid_speeds[] = {1000000, 4000000, 8000000};\n\n// Utility: A default-filled buffer for transfers\nstatic uint8_t tx_test_buffer[4096];\nstatic uint8_t rx_test_buffer[4096];\n\nvoid setUp(void)\n{\n // Reset driver state and config before each test.\n g_spi_state = SPI_STATE_UNINITIALIZED;\n g_spi_config.mode = 0xFF;\n g_spi_config.speed_hz = 0;\n\n // Also clear test buffers\n memset(tx_test_buffer, 0xA5, sizeof(tx_test_buffer));\n memset(rx_test_buffer, 0x00, sizeof(rx_test_buffer));\n}\n\n// ==============================\n// 1. spi_init\n// ==============================\n\nvoid test_spi_init_success(void)\n{\n int ret = spi_init();\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, ret);\n\n // State updated\n TEST_ASSERT_EQUAL_INT(SPI_STATE_INITIALIZED, test_spi_get_state());\n // Config set to defaults\n spi_config_t cfg = test_spi_get_config();\n TEST_ASSERT_EQUAL_UINT8(0, cfg.mode);\n TEST_ASSERT_EQUAL_UINT32(1000000, cfg.speed_hz);\n}\n\nvoid test_spi_init_already_initialized(void)\n{\n // First call: should succeed\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n // Change config/state so we can check it doesn't get reset\n g_spi_config.mode = 2;\n g_spi_config.speed_hz = 4000000;\n\n // Second call: should fail\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_ALREADY_INITIALIZED, spi_init());\n\n // State unchanged\n TEST_ASSERT_EQUAL_INT(SPI_STATE_INITIALIZED, test_spi_get_state());\n spi_config_t cfg = test_spi_get_config();\n TEST_ASSERT_EQUAL_UINT8(2, cfg.mode);\n TEST_ASSERT_EQUAL_UINT32(4000000, cfg.speed_hz);\n}\n\n// ==============================\n// 2. spi_set_config\n// ==============================\n\nvoid test_spi_set_config_success_all_modes_speeds(void)\n{\n for (size_t i = 0; i < sizeof(valid_modes)/sizeof(valid_modes[0]); ++i) {\n for (size_t j = 0; j < sizeof(valid_speeds)/sizeof(valid_speeds[0]); ++j) {\n setUp();\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n\n spi_config_t user_cfg;\n user_cfg.mode = valid_modes[i];\n user_cfg.speed_hz = valid_speeds[j];\n int ret = spi_set_config(&user_cfg);\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, ret);\n\n // Confirm internal config\n spi_config_t actual = test_spi_get_config();\n TEST_ASSERT_EQUAL_UINT8(user_cfg.mode, actual.mode);\n TEST_ASSERT_EQUAL_UINT32(user_cfg.speed_hz, actual.speed_hz);\n }\n }\n}\n\nvoid test_spi_set_config_error_not_initialized(void)\n{\n spi_config_t cfg = { .mode = 0, .speed_hz = 1000000 };\n int ret = spi_set_config(&cfg);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_NOT_INITIALIZED, ret);\n}\n\nvoid test_spi_set_config_error_null_pointer(void)\n{\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n int ret = spi_set_config(NULL);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_NULL_POINTER, ret);\n}\n\nvoid test_spi_set_config_error_invalid_mode(void)\n{\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n\n spi_config_t cfg = { .mode = 4, .speed_hz = 1000000 }; // mode > 3\n int ret = spi_set_config(&cfg);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_INVALID_ARG, ret);\n}\n\nvoid test_spi_set_config_error_invalid_speed(void)\n{\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n\n spi_config_t cfg = { .mode = 1, .speed_hz = 500000 }; // unsupported speed\n int ret = spi_set_config(&cfg);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_INVALID_ARG, ret);\n}\n\n// ==============================\n// 3. spi_transfer\n// ==============================\n\nvoid test_spi_transfer_success_normal_operation(void)\n{\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n\n // Populate tx buffer, clear rx buffer\n for(uint8_t i=0; i < 16; ++i) tx_test_buffer[i] = 0x11 + i;\n memset(rx_test_buffer, 0, 16);\n\n int ret = spi_transfer(tx_test_buffer, rx_test_buffer, 16);\n\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, ret);\n\n // Verify transfer - rx should match tx\n for(uint8_t i=0; i < 16; ++i)\n TEST_ASSERT_EQUAL_UINT8(tx_test_buffer[i], rx_test_buffer[i]);\n\n // State transitions: at end should be INITIALIZED\n TEST_ASSERT_EQUAL_INT(SPI_STATE_INITIALIZED, test_spi_get_state());\n}\n\nvoid test_spi_transfer_transmit_only_rxbuffer_null(void)\n{\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n\n // tx_buffer non-null, rx_buffer NULL\n for(uint8_t i=0; i < 10; ++i) tx_test_buffer[i] = 0xDE + i;\n\n int ret = spi_transfer(tx_test_buffer, NULL, 10);\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, ret);\n // No crash\n TEST_ASSERT_EQUAL_INT(SPI_STATE_INITIALIZED, test_spi_get_state());\n}\n\nvoid test_spi_transfer_receive_only_txbuffer_null(void)\n{\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n\n // rx_buffer non-null, tx_buffer NULL: rx should be filled with 0xFF\n memset(rx_test_buffer, 0, 10);\n int ret = spi_transfer(NULL, rx_test_buffer, 10);\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, ret);\n\n for(int i=0;i<10;++i)\n TEST_ASSERT_EQUAL_UINT8(0xFF, rx_test_buffer[i]);\n TEST_ASSERT_EQUAL_INT(SPI_STATE_INITIALIZED, test_spi_get_state());\n}\n\nvoid test_spi_transfer_error_not_initialized(void)\n{\n int ret = spi_transfer(tx_test_buffer, rx_test_buffer, 5);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_NOT_INITIALIZED, ret);\n}\n\nvoid test_spi_transfer_error_both_buffers_null(void)\n{\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n int ret = spi_transfer(NULL, NULL, 5);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_INVALID_ARG, ret);\n}\n\nvoid test_spi_transfer_error_zero_length(void)\n{\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n int ret = spi_transfer(tx_test_buffer, rx_test_buffer, 0);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_INVALID_LENGTH, ret);\n}\n\nvoid test_spi_transfer_error_exceed_max_length(void)\n{\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n int ret = spi_transfer(tx_test_buffer, rx_test_buffer, 2049); // max: 2048\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_INVALID_LENGTH, ret);\n}\n\n// ==============================\n// 4. Edge & State Cases\n// ==============================\n\nvoid test_spi_transfer_multiple_sequential(void)\n{\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n\n for(int t=0; t < 3; ++t) {\n for(uint8_t i=0; i<8; ++i) tx_test_buffer[i] = t*10 + i;\n memset(rx_test_buffer, 0x00, 8);\n\n int ret = spi_transfer(tx_test_buffer, rx_test_buffer, 8);\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, ret);\n\n // RX should match TX\n for(int i=0; i<8; ++i)\n TEST_ASSERT_EQUAL_UINT8(tx_test_buffer[i], rx_test_buffer[i]);\n\n // State resets to INITIALIZED\n TEST_ASSERT_EQUAL_INT(SPI_STATE_INITIALIZED, test_spi_get_state());\n }\n}\n\nvoid test_spi_concurrent_operations_while_busy(void)\n{\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n\n // Simulate busy state\n g_spi_state = SPI_STATE_BUSY;\n\n // Try config change\n spi_config_t cfg = { .mode = 2, .speed_hz = 4000000 };\n int cret = spi_set_config(&cfg);\n // Since code allows config set only in INITIALIZED, should still reject as NOT_INITIALIZED (here, not a special BUSY error)\n // In the code, it only checks for UNINITIALIZED, so this will allow a config set even if BUSY.\n // If BUSY is strictly protected, code would need updating. Here BUSY is not guarded, so will succeed,\n // so for the actual code, we need to check what happens.\n // We'll check that config is updated when state is BUSY (document this as a gap in requirements vs. code)\n int expected = SPI_SUCCESS;\n TEST_ASSERT_EQUAL_INT(expected, cret);\n\n // Try re-initialization while BUSY\n int iret = spi_init();\n // Since only UNINITIALIZED is allowed, in BUSY this will give ERROR_ALREADY_INITIALIZED\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_ALREADY_INITIALIZED, iret);\n\n // Reset state to INITIALIZED for other tests\n g_spi_state = SPI_STATE_INITIALIZED;\n}\n\n// ==============================\n// 5. Code Coverage of test helpers\n// ==============================\n\nvoid test_test_helpers_get_state_and_config(void)\n{\n // state\n g_spi_state = SPI_STATE_BUSY;\n TEST_ASSERT_EQUAL_INT(SPI_STATE_BUSY, test_spi_get_state());\n\n // config\n g_spi_config.mode = 1;\n g_spi_config.speed_hz = 8000000;\n spi_config_t cfg = test_spi_get_config();\n TEST_ASSERT_EQUAL_UINT8(1, cfg.mode);\n TEST_ASSERT_EQUAL_UINT32(8000000, cfg.speed_hz);\n}\n\n// ==============================\n// Test Runner\n// ==============================\n\nint main(void)\n{\n UNITY_BEGIN();\n\n // 1. spi_init\n RUN_TEST(test_spi_init_success);\n RUN_TEST(test_spi_init_already_initialized);\n\n // 2. spi_set_config\n RUN_TEST(test_spi_set_config_success_all_modes_speeds);\n RUN_TEST(test_spi_set_config_error_not_initialized);\n RUN_TEST(test_spi_set_config_error_null_pointer);\n RUN_TEST(test_spi_set_config_error_invalid_mode);\n RUN_TEST(test_spi_set_config_error_invalid_speed);\n\n // 3. spi_transfer\n RUN_TEST(test_spi_transfer_success_normal_operation);\n RUN_TEST(test_spi_transfer_transmit_only_rxbuffer_null);\n RUN_TEST(test_spi_transfer_receive_only_txbuffer_null);\n RUN_TEST(test_spi_transfer_error_not_initialized);\n RUN_TEST(test_spi_transfer_error_both_buffers_null);\n RUN_TEST(test_spi_transfer_error_zero_length);\n RUN_TEST(test_spi_transfer_error_exceed_max_length);\n\n // 4. Edge & State\n RUN_TEST(test_spi_transfer_multiple_sequential);\n RUN_TEST(test_spi_concurrent_operations_while_busy);\n\n // 5. Test-only helpers\n RUN_TEST(test_test_helpers_get_state_and_config);\n\n return UNITY_END();\n}\n```",
"\n You are an expert C unit testing engineer. Your task is to write a complete C test file that implements the following approved test plan for the source code in `spi.c`.\n\n **Implement this EXACT test plan:**\n # SPI Driver Test Plan\n\nThis document outlines the test plan for the SPI driver implemented in `spi.c`. Each function is broken down into specific test cases based on provided functional requirements, error handling, and the source code.\n\n---\n\n## 1. `spi_init`\n\n### Test Cases\n\n- **[Success] Fresh Initialization**\n - Verify that calling `spi_init` when the driver is uninitialized returns `SPI_SUCCESS`, sets state to `SPI_STATE_INITIALIZED`, configures `mode=0` and `speed_hz=1000000`.\n- **[Error] Double Initialization**\n - Verify that calling `spi_init` when the driver is already initialized returns `SPI_ERROR_ALREADY_INITIALIZED` and does not re-configure hardware/config structs.\n- **[Edge] Repeated Calls**\n - Call `spi_init` multiple times and ensure subsequent calls always return `SPI_ERROR_ALREADY_INITIALIZED`, configuration is unchanged.\n\n---\n\n## 2. `spi_set_config`\n\n### Test Cases\n\n- **[Success] Standard Configuration**\n - After successful initialization, provide a valid `spi_config_t` struct (`mode=1`, `speed_hz=4000000`) and verify `SPI_SUCCESS` is returned and internal config matches input.\n- **[Error] Not Initialized**\n - Call `spi_set_config` before calling `spi_init`; expect `SPI_ERROR_NOT_INITIALIZED`.\n- **[Error] Null Pointer**\n - Call `spi_set_config` with `config` as `NULL`; expect `SPI_ERROR_NULL_POINTER`.\n- **[Error] Invalid Mode (Too High)**\n - Provide `mode=4` (out of valid range); expect `SPI_ERROR_INVALID_ARG`.\n- **[Error] Invalid Mode (Negative, if supported by type)**\n - If `mode` can be negative (e.g., due to cast or struct manipulation), provide `mode=-1`; expect `SPI_ERROR_INVALID_ARG`.\n- **[Error] Invalid Speed (Not Allowed Value)**\n - Provide `speed_hz=2000000` (not in allowed set); expect `SPI_ERROR_INVALID_ARG`.\n- **[Error] Invalid Speed (Zero)**\n - Provide `speed_hz=0`; expect `SPI_ERROR_INVALID_ARG`.\n- **[Edge] Lowest and Highest Supported Speeds**\n - Test with `speed_hz=1000000` and `8000000` for all `mode` values 0–3; expect success.\n- **[Edge] Multiple Configurations**\n - Change configuration several times after initialization with valid values; ensure config is updated appropriately each time.\n\n---\n\n## 3. `spi_transfer`\n\n### Test Cases\n\n- **[Success] Full-Duplex (Transmit and Receive)**\n - Provide valid, initialized state; both `tx_buffer` and `rx_buffer` are non-NULL, `len` between 1 and 2048. Verify output matches expected behavior.\n- **[Success] Transmit Only**\n - Provide valid, initialized state; `tx_buffer` valid, `rx_buffer` NULL, valid `len`. Ensure no faults, data \"sent,\" received data is discarded.\n- **[Success] Receive Only**\n - Provide valid, initialized state; `tx_buffer` NULL, `rx_buffer` valid, valid `len`. Driver should transmit `0xFF` for all bytes, and store received data (should be `0xFF` per this implementation).\n- **[Edge] Minimum Length**\n - Transfer with `len=1`, ensure logic works for smallest valid transfer.\n- **[Edge] Maximum Length**\n - Transfer with `len=2048`, ensure boundary is accepted without error.\n- **[Error] Not Initialized**\n - Call `spi_transfer` before `spi_init`; expect `SPI_ERROR_NOT_INITIALIZED`.\n- **[Error] Both Buffers Null**\n - Call `spi_transfer` with both `tx_buffer` and `rx_buffer` NULL; expect `SPI_ERROR_INVALID_ARG`.\n- **[Error] Length Zero**\n - Call with either/both buffers non-NULL, `len=0`; expect `SPI_ERROR_INVALID_LENGTH`.\n- **[Error] Length Exceeds Maximum**\n - Call with `len=2049` and valid buffers; expect `SPI_ERROR_INVALID_LENGTH`.\n- **[Edge] Busy State Restored**\n - Start transfer; ensure driver state is set to `SPI_STATE_BUSY` during the operation and restored to `SPI_STATE_INITIALIZED` afterward, even on edge cases.\n- **[Edge] No Buffer Overrun**\n - Confirm that only exactly `len` bytes are written to `rx_buffer` and no out-of-bounds access occurs.\n\n---\n\n## 4. State and Configuration Helpers (Test-Only)\n\n- **[Support] `test_spi_get_state`**\n - Use after key steps to verify internal state matches expectation (e.g., after `spi_init`, `spi_transfer`).\n- **[Support] `test_spi_get_config`**\n - Use after `spi_init` and `spi_set_config` to verify the config values are set as prescribed.\n\n---\n\n# Summary Table\n\n| Function | Test Scenario | Expected Result |\n|------------------|---------------------------------------------|--------------------------------------|\n| spi_init | Fresh initialization | Success, initialized, defaults set |\n| spi_init | Already initialized | Error: ALREADY_INITIALIZED |\n| spi_set_config | Valid config (1, 4MHz) after init | Success, config set |\n| spi_set_config | Not initialized | Error: NOT_INITIALIZED |\n| spi_set_config | Config is NULL | Error: NULL_POINTER |\n| spi_set_config | Invalid mode (4, -1) | Error: INVALID_ARG |\n| spi_set_config | Invalid speed (2000000, 0) | Error: INVALID_ARG |\n| spi_transfer | Valid transmit/receive | Success, data exchanged |\n| spi_transfer | Only tx, only rx | Success, correct default behavior |\n| spi_transfer | Not initialized | Error: NOT_INITIALIZED |\n| spi_transfer | Both buffers NULL | Error: INVALID_ARG |\n| spi_transfer | len = 0 | Error: INVALID_LENGTH |\n| spi_transfer | len > 2048 | Error: INVALID_LENGTH |\n| spi_transfer | len = 1, 2048 | Success, boundary cases |\n| Helpers | State/config validation | Matches expected after each call |\n\n---\n\n**Note:** All test cases will check both return codes and internal state/config using test-only helper functions as appropriate. Boundary, error, and normal operating conditions are all exercised.\n\n **Base the tests on this source code:**\n ```c\n #include \"spi.h\"\n#include <stdbool.h>\n\n#ifdef TEST\nspi_state_t g_spi_state = SPI_STATE_UNINITIALIZED;\nspi_config_t g_spi_config;\n#else\nstatic spi_state_t g_spi_state = SPI_STATE_UNINITIALIZED;\nstatic spi_config_t g_spi_config;\n#endif\n// --- END OF FIX ---\n\n\nstatic bool is_valid_speed(uint32_t speed) {\n return (speed == 1000000 || speed == 4000000 || speed == 8000000);\n}\n\nint spi_init(void) {\n if (g_spi_state != SPI_STATE_UNINITIALIZED) {\n return SPI_ERROR_ALREADY_INITIALIZED;\n }\n g_spi_config.mode = 0;\n g_spi_config.speed_hz = 1000000;\n g_spi_state = SPI_STATE_INITIALIZED;\n return SPI_SUCCESS;\n}\n\nint spi_set_config(const spi_config_t* config) {\n if (g_spi_state == SPI_STATE_UNINITIALIZED) {\n return SPI_ERROR_NOT_INITIALIZED;\n }\n if (config == NULL) {\n return SPI_ERROR_NULL_POINTER;\n }\n if (config->mode > 3) {\n return SPI_ERROR_INVALID_ARG;\n }\n if (!is_valid_speed(config->speed_hz)) {\n return SPI_ERROR_INVALID_ARG;\n }\n g_spi_config = *config;\n return SPI_SUCCESS;\n}\n\nint spi_transfer(const uint8_t* tx_buffer, uint8_t* rx_buffer, uint16_t len) {\n if (g_spi_state == SPI_STATE_UNINITIALIZED) {\n return SPI_ERROR_NOT_INITIALIZED;\n }\n if (tx_buffer == NULL && rx_buffer == NULL) {\n return SPI_ERROR_INVALID_ARG;\n }\n if (len == 0 || len > 2048) {\n return SPI_ERROR_INVALID_LENGTH;\n }\n g_spi_state = SPI_STATE_BUSY;\n for (uint16_t i = 0; i < len; ++i) {\n uint8_t tx_byte = (tx_buffer) ? tx_buffer[i] : 0xFF;\n uint8_t rx_byte = tx_byte;\n if (rx_buffer) {\n rx_buffer[i] = rx_byte;\n }\n }\n g_spi_state = SPI_STATE_INITIALIZED;\n return SPI_SUCCESS;\n}\n\n// --- Test-only helper implementations ---\n#ifdef TEST\nspi_state_t test_spi_get_state(void) {\n return g_spi_state;\n}\nspi_config_t test_spi_get_config(void) {\n return g_spi_config;\n}\n#endif\n ```\n \n **CRITICAL INSTRUCTIONS:**\n 1. Write a complete C file containing Unity tests. The code must be complete and syntactically correct.\n 2. Include the necessary headers: `#include \"unity.h\"`, `#include \"spi.h\"`.\n 3. **To access the internal state for testing, you MUST declare the global variables from `spi.c` as `extern`. Add these lines at the top of the test file:**\n ```c\n extern spi_state_t g_spi_state;\n extern spi_config_t g_spi_config;\n ```\n 4. Implement the `setUp()` function to reset the state before each test.\n ": "```c\n#define TEST\n#include \"unity.h\"\n#include \"spi.h\"\n#include <string.h>\n#include <stdint.h>\n\n/* --- Expose internal state/config for testing as required by instructions --- */\nextern spi_state_t g_spi_state;\nextern spi_config_t g_spi_config;\n\n/* --- Test-only helpers from spi.c header (implemented only under TEST) --- */\nspi_state_t test_spi_get_state(void);\nspi_config_t test_spi_get_config(void);\n\n/* --- setUp(): Reset global SPI state/config before each test --- */\nvoid setUp(void) {\n g_spi_state = SPI_STATE_UNINITIALIZED;\n g_spi_config.mode = 0xAA; // Garbage value to catch missing init\n g_spi_config.speed_hz = 0xFFFFFFFF;\n}\n\n/* --- tearDown: not used --- */\nvoid tearDown(void) {}\n\n/* -------- spi_init tests -------- */\nvoid test_spi_init_fresh_initialization(void) {\n int ret = spi_init();\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, ret);\n spi_state_t state = test_spi_get_state();\n TEST_ASSERT_EQUAL_INT(SPI_STATE_INITIALIZED, state);\n spi_config_t cfg = test_spi_get_config();\n TEST_ASSERT_EQUAL_UINT8(0, cfg.mode);\n TEST_ASSERT_EQUAL_UINT32(1000000, cfg.speed_hz);\n}\n\nvoid test_spi_init_double_initialization(void) {\n int ret1 = spi_init();\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, ret1);\n g_spi_config.mode = 2;\n g_spi_config.speed_hz = 8000000;\n int ret2 = spi_init();\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_ALREADY_INITIALIZED, ret2);\n spi_state_t state = test_spi_get_state();\n TEST_ASSERT_EQUAL_INT(SPI_STATE_INITIALIZED, state);\n // Check that config is not overwritten to defaults\n spi_config_t cfg = test_spi_get_config();\n TEST_ASSERT_EQUAL_UINT8(2, cfg.mode);\n TEST_ASSERT_EQUAL_UINT32(8000000, cfg.speed_hz);\n}\n\nvoid test_spi_init_repeated_calls(void) {\n int i;\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n g_spi_config.mode = 1;\n g_spi_config.speed_hz = 4000000;\n for (i = 0; i < 5; ++i) {\n int ret = spi_init();\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_ALREADY_INITIALIZED, ret);\n spi_config_t cfg = test_spi_get_config();\n TEST_ASSERT_EQUAL_UINT8(1, cfg.mode);\n TEST_ASSERT_EQUAL_UINT32(4000000, cfg.speed_hz);\n }\n}\n\n/* -------- spi_set_config tests -------- */\nvoid test_spi_set_config_standard_configuration(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n spi_config_t cfg = {1, 4000000};\n int ret = spi_set_config(&cfg);\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, ret);\n spi_config_t current = test_spi_get_config();\n TEST_ASSERT_EQUAL_UINT8(1, current.mode);\n TEST_ASSERT_EQUAL_UINT32(4000000, current.speed_hz);\n}\n\nvoid test_spi_set_config_not_initialized(void) {\n spi_config_t cfg = {2, 8000000};\n int ret = spi_set_config(&cfg);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_NOT_INITIALIZED, ret);\n}\n\nvoid test_spi_set_config_null_pointer(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n int ret = spi_set_config(NULL);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_NULL_POINTER, ret);\n}\n\nvoid test_spi_set_config_invalid_mode_too_high(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n spi_config_t cfg = {4, 1000000};\n int ret = spi_set_config(&cfg);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_INVALID_ARG, ret);\n}\n\nvoid test_spi_set_config_invalid_mode_negative(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n spi_config_t cfg;\n memset(&cfg, 0, sizeof(cfg));\n cfg.mode = (uint8_t)-1;\n cfg.speed_hz = 1000000;\n int ret = spi_set_config(&cfg);\n // Only fail if mode > 3, but casting -1 to uint8_t is 255, so must fail\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_INVALID_ARG, ret);\n}\n\nvoid test_spi_set_config_invalid_speed_not_allowed(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n spi_config_t cfg = {2, 2000000};\n int ret = spi_set_config(&cfg);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_INVALID_ARG, ret);\n}\n\nvoid test_spi_set_config_invalid_speed_zero(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n spi_config_t cfg = {0, 0};\n int ret = spi_set_config(&cfg);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_INVALID_ARG, ret);\n}\n\nvoid test_spi_set_config_lowest_and_highest_speeds_mode_0_to_3(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n uint32_t speeds[2] = {1000000, 8000000};\n uint8_t m;\n for (m = 0; m <= 3; ++m) {\n size_t j;\n for (j = 0; j < 2; ++j) {\n spi_config_t cfg = {m, speeds[j]};\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_set_config(&cfg));\n spi_config_t cur = test_spi_get_config();\n TEST_ASSERT_EQUAL_UINT8(m, cur.mode);\n TEST_ASSERT_EQUAL_UINT32(speeds[j], cur.speed_hz);\n }\n }\n}\n\nvoid test_spi_set_config_multiple_configurations(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n\n spi_config_t cfg1 = {3, 8000000};\n spi_config_t cfg2 = {2, 4000000};\n spi_config_t cfg3 = {1, 1000000};\n\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_set_config(&cfg1));\n spi_config_t c1 = test_spi_get_config();\n TEST_ASSERT_EQUAL_UINT8(3, c1.mode);\n TEST_ASSERT_EQUAL_UINT32(8000000, c1.speed_hz);\n\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_set_config(&cfg2));\n spi_config_t c2 = test_spi_get_config();\n TEST_ASSERT_EQUAL_UINT8(2, c2.mode);\n TEST_ASSERT_EQUAL_UINT32(4000000, c2.speed_hz);\n\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_set_config(&cfg3));\n spi_config_t c3 = test_spi_get_config();\n TEST_ASSERT_EQUAL_UINT8(1, c3.mode);\n TEST_ASSERT_EQUAL_UINT32(1000000, c3.speed_hz);\n}\n\n/* -------- spi_transfer tests -------- */\nvoid test_spi_transfer_full_duplex(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n uint8_t tx[8], rx[8];\n for (size_t i = 0; i < 8; ++i) tx[i] = (uint8_t)(0xA0 + i), rx[i]=0;\n int ret = spi_transfer(tx, rx, 8);\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, ret);\n spi_state_t state = test_spi_get_state();\n TEST_ASSERT_EQUAL_INT(SPI_STATE_INITIALIZED, state);\n for (size_t i = 0; i < 8; ++i) {\n TEST_ASSERT_EQUAL_UINT8(tx[i], rx[i]);\n }\n}\n\nvoid test_spi_transfer_transmit_only(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n uint8_t tx[4] = {1,2,3,4};\n int ret = spi_transfer(tx, NULL, 4);\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, ret);\n // rx not checked\n spi_state_t state = test_spi_get_state();\n TEST_ASSERT_EQUAL_INT(SPI_STATE_INITIALIZED, state);\n}\n\nvoid test_spi_transfer_receive_only(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n uint8_t rx[6];\n memset(rx, 0, sizeof(rx));\n int ret = spi_transfer(NULL, rx, 6);\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, ret);\n spi_state_t state = test_spi_get_state();\n TEST_ASSERT_EQUAL_INT(SPI_STATE_INITIALIZED, state);\n for (size_t i = 0; i < 6; ++i) {\n TEST_ASSERT_EQUAL_UINT8(0xFF, rx[i]);\n }\n}\n\nvoid test_spi_transfer_minimum_length(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n uint8_t tx = 0x55, rx = 0;\n int ret = spi_transfer(&tx, &rx, 1);\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, ret);\n TEST_ASSERT_EQUAL_UINT8(0x55, rx);\n}\n\nvoid test_spi_transfer_maximum_length(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n uint8_t tx[2048], rx[2048];\n for (size_t i = 0; i < 2048; ++i) tx[i]=i&0xFF, rx[i]=0;\n int ret = spi_transfer(tx, rx, 2048);\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, ret);\n spi_state_t state = test_spi_get_state();\n TEST_ASSERT_EQUAL_INT(SPI_STATE_INITIALIZED, state);\n for (size_t i = 0; i < 2048; ++i) {\n TEST_ASSERT_EQUAL_UINT8(tx[i], rx[i]);\n }\n}\n\nvoid test_spi_transfer_not_initialized(void) {\n uint8_t tx = 0x23, rx = 0;\n int ret = spi_transfer(&tx, &rx, 1);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_NOT_INITIALIZED, ret);\n}\n\nvoid test_spi_transfer_both_buffers_null(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n int ret = spi_transfer(NULL, NULL, 10);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_INVALID_ARG, ret);\n}\n\nvoid test_spi_transfer_length_zero(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n uint8_t tx = 0x55, rx = 0;\n int ret = spi_transfer(&tx, &rx, 0);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_INVALID_LENGTH, ret);\n\n ret = spi_transfer(&tx, NULL, 0);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_INVALID_LENGTH, ret);\n\n ret = spi_transfer(NULL, &rx, 0);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_INVALID_LENGTH, ret);\n}\n\nvoid test_spi_transfer_length_exceeds_max(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n uint8_t tx[2049], rx[2049];\n memset(tx, 0xAA, sizeof(tx));\n memset(rx, 0x55, sizeof(rx));\n int ret = spi_transfer(tx, rx, 2049);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_INVALID_LENGTH, ret);\n}\n\nvoid test_spi_transfer_busy_state_restored(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n uint8_t tx[2] = {1, 2};\n uint8_t rx[2] = {0, 0};\n // Set an invalid length, make sure state remains initialized\n int ret = spi_transfer(tx, rx, 0);\n TEST_ASSERT_EQUAL_INT(SPI_ERROR_INVALID_LENGTH, ret);\n TEST_ASSERT_EQUAL_INT(SPI_STATE_INITIALIZED, test_spi_get_state());\n\n // Now with valid transfer: during spi_transfer, state is BUSY, but after, should be INITIALIZED\n // The function does not provide a callback, but we can check before/after\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_transfer(tx, rx, 2));\n TEST_ASSERT_EQUAL_INT(SPI_STATE_INITIALIZED, test_spi_get_state());\n}\n\nvoid test_spi_transfer_no_buffer_overrun(void) {\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n uint8_t rx[8], canary[2]={0xCC,0xCC};\n memset(rx, 0, sizeof(rx));\n uint8_t tx[8];\n for (size_t i=0;i<8;++i) tx[i]=i*2;\n\n // Setup canaries after the output buffer to detect overwrite\n uint8_t* overrun_area = (uint8_t*)(&rx[8]);\n memcpy(overrun_area, canary, sizeof(canary));\n\n int ret = spi_transfer(tx, rx, 8);\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, ret);\n for (size_t i=0;i<8;++i) TEST_ASSERT_EQUAL_UINT8(tx[i], rx[i]);\n // Check canaries unchanged\n TEST_ASSERT_EQUAL_UINT8(0xCC, overrun_area[0]);\n TEST_ASSERT_EQUAL_UINT8(0xCC, overrun_area[1]);\n}\n\n/* -------- Helpers tests -------- */\nvoid test_helpers_state_and_config(void) {\n TEST_ASSERT_EQUAL_INT(SPI_STATE_UNINITIALIZED, test_spi_get_state());\n TEST_ASSERT_EQUAL_UINT8(0xAA, test_spi_get_config().mode);\n TEST_ASSERT_EQUAL_UINT32(0xFFFFFFFF, test_spi_get_config().speed_hz);\n\n TEST_ASSERT_EQUAL_INT(SPI_SUCCESS, spi_init());\n TEST_ASSERT_EQUAL_INT(SPI_STATE_INITIALIZED, test_spi_get_state());\n spi_config_t cfg = test_spi_get_config();\n TEST_ASSERT_EQUAL_UINT8(0, cfg.mode);\n TEST_ASSERT_EQUAL_UINT32(1000000, cfg.speed_hz);\n}\n\n/* ---- Unity test declaration ---- */\nint main(void) {\n UNITY_BEGIN();\n\n /* spi_init */\n RUN_TEST(test_spi_init_fresh_initialization);\n RUN_TEST(test_spi_init_double_initialization);\n RUN_TEST(test_spi_init_repeated_calls);\n\n /* spi_set_config */\n RUN_TEST(test_spi_set_config_standard_configuration);\n RUN_TEST(test_spi_set_config_not_initialized);\n RUN_TEST(test_spi_set_config_null_pointer);\n RUN_TEST(test_spi_set_config_invalid_mode_too_high);\n RUN_TEST(test_spi_set_config_invalid_mode_negative);\n RUN_TEST(test_spi_set_config_invalid_speed_not_allowed);\n RUN_TEST(test_spi_set_config_invalid_speed_zero);\n RUN_TEST(test_spi_set_config_lowest_and_highest_speeds_mode_0_to_3);\n RUN_TEST(test_spi_set_config_multiple_configurations);\n\n /* spi_transfer */\n RUN_TEST(test_spi_transfer_full_duplex);\n RUN_TEST(test_spi_transfer_transmit_only);\n RUN_TEST(test_spi_transfer_receive_only);\n RUN_TEST(test_spi_transfer_minimum_length);\n RUN_TEST(test_spi_transfer_maximum_length);\n RUN_TEST(test_spi_transfer_not_initialized);\n RUN_TEST(test_spi_transfer_both_buffers_null);\n RUN_TEST(test_spi_transfer_length_zero);\n RUN_TEST(test_spi_transfer_length_exceeds_max);\n RUN_TEST(test_spi_transfer_busy_state_restored);\n RUN_TEST(test_spi_transfer_no_buffer_overrun);\n\n /* Helpers */\n RUN_TEST(test_helpers_state_and_config);\n\n return UNITY_END();\n}\n```"
}