Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions .copilot/unit_test_agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Unit Test Generation Agent
This agent scans C/C++ header and source files, extracts the public API, analyzes implementation behavior, and generates high‑quality unit tests using Catch2 and fff (Fake Function Framework).

## Goals
- Identify all public API functions exposed in header files.
- Understand expected behavior by scanning corresponding source files.
- Generate Catch2-based unit tests for each API.
- Using BDD (behavior driven development) method from Catch2 to develop test cases
- Clear documentation (code comment) to explain what the test cases and asserts do.
- Use fff to mock external dependencies.
- Cover input/output validation, happy path, and fail path for each API.

## Scope
Allowed:
- Read and analyze all header (.h/.hpp) and source (.c/.cpp) files.
- Create new test files or update existing ones.
- Introduce fff (Fake Function Framework) mocks and stubs.
- Add helper test utilities if needed.

Not allowed:
- Modify production code unless explicitly instructed.
- Change API signatures.
- Introduce new external dependencies beyond Catch2 + fff.

## Required Inputs
- Path to the module or folder to test.
- Optional: specific API names to focus on.

## Test File Location Requirements
- All generated test files **must be placed inside**:

`workspace/tests/<module_name>/`

- The agent must:
- `<module_name>` must reflects the folder structure in `inc` folder
- Create the folder if it does not exist.
- Mirror the module structure when appropriate.
- Follow project naming conventions:
- test file: `unittest_<module>.cpp`
- mock file: `mocks_<module>.cpp`

## Tools
- File search and reading.
- File creation and editing.
- Test runner (e.g., `ctest`, `make test`, or project-specific command).
- Static analysis of function signatures and call graphs.

## Workflow

1. **Scan Headers**
- Parse all header files in the target module.
- Extract all public API functions:
- function name
- parameters (types, names)
- return type
- documentation comments (if present)

2. **Analyze Source Files**
- Locate each API’s implementation.
- Identify:
- control flow
- error conditions
- boundary checks
- dependencies (functions, modules, globals)
- Build a behavioral summary for each API.

3. **Prepare Test Structure**
- Create a test file per module or per API group.
- Include Catch2 headers.
- Include fff and define mocks for all external dependencies.

4. **Generate Test Cases**
For each API, generate:
- **Input validation tests**
- null pointers
- invalid ranges
- boundary values
- **Happy path tests**
- typical valid inputs
- expected outputs
- expected side effects
- **Fail path tests**
- forced dependency failures (via fff)
- error return codes
- exceptional conditions

5. **Mocking Setup**
- Identify all external calls inside the API.
- Create fff (Fake Function Framework) fakes for each dependency.
- Reset fakes before each test.

6. **Verification**
- Run the test suite.
- If tests fail:
- Fix test logic first.
- Only modify production code if failure indicates a real bug.

7. **Completion**
- Re-run tests until all pass.
- Output:
- list of created/updated test files
- summary of coverage gaps
- suggestions for additional tests
- short summary of the test cases: what have been tested.

## Rules
- Use Catch2 `TEST_CASE` and `SECTION` for structure.
- Use fff for all external dependencies.
- Keep tests deterministic and isolated.
- Prefer table-driven tests when multiple input/output pairs exist.
- Do not mock the API under test — only its dependencies.
- Follow project naming conventions:
- test file: `unittest_<module>.cpp`
- mock file: `mocks_<module>.cpp`

## Output Format
At the end, output:

- "Summary:"
- List of created/updated test files
- Any warnings or TODOs
- Coverage notes

## Failure Handling
- If API behavior is unclear, ask the user for clarification.
- If dependencies cannot be mocked, request guidance.
- If the module lacks testable entry points, stop and report.
6 changes: 5 additions & 1 deletion .github/workflows/document_build.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: Deploy Sphinx documentation to Pages

on: [push, workflow_dispatch]
on:
pull_request:
branches: [ "**" ]
push:
branches: [ "main" ]

permissions:
contents: write
Expand Down
81 changes: 31 additions & 50 deletions inc/hal/ez_driver_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,28 +73,31 @@ typedef enum
typedef void (*ezDrvCallback)(uint8_t event_code, void *param1, void *param2);


