SkillAgentSearch skills...

Ceedling

Unit testing and build system for C projects

Install / Use

/learn @ThrowTheSwitch/Ceedling
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Ceedling CI

Welcome to Ceedling 1.0.1

See the Release Notes for an overview of all that’s new since the last generation of Ceedling, versions 0.3x.x, plus links to the detailed Changelog and list of Breaking Changes.

🌱 Ceedling is a handy-dandy build system for C projects

Developer-friendly release and test builds

Ceedling can build your release artifact but is especially adept at building unit test suites for your C projects — even in tricky embedded systems.

⭐️ Eager to just get going? Jump to 📚 Documentation & Learning and 🚀 Getting Started.

Ceedling works the way developers want to work. It is flexible and entirely command-line driven. It drives code generation and command line tools for you. All generated and framework code is easy to see and understand.

Ceedling’s features support all types of C development from low-level embedded to enterprise systems. No tool is perfect, but Ceedling can do a whole lot to help you and your team produce quality software.

Supporting this work

Ceedling and its complementary ThrowTheSwitch pieces and parts are and always will be freely available and open source.

💼 Ceedling Suite is a growing collection of paid products and services built around Ceedling to help you do even more. Ceedling Assist for support contracts and training is now available.

🙏🏻 Please consider supporting Ceedling as a Github Sponsor

Ceedling is a suite of tools

Ceedling is also a suite of tools. It is the glue for bringing together three other awesome open-source projects you can’t live without if you‘re creating awesomeness in the C language.

  1. Unity, an xUnit-style test framework.
  2. CMock<sup></sup>, a code generating, function mocking & stubbing kit for interaction-based testing.
  3. CException, a framework for adding simple exception handling to C projects in the style of higher-order programming languages.

<sup></sup> Through a plugin, Ceedling also supports FFF for fake functions as an alternative to CMock’s mocks and stubs.

But, wait. There’s more.

For simple project structures, Ceedling can build and test an entire project from just a few lines in its project configuration file.

Because it handles all the nitty-gritty of rebuilds and becuase of Unity and CMock, Ceedling makes Test-Driven Development in C a breeze. It even provides handy backtrace debugging options for finding the source of crashing code exercised by your unit tests.

Ceedling is extensible with a simple plugin mechanism. It comes with a number of built-in plugins for code coverage, test suite report generation, Continuous Integration features, IDE integration, release library builds & dependency management, and more.

<br/>

🙋‍♀️ Need Help? Want to Help?

  • Found a bug or want to suggest a feature? Submit an issue at this repo.
  • Trying to understand features or solve a testing problem? Hit the discussion forums.
  • Paid training, customizations, and support contracts are available through Ceedling Assist.

The ThrowTheSwitch community follows a code of conduct.

Please familiarize yourself with our guidelines for contributing to this project, be it code, reviews, documentation, or reports.

Yes, work has begun on Ceedling Certified, a validated version of Ceedling to meet the needs of industry software certification.

<br/>

🧑‍🍳 Sample Unit Testing Code

While Ceedling can build your release artifact, its claim to fame is building and running test suites.

There’s a good chance you’re looking at Ceedling because of its test suite abilities. And, you’d probably like to see what that looks like, huh? Well, let’s cook you up some realistic examples of tested code and running Ceedling with that code.

(A sample Ceedling project configuration file and links to documentation for it are a bit further down in 🚀 Getting Started.)

First, we start with servings of source code to be tested…

Recipe.c

#include "Recipe.h"
#include "Kitchen.h"
#include <stdio.h>

#define MAX_SPICE_COUNT (4)
#define MAX_SPICE_AMOUNT_TSP (8.0f)

static float spice_amount = 0;
static uint8_t spice_count = 0;

void Recipe_Reset(char* recipe, size_t size) {
  memset(recipe, 0, size);
  spice_amount = 0;
  spice_count = 0;
}

// Add ingredients to a spice list string with amounts (tsp.)
bool_t Recipe_BuildSpiceListTsp(char* list, size_t maxLen, SpiceId spice, float amount) {
  if ((++spice_count > MAX_SPICE_COUNT) || ((spice_amount += amount) > MAX_SPICE_AMOUNT_TSP)) {
    snprintf( list, maxLen, "Too spicy!" );
    return FALSE;
  }

  // Kitchen_Ingredient() not shown
  snprintf( list + strlen(list), maxLen, "%s\n", Kitchen_Ingredient( spice, amount, TEASPOON ) );
  return TRUE;
}

Baking.c

#include "Oven.h"
#include "Time.h"
#include "Baking.h"

bool_t Baking_PreheatOven(float setTempF, duration_t timeout) {
  float temperature = 0.0;
  Timer* timer = Time_StartTimer( timeout );
  
  Oven_SetTemperatureF( setTempF );

  while (temperature < setTempF) {
    Time_SleepMs( 250 );
    if (Time_IsTimerExpired( timer )) break;
    temperature = Oven_GetTemperatureReadingF();
  }

  return (temperature >= setTempF);
}

