Ceedling

Build System for GROWING ROBUST C Projects

 

Ceedling starts with the Unity test framework and CMock mock and stub generation, then adds a build system for coordinating, executing, and summarizing test and release builds. It handles all the messiness of managing tests, so that you can focus on writing code.

It supports your favorite toolchains, targeting native gcc or clang builds “out of the box”, or is configurable to use your favorite cross-compiler and simulators. It has a rich plugin infrastructure which expands it core capabilities to a wide array of reporting options, test coverage tracking, and other niceties.

Check out Ceedling’s extensive documentation for more!

panel5.png

HOW CEEDLING WORKS

Ceedling is a command-line tool which runs on any operating system that can run Ruby (yes, even that one). It’s commands are plain and consistent, so it can be integrated smoothly into most IDE’s or text editors without too much effort.

Ceedling’s configuration is stored in a single yaml file, which is human-editable and can be stored alongside your actual tests in version control. This configuration tells Ceedling where to find your source files, how you expect tests to be run, what tools you’re using, and more. It’s your one-stop shop to all things Ceedling!

If you need to install Ceedling yet, jump down to the next section first. Then come back here.

Ready?

Let’s start by creating a new project:


> ceedling new MyProject
      create  MyProject
      create  MyProject/src
      create  MyProject/test
      create  MyProject/test/support
      create  MyProject/project.yml

🌱 New project 'MyProject' created at ./MyProject/

> cd MyProject

Ceedling creates a new folder named after the project name we specified, MyProject, and then adds a starter project.yml file and some basic structure to it. You don’t have to use this structure. You’re welcome to add or remove files as needed… just update the :paths: section of your project.yml file to match.

So let’s create a new module in our project:


> ceedling module:create[Demo]
🚧 Loaded project configuration from working directory.
File src/Demo.c created
File src/Demo.h created
File test/test_Demo.c created
Generate Complete

It’s created three files for us… a C and header pair called Demo.c and Demo.h… and a test file to test those files. Let’s dump some code into those, starting with Demo.c:


#include "Demo.h"

int run_demo(int a, int b)
{
  return 2 * a + b;
}

Demo.h:


int run_demo(int a, int b);

and finally test_Demo.c:


#include "unity.h"
#include "Demo.h"

void setUp(void) {}
void tearDown(void) {}

void test_RunningDemo_should_DoNormalOperations(void)
{
  TEST_ASSERT_EQUAL_INT(3, run_demo(1,1));
  TEST_ASSERT_EQUAL_INT(6, run_demo(2,2));
  TEST_ASSERT_EQUAL_INT(13, run_demo(4,5));
}

If you’re familiar with Unity, those assertions probably look familiar? We’re running our run_demo function a few times with various inputs, and making sure the outputs are correct. Well, let’s see if it works:


> ceedling test:all
🚧 Loaded project configuration from working directory.
👟 Preparing Build Paths...

👟 Collecting Test Context
--------------------------
Parsing test_Demo.c for build directive macros, #includes, and test case names...

👟 Ingesting Test Configurations
--------------------------------
Collecting search paths, flags, and defines test_Demo.c...

👟 Determining Files to be Generated...

👟 Mocking
----------

👟 Test Runners
---------------
Generating runner for test_Demo.c...

👟 Determining Artifacts to Be Built...

👟 Building Objects
-------------------
Compiling test_Demo.c...
Compiling test_Demo::Demo.c...
Compiling test_Demo::test_Demo_runner.c...
Compiling test_Demo::unity.c...

👟 Building Test Executables
----------------------------
Linking test_Demo.out...

👟 Executing
------------
Running test_Demo.out...

-----------------------
✅ OVERALL TEST SUMMARY
-----------------------
TESTED:  1
PASSED:  1
FAILED:  0
IGNORED: 0

Well, it appears that our test works… Notice that it lists the number of test functions, not assertions. Ceedling finds your tests to be more important than the number of details you check during a test. In fact, it will stop on the first failure in each test and report that, without continuing to the rest of the test.

For example, let’s add this to the beginning of our test function:


void test_RunningDemo_should_DoNormalOperations(void)
{
  TEST_ASSERT_EQUAL_INT(1, run_demo(0,0)); // This will fail
  TEST_ASSERT_EQUAL_INT(3, run_demo(1,1));
  TEST_ASSERT_EQUAL_INT(6, run_demo(2,2));
  TEST_ASSERT_EQUAL_INT(13, run_demo(4,5));
}

If you rerun the tests, the end of the report will now look like this:


-------------------
FAILED TEST SUMMARY
-------------------
[test/test_Demo.c]
  Test: test_RunningDemo_should_DoNormalOperations
  At line (16): "Expected 1 Was 0"

-----------------------
❌ OVERALL TEST SUMMARY
-----------------------
TESTED:  1
PASSED:  0
FAILED:  1
IGNORED: 0

---------------------
BUILD FAILURE SUMMARY
---------------------
Unit test failures.

Aw… Ceedling was kind enough to point out where our failure is, so that it’s easier to debug. Isn’t that nice?

Notice we never had to give Ceedling a list of tests to run. We never had to write a main function. We didn’t have to tell Ceedling how many files to compile or when to run them. It’s all automatic. We HAVE the flexibility to dive into those things, but Ceedling has been designed to “just work” through a lot of convenient conventions. Want to learn more? To the docs!

GET Ceedling

The most common way to “get” Ceedling is going to be to install the Ceedling gem. If you’re familiar with Ruby, you could have guessed this. Otherwise, check out the instructions below:

 
 

OR

 

USE RUBY GEMS

gem install ceedling

or, if you’re using a firewall:

gem install ceedling --http-proxy=http://user:password@server:port

(where you get to replace user, password, server, and port with your specific credentials)

USE DOCKER

Maybe you want to just use our preconfigured docker image which already contains the tools you need?

docker run -it --rm -v <local project path>:/project throwtheswitch/madsciencelab:latest

panel4.png
Ceedling Assist

Are you looking for more focused support than forums and volunteers? ThingamaByte is here to help! Reserve a block of assistance and then use it as you need it. We assist project setup and configuration. We assist testing best-practices. We even assist plugin development or Ceedling feature updates! Get prioritized support now!