typedef void (*ezDrvOnReceiveEventCallback)(
void *driver_h,
uint8_t event_code,
void *param1,
void *param2);


/** @brief Define a driver instance.
*/
struct ezDrvInstance
typedef struct ezDrvInstance
{
ezDrvCallback calback; /**< Callback funtion to handle the event from the HW driver */
ezDrvCallback callback; /**< Callback funtion to handle the event from the HW driver */
void *driver; /**< Pointer to the HAL driver, depending on the implmentation */
};


/** @brief Define a driver instance type.
*/
typedef struct ezDrvInstance ezDrvInstance_t;
}ezDrvInstance_t;


/** @brief Define structure holding common data of a driver
*/
struct ezDriverCommon
typedef struct ezDriverCommon
{
const char* name; /* Name of the driver instance */
uint8_t version[3]; /* Version number including major, minor, patch */
ezDrvInstance_t *curr_inst; /* Point to the current instance using the driver. NULL means the driver is available. */
};
const char* name; /* Name of the driver instance */
uint8_t version[3]; /* Version number including major, minor, patch */
ezDrvInstance_t *curr_inst; /* Point to the current instance using the driver. NULL means the driver is available. */
ezDrvOnReceiveEventCallback callback; /* Callback funtion to handle the event from the HW driver, point to the callback of the instance which is using the driver */
}ezDriver_t;


/*****************************************************************************
Expand Down Expand Up @@ -140,41 +143,6 @@ static inline void *ezDriver_GetDriverFromInstance(ezDrvInstance_t *inst)
}


/*****************************************************************************
* Function: ezDriver_IsDriverAvailable
*//**
* @brief Check if the driver is availabe and ready to be used
*
* @details Helper function used by other components. THe user are not
* supposed to used this function
*
* @param[in] inst: Driver instance
* @param[in] drv_common: Pointer to the common structure of the driver.
* @see ezDriverCommon
* @return true is the driver is available, else false
*
* @pre None
* @post None
*
* \b Example
* @code
* @endcode
*
* @see
*
*****************************************************************************/
static inline bool ezDriver_IsDriverAvailable(ezDrvInstance_t *inst,
struct ezDriverCommon *drv_common)
{
bool ret = false;
if(inst != NULL && drv_common != NULL)
{
ret = ((drv_common->curr_inst == NULL) || (drv_common->curr_inst == inst));
}
return ret;
}