Next, a sprinkle of unit test code…

Some of what Ceedling does is by naming conventions. See Ceedling’s documentation for much more on this.

TestRecipe.c

#include "unity.h"   // Unity, unit test framework
#include "Recipe.h"  // By convention, Recipe.c is part of TestRecipe executable build
#include "Kitchen.h" // By convention, Kitchen.c (not shown) is part of TestRecipe executable build

char recipe[100];

void setUp(void) {
  // Execute reset before each test case
  Recipe_Reset( recipe, sizeof(recipe) );
}

void test_Recipe_BuildSpiceListTsp_shouldBuildSpiceList(void) {
  TEST_ASSERT_TRUE( Recipe_BuildSpiceListTsp( recipe, sizeof(recipe), OREGANO, 0.5 ) );
  TEST_ASSERT_TRUE( Recipe_BuildSpiceListTsp( recipe, sizeof(recipe), ROSEMARY, 1.0 ) );
  TEST_ASSERT_TRUE( Recipe_BuildSpiceListTsp( recipe, sizeof(recipe), THYME, 0.33 ) );
  TEST_ASSERT_EQUAL_STRING( "1/2 tsp. Oregano\n1 tsp. Rosemary\n1/3 tsp. Thyme\n", recipe );
}

void test_Recipe_BuildSpiceListTsp_shouldFailIfTooMuchSpice(void) {
  TEST_ASSERT_TRUE ( Recipe_BuildSpiceListTsp( recipe, sizeof(recipe), CORIANDER, 4.0 ) );
  TEST_ASSERT_TRUE ( Recipe_BuildSpiceListTsp( recipe, sizeof(recipe), BLACK_PEPPER, 4.0 ) );
  // Total spice = 8.0 + 0.1 tsp.
  TEST_ASSERT_FALSE( Recipe_BuildSpiceListTsp( recipe, sizeof(recipe), BASIL, 0.1 ) );
  TEST_ASSERT_EQUAL_STRING( "Too spicy!", recipe );
}

void test_Recipe_BuildSpiceListTsp_shouldFailIfTooManySpices(void) {
  TEST_ASSERT_TRUE ( Recipe_BuildSpiceListTsp( recipe, sizeof(recipe), OREGANO, 1.0 ) );
  TEST_ASSERT_TRUE ( Recipe_BuildSpiceListTsp( recipe, sizeof(recipe), CORIANDER, 1.0 ) );
  TEST_ASSERT_TRUE ( Recipe_BuildSpiceListTsp( recipe, sizeof(recipe), BLACK_PEPPER, 1.0 ) );
  TEST_ASSERT_TRUE ( Recipe_BuildSpiceListTsp( recipe, sizeof(recipe), THYME, 1.0 ) );
  // Attempt to add 5th spice
  TEST_ASSERT_FALSE( Recipe_BuildSpiceListTsp( recipe, sizeof(recipe), BASIL, 1.0 ) );
  TEST_ASSERT_EQUAL_STRING( "Too spicy!", recipe );
}

TestBaking.c

Let’s flavor our test code with a dash of mocks as well…

#include "unity.h"    // Unity, unit test framework
#include "Baking.h"   // By convention, Baking.c is part of TestBaking executable build
#include "MockOven.h" // By convention, mock .h/.c code generated from Oven.h by CMock
#include "MockTime.h" // By convention, mock .h/.c code generated from Time.h by CMock

/*
 * 🚫 This test will fail! Find the missing logic in `Baking_PreheatOven()`.
 * (`Oven_SetTemperatureF()` returns success / failure.)
 */
void test_Baking_PreheatOven_shouldFailIfSettingOvenTemperatureFails(void) {
  Timer timer; // Uninitialized struct

  Time_StartTimer_ExpectAndReturn( TWENTY_MIN, &timer );

  // Tell source code that setting the oven temperature did not work
  Oven_SetTemperatureF_ExpectAndReturn( 350.0, FALSE );

  TEST_ASSERT_FALSE( Baking_PreheatOven( 350.0, TWENTY_MIN ) );
}

void test_Baking_PreheatOven_shouldFailIfTimeoutExpires(void) {
  Timer timer; // Uninitialized struct

  Time_StartTimer_ExpectAndReturn( TEN_MIN, &timer );

  Oven_SetTemperatureF_ExpectAndReturn( 200.0, TRUE );

  // We only care that `sleep()` is called, not necessarily every call to it
  Time_SleepMs_Ignore();

  // Unrolled loop of timeout and temperature checks
  Time_IsTimerExpired_ExpectAndReturn( &timer, FALSE );
  Oven_GetTemperatureReadingF_ExpectAndReturn( 100.0 );
  Time_IsTimerExpired_ExpectAnd
View on GitHub
GitHub Stars790
CategoryDevelopment
Updated1d ago
Forks265

Languages

Ruby

Security Score

100/100

Audited on Mar 30, 2026

No findings