/*****************************************************************************
* Function: ezDriver_LockDriver
*//**
Expand All @@ -194,13 +162,26 @@ static inline bool ezDriver_IsDriverAvailable(ezDrvInstance_t *inst,
* @see
*
*****************************************************************************/
static inline void ezDriver_LockDriver(ezDrvInstance_t *inst,
static inline bool ezDriver_LockDriver(ezDrvInstance_t *inst,
struct ezDriverCommon *drv_common)
{
if(inst != NULL && drv_common != NULL)
if(inst == NULL || drv_common == NULL)
{
return false;
}

if(drv_common->curr_inst == inst)
{
return true;
}

if(drv_common->curr_inst == NULL)
{
drv_common->curr_inst = inst;
return true;
}

return false;
}


Expand Down
20 changes: 9 additions & 11 deletions inc/hal/gpio/ez_gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ extern "C" {
/*****************************************************************************
* Component Typedefs
*****************************************************************************/
/** @brief Define Uart Driver Instance
*/
typedef struct ezDrvInstance ezGpioDrvInstance_t;


/** @brief GPIO mode */
typedef enum
{
Expand Down Expand Up @@ -101,26 +106,26 @@ typedef struct ezHwGpioConfig
* @param[in] config: configuration of the GPIO pin
* @return EZ_DRV_STATUS
*/
typedef EZ_DRV_STATUS (*ezHwGpio_Initialize)(uint16_t pin_index, ezHwGpioConfig_t *config);
typedef EZ_DRV_STATUS (*ezHwGpio_Initialize)(ezDriver_t *handle, uint16_t pin_index, ezHwGpioConfig_t *config);

/** @brief Read state of a pin
* @param[in] pin_index: index of the GPIO pin
* @return EZ_GPIO_PIN_LOW or EZ_GPIO_PIN_HIGH
*/
typedef EZ_GPIO_PIN_STATE(*ezHwGpio_ReadPin)(uint16_t pin_index);
typedef EZ_GPIO_PIN_STATE(*ezHwGpio_ReadPin)(ezDriver_t *handle, uint16_t pin_index);

/** @brief Write state of a pin
* @param[in] pin_index: index of the GPIO pin
* @param[in] state: state of the pin
* @return EZ_DRV_STATUS
*/
typedef EZ_DRV_STATUS(*ezHwGpio_WritePin)(uint16_t pin_index, EZ_GPIO_PIN_STATE state);
typedef EZ_DRV_STATUS(*ezHwGpio_WritePin)(ezDriver_t *handle, uint16_t pin_index, EZ_GPIO_PIN_STATE state);

/** @brief Toggle state of a pin
* @param[in] pin_index: index of the GPIO pin
* @return EZ_DRV_STATUS
*/
typedef EZ_DRV_STATUS(*ezHwGpio_TogglePin)(uint16_t pin_index);
typedef EZ_DRV_STATUS(*ezHwGpio_TogglePin)(ezDriver_t *handle, uint16_t pin_index);


/** @brief GPIO driver interface
Expand All @@ -143,13 +148,6 @@ struct ezGpioDriver
bool initialized; /* Flag to check if the driver is initialized */
};

/** @brief Define Uart Driver Instance
*/
typedef struct{
struct ezDrvInstance drv_instance; /**< Driver instance */
} ezGpioDrvInstance_t;


/*****************************************************************************
* Component Variable Definitions
*****************************************************************************/
Expand Down
17 changes: 7 additions & 10 deletions inc/hal/i2c/ez_i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,40 +85,39 @@ typedef struct
} ezI2cConfig_t;


typedef EZ_DRV_STATUS (*ezHwI2c_Initialize)(void *driver_h, ezI2cConfig_t *config);
typedef EZ_DRV_STATUS (*ezHwI2c_TransmitSync)(void *driver_h,
typedef EZ_DRV_STATUS (*ezHwI2c_Initialize)(ezDriver_t *driver_h, ezI2cConfig_t *config);
typedef EZ_DRV_STATUS (*ezHwI2c_TransmitSync)(ezDriver_t *driver_h,
uint16_t address,
const uint8_t *data,
size_t length,
bool send_stop,
uint32_t timeout_millis);

typedef EZ_DRV_STATUS (*ezHwI2c_TransmitAsync)(void *driver_h,
typedef EZ_DRV_STATUS (*ezHwI2c_TransmitAsync)(ezDriver_t *driver_h,
uint16_t address,
const uint8_t *data,
size_t length,
bool send_stop);

typedef EZ_DRV_STATUS (*ezHwI2c_ReceiveSync)(void *driver_h,
typedef EZ_DRV_STATUS (*ezHwI2c_ReceiveSync)(ezDriver_t *driver_h,
uint16_t address,
uint8_t *data,
size_t length,
bool send_stop,
uint32_t timeout_millis);

typedef EZ_DRV_STATUS (*ezHwI2c_ReceiveAsync)(void *driver_h,
typedef EZ_DRV_STATUS (*ezHwI2c_ReceiveAsync)(ezDriver_t *driver_h,
uint16_t address,
uint8_t *data,
size_t length,
bool send_stop);

typedef EZ_DRV_STATUS (*ezHwI2c_Probe)(void *driver_h,
typedef EZ_DRV_STATUS (*ezHwI2c_Probe)(ezDriver_t *driver_h,
uint16_t address,
uint32_t timeout_millis);

struct ezHwI2cInterface
{
void *driver_h; /**< Pointer to the HW driver handle to identify which hw driver is used */
ezHwI2c_Initialize initialize; /**< Initialize I2C interface */
ezHwI2c_TransmitSync transmit_sync; /**< Transmit data synchronously */
ezHwI2c_TransmitAsync transmit_async; /**< Transmit data asynchronously */
Expand All @@ -136,9 +135,7 @@ struct ezI2cDriver
};


typedef struct{
struct ezDrvInstance drv_instance; /**< Driver instance */
} ezI2cDrvInstance_t;
typedef struct ezDrvInstance ezI2cDrvInstance_t;

/*****************************************************************************
* Component Variable Definitions
Expand Down
Loading
Loading