diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 0b724accc..894cd1c24 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -1,9 +1,15 @@
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
---
-# Continuous Integration Workflow: Test case suite run + validation build check
+# Continuous Integration Workflow
name: CI
-# Controls when the action will run.
-# Triggers the workflow on push or pull request events but only for the master branch
+# Triggers the workflow on push or pull request events for master & test branches
on:
push:
branches:
@@ -13,69 +19,269 @@ on:
branches: [ master ]
workflow_dispatch:
+
+# Needed by softprops/action-gh-release
+permissions:
+ # Allow built gem file push to Github release
+ contents: write
+
+
jobs:
- # Job: Unit test suite
- unit-tests:
- name: "Unit Tests"
+ # Job: Linux unit test suite
+ unit-tests-linux:
+ name: "Linux Test Suite"
runs-on: ubuntu-latest
strategy:
+ fail-fast: false
matrix:
- ruby: ['2.7', '3.0', '3.1']
+ ruby: ['3.0', '3.1', '3.2', '3.3']
steps:
- # Install Binutils, Multilib, etc
- - name: Install C dev Tools
+ # Use a cache for our tools to speed up testing
+ - uses: actions/cache@v4
+ with:
+ path: vendor/bundle
+ key: bundle-use-ruby-${{ matrix.os }}-${{ matrix.ruby-version }}-${{ hashFiles('**/Gemfile.lock') }}
+ restore-keys: |
+ bundle-use-ruby-${{ matrix.os }}-${{ matrix.ruby-version }}-
+
+ # Checks out repository under $GITHUB_WORKSPACE
+ - name: Checkout Latest Repo
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+
+ # Setup Ruby to run test & build steps on multiple ruby versions
+ - name: Setup Ruby Version Matrix
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: ${{ matrix.ruby }}
+
+ # Install Gem Depdencies (Bundler version should match the one in Gemfile.lock)
+ - name: Install Gem Dependencies for Testing and Ceedling Gem Builds
+ run: |
+ gem install rubocop -v 0.57.2
+ gem install bundler -v "$(grep -A 1 "BUNDLED WITH" Gemfile.lock | tail -n 1)"
+ bundle update
+ bundle install
+
+ # Install gdb for backtrace feature testing
+ - name: Install gdb for Backtrace Feature Testing
run: |
sudo apt-get update -qq
- sudo apt-get install --assume-yes --quiet gcc-multilib
- sudo apt-get install -qq gcc-avr binutils-avr avr-libc gdb
+ sudo apt-get install --assume-yes --quiet gdb
- # Install GCovr
- - name: Install GCovr
+ # Install GCovr for Gcov plugin
+ - name: Install GCovr for Gcov Plugin Tests
run: |
sudo pip install gcovr
+ # Install ReportGenerator for Gcov plugin
+ # Fix PATH before tool installation
+ # https://stackoverflow.com/questions/59010890/github-action-how-to-restart-the-session
+ - name: Install ReportGenerator for Gcov Plugin Tests
+ run: |
+ mkdir --parents $HOME/.dotnet/tools
+ echo "$HOME/.dotnet/tools" >> $GITHUB_PATH
+ dotnet tool install --global dotnet-reportgenerator-globaltool
+
+ # Run Tests
+ - name: Run All Self Tests
+ run: |
+ rake ci
+
+ # Build & Install Ceedling Gem
+ - name: Build and Install Ceedling Gem
+ run: |
+ gem build ceedling.gemspec
+ gem install --local ceedling-*.gem
+
+ # Run temp_sensor
+ - name: Run Tests on temp_sensor Project
+ run: |
+ cd examples/temp_sensor
+ ceedling test:all
+ cd ../..
+
+ # Run FFF Plugin Tests
+ - name: "Run Tests on Ceedling Plugin: FFF"
+ run: |
+ cd plugins/fff
+ rake
+ cd ../..
+
+ # Run Module Generator Plugin Tests
+ - name: "Run Tests on Ceedling Plugin: Module Generator"
+ run: |
+ cd plugins/module_generator
+ rake
+ cd ../..
+
+ # Run Dependencies Plugin Tests
+ - name: "Run Tests on Ceedling Plugin: Dependencies"
+ run: |
+ cd plugins/dependencies
+ rake
+ cd ../..
+
+ # Job: Windows unit test suite
+ unit-tests-windows:
+ name: "Windows Test Suite"
+ runs-on: windows-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ ruby: ['3.0', '3.1', '3.2', '3.3']
+ steps:
+ # Use a cache for our tools to speed up testing
+ - uses: actions/cache@v4
+ with:
+ path: vendor/bundle
+ key: bundle-use-ruby-${{ matrix.os }}-${{ matrix.ruby-version }}-${{ hashFiles('**/Gemfile.lock') }}
+ restore-keys: |
+ bundle-use-ruby-${{ matrix.os }}-${{ matrix.ruby-version }}-
+
# Checks out repository under $GITHUB_WORKSPACE
- name: Checkout Latest Repo
- uses: actions/checkout@v2
+ uses: actions/checkout@v4
with:
submodules: recursive
- # Setup Ruby Testing Tools to do tests on multiple ruby version
- - name: Setup Ruby Testing Tools
+ # Setup Ruby to run test & build steps on multiple ruby versions
+ - name: Setup Ruby Version Matrix
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
- # Install Ruby Testing Tools (Bundler version should match the one in Gemfile.lock)
- - name: Install Ruby Testing Tools
+
+ # Install Gem Depdencies (Bundler version should match the one in Gemfile.lock)
+ - name: Install Gem Dependencies for Testing and Ceedling Gem Builds
+ shell: bash
run: |
- gem install rspec
gem install rubocop -v 0.57.2
gem install bundler -v "$(grep -A 1 "BUNDLED WITH" Gemfile.lock | tail -n 1)"
bundle update
bundle install
+ # Install GCovr for Gcov plugin test
+ - name: "Install GCovr for Tests of Ceedling Plugin: Gcov"
+ run: |
+ pip install gcovr
+
+ # Install ReportGenerator for Gcov plugin test
+ - name: "Install ReportGenerator for Tests of Ceedling Plugin: Gcov"
+ run: |
+ dotnet tool install --global dotnet-reportgenerator-globaltool
+
# Run Tests
- name: Run All Self Tests
run: |
- bundle exec rake ci
+ rake ci
# Build & Install Gem
- - name: Build and Install Gem
+ - name: Build and Install Ceedling Gem
run: |
gem build ceedling.gemspec
gem install --local ceedling-*.gem
- # Run Blinky
- # Disabled because it's set up for avr-gcc
- #- name: Run Tests On Blinky Project
- # run: |
- # cd examples/blinky
- # ceedling module:create[someNewModule] module:destroy[someNewModule] test:all
- # cd ../..
-
- # Run Temp Sensor
- - name: Run Tests On Temp Sensor Project
+ # Run temp_sensor example project
+ - name: Run Tests on temp_sensor Project
run: |
cd examples/temp_sensor
- ceedling module:create[someNewModule] module:destroy[someNewModule] test:all
+ ceedling test:all
+ cd ../..
+
+ # Run FFF Plugin Tests
+ - name: "Run Tests on Ceedling Plugin: FFF"
+ run: |
+ cd plugins/fff
+ rake
cd ../..
+
+ # Run Module Generator Plugin Tests
+ - name: "Run Tests on Ceedling Plugin: Module Generator"
+ run: |
+ cd plugins/module_generator
+ rake
+ cd ../..
+
+ # Run Dependencies Plugin Tests
+ - name: "Run Tests on Ceedling Plugin: Dependencies"
+ run: |
+ cd plugins/dependencies
+ rake
+ cd ../..
+
+ # Job: Automatic Minor Release
+ auto-release:
+ name: "Automatic Minor Release"
+ needs:
+ - unit-tests-linux
+ - unit-tests-windows
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ ruby: [3.2]
+
+ steps:
+ # Checks out repository under $GITHUB_WORKSPACE
+ - name: Checkout Latest Repo
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+
+ # Set Up Ruby Tools
+ - name: Set Up Ruby Tools
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: ${{ matrix.ruby }}
+
+ # Capture the SHA string
+ - name: Git commit short SHA as environment variable
+ shell: bash
+ run: |
+ echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
+
+ - name: Ceedling tag as environment variable
+ shell: bash
+ run: |
+ echo "ceedling_tag=$(ruby ./lib/version.rb)" >> $GITHUB_ENV
+
+ - name: Ceedling build string as environment variable
+ shell: bash
+ run: |
+ echo "ceedling_build=${{ env.ceedling_tag }}-${{ env.sha_short }}" >> $GITHUB_ENV
+
+ # Create Git Commit SHA file in root of checkout
+ - name: Git Commit SHA file
+ shell: bash
+ run: |
+ echo "${{ env.sha_short }}" > ${{ github.workspace }}/GIT_COMMIT_SHA
+
+ # Build Gem
+ - name: Build Gem
+ run: |
+ gem build ceedling.gemspec
+
+ # Create Unofficial Release
+ - name: Create Pre-Release
+ uses: actions/create-release@v1
+ id: create_release
+ with:
+ draft: false
+ prerelease: true
+ release_name: ${{ env.ceedling_build }}
+ tag_name: ${{ env.ceedling_build }}
+ body: "Automatic pre-release for ${{ env.ceedling_build }}"
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+
+ # Post Gem to Unofficial Release
+ - name: Upload Pre-Release Gem
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ with:
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
+ asset_path: ./ceedling-${{ env.ceedling_tag }}.gem
+ asset_name: ceedling-${{ env.ceedling_build }}.gem
+ asset_content_type: test/x-gemfile
+
diff --git a/.gitignore b/.gitignore
index 7224d1d97..b3cb00bbe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,10 +7,13 @@ out.fail
tags
*.taghl
-examples/blinky/build/
-examples/blinky/vendor/
examples/temp_sensor/vendor/
examples/temp_sensor/build/
+plugins/fff/examples/fff_example/build/
+plugins/module_generator/example/build/
+plugins/dependencies/example/boss/build/
+plugins/dependencies/example/boss/third_party/
+plugins/dependencies/example/supervisor/build/
ceedling.sublime-project
ceedling.sublime-workspace
@@ -19,3 +22,4 @@ ceedling-*.gem
.ruby-version
/.idea
/.vscode
+/GIT_COMMIT_SHA
diff --git a/.gitmodules b/.gitmodules
index 128aadf4d..e00535031 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -10,6 +10,3 @@
path = vendor/cmock
url = https://github.com/ThrowTheSwitch/CMock.git
branch = master
-[submodule "plugins/fake_function_framework"]
- path = plugins/fake_function_framework
- url = https://github.com/ElectronVector/fake_function_framework.git
diff --git a/.rubocop.yml b/.rubocop.yml
index 2d00ac807..59b714774 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -1,3 +1,10 @@
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
# This is the configuration used to check the rubocop source code.
#inherit_from: .rubocop_todo.yml
diff --git a/Gemfile b/Gemfile
index a00f5e7f5..7a7d1d5c4 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,14 +1,26 @@
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
source "http://rubygems.org/"
-gem "bundler"
-gem "rake"
+gem "bundler", "~> 2.5"
+
+# Testing tools
gem "rspec", "~> 3.8"
-gem "require_all"
-gem "constructor"
-gem "diy"
+gem "rake", ">= 12", "< 14"
gem "rr"
-gem "thor"
-gem "deep_merge"
+gem "require_all"
+
+# Ceedling dependencies
+gem "diy", "~> 1.1"
+gem "constructor", "~> 2"
+gem "thor", "~> 1.3"
+gem "deep_merge", "~> 1.2"
+gem "unicode-display_width", "~> 3.1"
#these will be used if present, but ignored otherwise
#gem "curses"
diff --git a/Gemfile.lock b/Gemfile.lock
index 647a9fece..8133ca0c3 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -3,41 +3,48 @@ GEM
specs:
constructor (2.0.0)
deep_merge (1.2.2)
- diff-lcs (1.3)
+ diff-lcs (1.5.1)
diy (1.1.2)
constructor (>= 1.0.0)
- rake (13.0.6)
- require_all (1.3.3)
- rr (1.1.2)
- rspec (3.8.0)
- rspec-core (~> 3.8.0)
- rspec-expectations (~> 3.8.0)
- rspec-mocks (~> 3.8.0)
- rspec-core (3.8.0)
- rspec-support (~> 3.8.0)
- rspec-expectations (3.8.2)
+ rake (13.2.1)
+ require_all (3.0.0)
+ rr (3.1.1)
+ rspec (3.13.0)
+ rspec-core (~> 3.13.0)
+ rspec-expectations (~> 3.13.0)
+ rspec-mocks (~> 3.13.0)
+ rspec-core (3.13.2)
+ rspec-support (~> 3.13.0)
+ rspec-expectations (3.13.3)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.8.0)
- rspec-mocks (3.8.0)
+ rspec-support (~> 3.13.0)
+ rspec-mocks (3.13.2)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.8.0)
- rspec-support (3.8.0)
- thor (0.20.3)
+ rspec-support (~> 3.13.0)
+ rspec-support (3.13.1)
+ thor (1.3.2)
+ unicode-display_width (3.1.2)
+ unicode-emoji (~> 4.0, >= 4.0.4)
+ unicode-emoji (4.0.4)
PLATFORMS
ruby
+ x64-mingw-ucrt
x64-mingw32
+ x86_64-darwin-22
+ x86_64-linux
DEPENDENCIES
- bundler
- constructor
- deep_merge
- diy
- rake
+ bundler (~> 2.5)
+ constructor (~> 2)
+ deep_merge (~> 1.2)
+ diy (~> 1.1)
+ rake (>= 12, < 14)
require_all
rr
rspec (~> 3.8)
- thor
+ thor (~> 1.3)
+ unicode-display_width (~> 3.1)
BUNDLED WITH
- 2.4.3
+ 2.5.23
diff --git a/README.md b/README.md
index b74de9965..52fc92489 100644
--- a/README.md
+++ b/README.md
@@ -1,120 +1,741 @@
Ceedling ![CI](https://github.com/ThrowTheSwitch/Ceedling/workflows/CI/badge.svg)
========
-_October 26, 2024_ đ **Ceedling 1.0.0** will be shipping very soon.
-[Prerelease versions are available now](https://github.com/ThrowTheSwitch/Ceedling/releases).
-See the [all new README](https://github.com/ThrowTheSwitch/Ceedling/blob/test/ceedling_0_32_rc/README.md)
-for a reintroduction to Ceedling and links to a variety of complementary resources. See the
-[Release Notes](https://github.com/ThrowTheSwitch/Ceedling/blob/test/ceedling_0_32_rc/docs/ReleaseNotes.md)
-for an overview of all thatâs new since 0.31.1 plus links to a detailed Changelog and list of
+_November 28, 2024_ đ **Ceedling 1.0.0** is a release candidate and will be
+shipping very soon. See the [Release Notes](docs/ReleaseNotes.md) for an overview
+of all thatâs new since 0.31.1 plus links to the detailed Changelog and list of
Breaking Changes.
-Ceedling is a build system for C projects that is something of an extension
-around Rubyâs Rake (make-ish) build system. Ceedling also makes TDD (Test-Driven Development)
-in C a breeze by integrating [CMock](https://github.com/throwtheswitch/cmock),
-[Unity](https://github.com/throwtheswitch/unity), and
-[CException](https://github.com/throwtheswitch/cexception) --
-three other awesome open-source projects you canât live without if you're creating awesomeness
-in the C language. Ceedling is also extensible with a handy plugin mechanism.
+# đ± Ceedling is a handy-dandy build system for C projects
-Usage Documentation
-===================
+## Developer-friendly release _and_ test builds
-Documentation and license info exists [in the repo in docs/](docs/CeedlingPacket.md)
+Ceedling can build your release artifact but is especially adept at building
+unit test suites for your C projects â even in tricky embedded systems.
-Getting Started
-===============
+Ceedling and its complementary pieces and parts are and always will be freely
+available and open source. **_[Ceedling Pro][ceedling-pro]_** is a growing list
+of paid products and services to help you do even more with these tools.
-First make sure Ruby is installed on your system (if it's not already). Then, from a command prompt:
+[ceedling-pro]: https://thingamabyte.com/ceedlingpro
- > gem install ceedling
+âïž **Eager to just get going? Jump to
+[đ Documentation & Learning](#-documentation--learning) and
+[đ Getting Started](#-getting-started).**
-(Alternate Installation for Those Planning to Be Ceedling Developers)
-======================================================================
+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.
- > git clone --recursive https://github.com/throwtheswitch/ceedling.git
- > cd ceedling
- > bundle install # Ensures you have all RubyGems needed
- > git submodule update --init --recursive # Updates all submodules
- > bundle exec rake # Run all Ceedling library tests
+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.
-If bundler isn't installed on your system or you run into problems, you might have to install it:
+## Ceedling is a suite of tools
- > sudo gem install bundler
+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.
-If you run into trouble running bundler and get messages like this `can't find gem
-bundler (>= 0.a) with executable bundle (Gem::GemNotFoundException)`, you may
-need to install a different version of bundler. For this please reference the
-version in the Gemfile.lock. An example based on the current Gemfile.lock is as
-followed:
+1. **[Unity]**, an [xUnit]-style test framework.
+1. **[CMock]**â , a code generating,
+ [function mocking & stubbing][test-doubles] kit for interaction-based testing.
+1. **[CException]**, a framework for adding simple exception handling to C projects
+ in the style of higher-order programming languages.
- > sudo gem install bundler -v 1.16.2
+â Through a [plugin][FFF-plugin], Ceedling also supports [FFF] for
+[fake functions][test-doubles] as an alternative to CMockâs mocks and stubs.
-Creating A Project
-==================
+## But, wait. Thereâs more.
-Creating a project with Ceedling is easy. Simply tell ceedling the
-name of the project, and it will create a subdirectory called that
-name and fill it with a default directory structure and configuration.
+For simple project structures, Ceedling can build and test an entire project
+from just a few lines in its project configuration file.
- ceedling new YourNewProjectName
+Because it handles all the nitty-gritty of rebuilds and becuase of Unity and
+CMock, Ceedling makes [Test-Driven Development][TDD] in C a breeze. It even
+provides handy backtrace debugging options for finding the source of crashing
+code exercised by your unit tests.
-You can add files to your src and test directories and they will
-instantly become part of your test build. Need a different structure?
-You can start to tweak the `project.yml` file immediately with your new
-path or tool requirements.
+Ceedling is extensible with a simple plugin mechanism. It comes with a
+number of [built-in plugins][ceedling-plugins] for code coverage, test suite
+report generation, Continuous Integration features, IDE integration, release
+library builds & dependency management, and more.
-You can upgrade to the latest version of Ceedling at any time,
-automatically gaining access to the packaged Unity and CMock that
-come with it.
+[Unity]: https://github.com/throwtheswitch/unity
+[xUnit]: https://en.wikipedia.org/wiki/XUnit
+[CMock]: https://github.com/throwtheswitch/cmock
+[CException]: https://github.com/throwtheswitch/cexception
+[TDD]: http://en.wikipedia.org/wiki/Test-driven_development
+[test-doubles]: https://blog.pragmatists.com/test-doubles-fakes-mocks-and-stubs-1a7491dfa3da
+[FFF]: https://github.com/meekrosoft/fff
+[FFF-plugin]: plugins/fff
+[ceedling-plugins]: docs/CeedlingPacket.md#ceedling-plugins
- gem update ceedling
+
-Documentation
-=============
+# đââïž Need Help? Want to Help?
-Are you just getting started with Ceedling? Maybe you'd like your
-project to be installed with some of its handy documentation? No problem!
-You can do this when you create a new project.
+* Found a bug or want to suggest a feature?
+ **[Submit an issue][ceedling-issues]** at this repo.
+* Trying to understand features or solve a testing problem? Hit the
+ **[discussion forums][forums]**.
+* Paid training, customizations, and support contracts are available through
+ **[Ceedling Pro][ceedling-pro]**.
- ceedling new --docs MyAwesomeProject
+The ThrowTheSwitch community follows a **[code of conduct](docs/CODE_OF_CONDUCT.md)**.
-Bonding Your Tools And Project
-==============================
+Please familiarize yourself with our guidelines for **[contributing](docs/CONTRIBUTING.md)** to this project, be it code, reviews, documentation, or reports.
-Ceedling can deploy all of its guts into the project as well. This
-allows it to be used without having to worry about external dependencies.
-You don't have to worry about Ceedling changing for this particular
-project just because you updated your gems... no need to worry about
-changes in Unity or CMock breaking your build in the future. If you'd like
-to use Ceedling this way, tell it you want a local copy when you create
+Yes, work has begun on certified versions of the Ceedling suite of tools to be available through **[Ceedling Pro][ceedling-pro]**. [Reach out to ThingamaByte][thingama-contact] for more.
+
+[ceedling-issues]: https://github.com/ThrowTheSwitch/Ceedling/issues
+[forums]: https://www.throwtheswitch.org/forums
+[thingama-contact]: https://www.thingamabyte.com/contact
+
+
+
+# đ§âđł 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](#-getting-started)_.)
+
+## First, we start with servings of source code to be testedâŠ
+
+### Recipe.c
+
+```c
+#include "Recipe.h"
+#include "Kitchen.h"
+#include
+
+#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
+
+```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](#-documentation--learning) for much more on this.
+
+### TestRecipe.c
+
+```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âŠ
+
+```c
+#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_ExpectAndReturn( &timer, FALSE );
+ Oven_GetTemperatureReadingF_ExpectAndReturn( 105.0 );
+ Time_IsTimerExpired_ExpectAndReturn( &timer, FALSE );
+ Oven_GetTemperatureReadingF_ExpectAndReturn( 110.0 );
+ Time_IsTimerExpired_ExpectAndReturn( &timer, TRUE );
+
+ TEST_ASSERT_FALSE( Baking_PreheatOven( 200.0, TEN_MIN ) );
+}
+
+void test_Baking_PreheatOven_shouldSucceedAfterAWhile(void) {
+ Timer timer; // Uninitialized struct
+
+ Time_StartTimer_ExpectAndReturn( TEN_MIN, &timer );
+
+ Oven_SetTemperatureF_ExpectAndReturn( 400.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( 390.0 );
+ Time_IsTimerExpired_ExpectAndReturn( &timer, FALSE );
+ Oven_GetTemperatureReadingF_ExpectAndReturn( 395.0 );
+ Time_IsTimerExpired_ExpectAndReturn( &timer, FALSE );
+ Oven_GetTemperatureReadingF_ExpectAndReturn( 399.0 );
+ Time_IsTimerExpired_ExpectAndReturn( &timer, FALSE );
+ Oven_GetTemperatureReadingF_ExpectAndReturn( 401.0 );
+
+ TEST_ASSERT_TRUE( Baking_PreheatOven( 400.0, TEN_MIN ) );
+}
+```
+
+## Add a pinch of command lineâŠ
+
+See Ceedlingâs [documentation](#-documentation--learning) for examples and everything you need to know about Ceedlingâs configuration file options (not shown here).
+
+The super duper short version is that your project configuration file tells Ceedling where to find test and source files, what testing options youâre using, sets compilation symbols and build tool flags, enables your plugins, and configures your build tool command lines (Ceedling defaults to using the GNU compiler collection â which must be installed, if used).
+
+```shell
+ > ceedling test:all
+```
+
+## VoilĂ ! Test results. `#ChefsKiss`
+
+The test results below are one of the last bits of logging Ceedling produces for a test suite build. Not shown here are all the steps for extracting build details, C code generation, and compilation and linking.
+
+```
+-------------------
+FAILED TEST SUMMARY
+-------------------
+[test/TestBaking.c]
+ Test: test_Baking_PreheatOven_shouldFailIfSettingOvenTemperatureFails
+ At line (7): "Function Time_SleepMs() called more times than expected."
+
+-----------------------
+â OVERALL TEST SUMMARY
+-----------------------
+TESTED: 6
+PASSED: 5
+FAILED: 1
+IGNORED: 0
+```
+
+## Ceedling also supports various side dishes in your delicious test suite
+
+The Unity project supports parameterized test cases like this:
+
+```C
+TEST_RANGE([5, 100, 5])
+void test_should_handle_divisible_by_5_for_parameterized_test_range(int num) {
+ TEST_ASSERT_EQUAL(0, (num % 5));
+}
+```
+
+Ceedling can do all the magic to build and run this test code simply by enabling parameterized test cases in its project configuration. Keep reading for more on how to configure a Ceedling build.
+
+```yaml
+:unity:
+ :use_param_tests: TRUE
+```
+
+
+
+# đ Documentation & Learning
+
+A variety of options for [community-based support][TTS-help] exist.
+
+Training and support contracts are available through **_[Ceedling Pro][ceedling-pro]_**
+
+[TTS-help]: https://www.throwtheswitch.org/#help-section
+
+The [Agile Embedded Podcast][ae-podcast] includes an [episode on Ceedling][ceedling-episode]!
+
+[ae-podcast]: https://agileembeddedpodcast.com/
+[ceedling-episode]: https://agileembeddedpodcast.com/episodes/ceedling
+
+## Ceedling docs
+
+* **_[Ceedling Packet][ceedling-packet]_** is Ceedlingâs user manual. It also references and links to the documentation of the projects, _Unity_, _CMock_, and _CException_, that it weaves together into your test and release builds.
+* **[Release Notes][release-notes]**, **[Breaking Changes][breaking-changes]**, and **[Changelog][changelog]** can be found in the **[docs/](docs/)** directory along with a variety of guides and much more.
+* The **[Plugins section](https://github.com/ThrowTheSwitch/Ceedling/blob/test/ceedling_0_32_rc/docs/CeedlingPacket.md#ceedling-plugins)** within _Ceedling Packet_ lists all of Ceedlingâs built-in plugins providing overviews and links to their documentation.
+
+## Library and courses
+
+[ThrowTheSwitch.org][TTS]:
+
+* Provides a small but useful **[library of resources and guides][library]** on testing and using the Ceedling suite of tools.
+* Discusses your **[options for running a test suite][running-options]**, particularly in the context of embedded systems.
+* Links to paid courses, **_[Dr. Surlyâs School for Mad Scientists][courses]_**, that provide in-depth training on creating C unit tests and using Unity, CMock, and Ceedling to do so.
+
+## Online tutorial
+
+Matt Chernoskyâs **[detailed tutorial][tutorial]** demonstrates using Ceedling to build a C project with test suite. As the tutorial is a number of years old, the content is a bit out of date. That said, it provides an excellent overview of a real project. Matt is the author of [FFF] and the [FFF plugin][FFF-plugin] for Ceedling.
+
+[ceedling-packet]: docs/CeedlingPacket.md
+[release-notes]: docs/ReleaseNotes.md
+[breaking-changes]: docs/BreakingChanges.md
+[changelog]: docs/Changelog.md
+[TTS]: https://throwtheswitch.org
+[library]: http://www.throwtheswitch.org/library
+[running-options]: http://www.throwtheswitch.org/build/which
+[courses]: http://www.throwtheswitch.org/dr-surlys-school
+[tutorial]: http://www.electronvector.com/blog/add-unit-tests-to-your-current-project-with-ceedling
+
+
+
+# đ Getting Started
+
+đ See the **_[Quick Start](docs/CeedlingPacket.md#quick-start)_** section in Ceedlingâs user manual, _Ceedling Packet_.
+
+## The basics
+
+### Local installation
+
+1. Install [Ruby]. (Only Ruby 3+ supported.)
+1. Install Ceedling. All supporting frameworks are included.
+ ```shell
+ > gem install ceedling
+ ```
+1. Begin crafting your project:
+ 1. Create an empty Ceedling project.
+ ```shell
+ > ceedling new []
+ ```
+ 1. Or, add a Ceedling project file to the root of an existing code project.
+1. Run tasks like so:
+ ```shell
+ > ceedling test:all release
+ ```
+
+[Ruby]: https://www.ruby-lang.org/
+
+### _MadScienceLab_ Docker Images
+
+As an alternative to local installation, fully packaged Docker images containing Ruby, Ceedling, the GCC toolchain, and more are also available. [Docker][docker-overview] is a virtualization technology that provides self-contained software bundles that are a portable, well-managed alternative to local installation of tools like Ceedling.
+
+Four Docker image variants containing Ceedling and supporting tools exist. These four images are available for both Intel and ARM host platforms (Docker does the right thing based on your host environment). The latter includes ARM Linux and Appleâs M-series macOS devices.
+
+1. **_[MadScienceLab][docker-image-base]_**. This image contains Ruby, Ceedling, CMock, Unity, CException, the GNU Compiler Collection (gcc), and a handful of essential C libraries and command line utilities.
+1. **_[MadScienceLab Plugins][docker-image-plugins]_**. This image contains all of the above plus the command line tools that Ceedlingâs built-in plugins rely on. Naturally, it is quite a bit larger than option (1) because of the additional tools and dependencies.
+1. **_[MadScienceLab ARM][docker-image-arm]_**. This image mirrors (1) with the compiler toolchain replaced with the GNU `arm-none-eabi` variant.
+1. **_[MadScienceLab ARM + Plugins][docker-image-arm-plugins]_**. This image is (3) with the addition of all the complementary plugin tooling just like (2) provides.
+
+See the Docker Hub pages linked above for more documentation on these images.
+
+Just to be clear here, most users of the _MadScienceLab_ Docker images will probably care about the ability to run unit tests on your own host. If you are one of those users, no matter what host platform you are on â Intel or ARM â youâll want to go with (1) or (2) above. The tools within the image will automatically do the right thing within your environment. Options (3) and (4) are most useful for specialized cross-compilation scenarios.
+
+#### _MadScienceLab_ Docker Image usage basics
+
+To use a _MadScienceLab_ image from your local terminal:
+
+1. [Install Docker][docker-install]
+1. Determine:
+ 1. The local path of your Ceedling project
+ 1. The variant and revision of the Docker image youâll be using
+1. Run the container with:
+ 1. The Docker `run` command and `-it --rm` command line options
+ 1. A Docker volume mapping from the root of your project to the default project path inside the container (_/home/dev/project_)
+
+See the command line examples in the following two sections.
+
+Note that all of these somewhat lengthy command lines lend themselves well to being wrapped up in simple helper scripts specific to your project and directory structure.
+
+#### Run a _MadScienceLab_ Docker Image as an interactive terminal
+
+When the container launches as shown below, it will drop you into a Z-shell command line that has access to all the tools and utilities available within the container. In this usage, the Docker container becomes just another terminal, including ending its execution with `exit`.
+
+```shell
+ > docker run -it --rm -v /my/local/project/path:/home/dev/project throwtheswitch/madsciencelab-plugins:1.0.0
+```
+
+Once the _MadScienceLab_ containerâs command line is available, to run Ceedling, execute it just as you would after installing Ceedling locally:
+
+```shell
+ ~/project > ceedling help
+```
+
+```shell
+ ~/project > ceedling new ...
+```
+
+```shell
+ ~/project > ceedling test:all
+```
+
+#### Run a _MadScienceLab_ Docker Image as a command line utility
+
+Alternatively, you can run Ceedling through the _MadScienceLab_ Docker container directly from the command line as a command line utility. The general pattern is immediately below.
+
+```shell
+ > docker run -it --rm -v /my/local/project/path:/home/dev/project throwtheswitch/madsciencelab-plugins:1.0.0
+```
+
+As a specific example, to run all tests in a suite, the command line would be this:
+
+```shell
+ > docker run -it --rm -v /my/local/project/path:/home/dev/project throwtheswitch/madsciencelab-plugins:1.0.0 ceedling test:all
+```
+
+In this usage, the container starts, executes Ceedling, and then ends.
+
+[docker-overview]: https://www.ibm.com/topics/docker
+[docker-install]: https://www.docker.com/products/docker-desktop/
+
+[docker-image-base]: https://hub.docker.com/repository/docker/throwtheswitch/madsciencelab
+[docker-image-plugins]: https://hub.docker.com/repository/docker/throwtheswitch/madsciencelab-plugins
+[docker-image-arm]: https://hub.docker.com/repository/docker/throwtheswitch/madsciencelab-arm-none-eabi
+[docker-image-arm-plugins]: https://hub.docker.com/repository/docker/throwtheswitch/madsciencelab-arm-none-eabi-plugins
+
+### Example super-duper simple Ceedling configuration file
+
+```yaml
+:project:
+ :build_root: project/build/
+ :release_build: TRUE
+
+:paths:
+ :test:
+ - tests/**
+ :source:
+ - source/**
+ :include:
+ - inc/**
+```
+
+See this [commented project configuration file][example-config-file] for a much more complete and sophisticated example of a project configuration.
+
+Or, use Ceedlingâs built-in `examples` & `example` commands to extract a sample project and reference its project file.
+
+See the [configuration section][ceedling-packet-config] in _Ceedling Packet_ for way more details on your project configuration options than we can provide here.
+
+[example-config-file]: assets/project_as_gem.yml
+[ceedling-packet-config]: docs/CeedlingPacket.md#the-almighty-ceedling-project-configuration-file-in-glorious-yaml
+
+## Using Ceedlingâs command line (and related)
+
+### Command line help
+
+For an overview of all commands, itâs as easy asâŠ
+
+```sh
+ > ceedling help
+```
+
+For a detailed explanation of a single commandâŠ
+
+```sh
+ > ceedling help
+```
+
+### Creating a project
+
+Creating a project with Ceedling is easy. Simply tell Ceedling the name of the
+project, and it will create a directory with that name and fill it with a
+default subdirectory structure and configuration file. An optional destination
+path is also possible.
+
+```shell
+ > ceedling new YourNewProjectName
+```
+
+You can add files to your `src/` and `test/` directories, and they will
+instantly become part of your test and/or release build. Need a different
+structure? You can modify the `project.yml` file with your new path or
+tooling setup.
+
+#### Installing local documentation
+
+Are you just getting started with Ceedling? Maybe youâd like your
+project to be installed with some of its handy [documentation](docs/)?
+No problem! You can do this when you create a new projectâŠ
+
+```shell
+ > ceedling new --docs MyAwesomeProject
+```
+
+#### Attaching a Ceedling version to your project
+
+Ceedling can be installed as a globally available Ruby gem. Ceedling can
+also deploy all its guts into your project instead. This allows it to
+be used without worrying about external dependencies. More importantly,
+you donât have to worry about Ceedling changing outside of your project
+just because you updated your gems. No need to worry about changes in
+Unity or CMock breaking your build in the future.
+
+To use Ceedling this way, tell it you want a local copy when you create
your project:
- ceedling new --local YourNewProjectName
+```shell
+ > ceedling new --local YourNewProjectName
+```
+
+This will install all of Unity, CMock, CException, and Ceedling itself
+into a new folder `vendor/` inside your project `YourNewProjectName/`.
+It will create the same simple empty directory structure for you with
+`src/` and `test/` folders as the standard `new` command.
+
+### Running build & plugin tasks
+
+You can view all the build and plugin tasks available to you thanks to your
+Ceedling project file with `ceedling help`. Ceedlingâs command line help
+provides a summary list from your project configuration if Ceedling is
+able to find your project file (`ceedling help help` for more on this).
+
+Running Ceedling build tasks tends to look like thisâŠ
+
+```shell
+ > ceedling test:all release
+```
+
+```shell
+ > ceedling gcov:all --verbosity=obnoxious --test-case=boot --mixin=code_cruncher_toolchain
+```
+
+### Upgrading / updating Ceedling
+
+You can upgrade to the latest version of Ceedling at any time, automatically
+gaining access to any accompanying updates to Unity, CMock, and CException.
+
+To update a locally installed gemâŠ
+
+```shell
+ > gem update ceedling
+```
+
+Otherwise, if you are using the Docker image, you may upgrade by pulling
+a newer version of the imageâŠ
+
+```shell
+ > docker pull throwtheswitch/madsciencelab:
+```
+
+If you want to force a vendored version of Ceedling inside your project to
+upgrade to match your latest gem, no problem. Just do the followingâŠ
+
+```shell
+ > ceedling upgrade --local YourNewProjectName
+```
+
+Just like with the `new` command, an `upgrade` should be executed from
+within the root directory of your project.
+
+### Git integration
+
+Are you using Git? You might want Ceedling to create a `.gitignore`
+that ignores the build folder while retaining control of the artifacts
+folder. This will also add a `.gitkeep` file to your `test/support` folder.
+You can enable this by adding `--gitsupport` to your `new` call.
+
+```shell
+ > ceedling new --gitsupport YourNewProjectName
+```
+
+
+# đ» Contributing to Ceedling Development
+
+## Alternate installation options for Ceedling development
+
+### Alternate local installation for development
+
+After installing RubyâŠ
+
+```shell
+ > git clone --recursive https://github.com/throwtheswitch/ceedling.git
+ > cd ceedling
+ > git submodule update --init --recursive
+ > bundle install
+```
+
+The Ceedling repository incorporates its supporting frameworks and some
+plugins via Git submodules. A simple clone may not pull in the latest
+and greatest.
+
+The `bundle` tool ensures you have all needed Ruby gems installed. If
+Bundler isnât installed on your system or you run into problems, you
+might have to install it:
+
+```shell
+ > sudo gem install bundler
+```
+
+If you run into trouble running bundler and get messages like _canât
+find gem bundler (>= 0.a) with executable bundle
+(Gem::GemNotFoundException)_, you may need to install a different
+version of Bundler. For this please reference the version in the
+Gemfile.lock.
+
+```shell
+ > sudo gem install bundler -v
+```
+
+### Alternate Docker image usage for development
+
+As an alternative to local installation of Ceedling, nearly all development
+tasks can be accomplished with the _MadScienceLab_ Docker images.
+
+When running an existing image as a development container, one merely needs
+to map a volume from your local Ceedling code repository to Ceedlingâs
+installation location within the container. With that accomplished,
+experimenting with project builds and running self-tests is simple.
+
+1. Start your target Docker container from your host system terminal:
+
+ ```shell
+ > docker run -it --rm throwtheswitch/:
+ ```
+1. Look up and note Ceedlingâs installation path (listed in `version` output) from within the container command line:
+
+ ```shell
+ ~/project > ceedling version
+
+
+ ```
+1. Exit the container.
+1. Restart the container from your host system with the Ceedling installation
+ volume mapping from (2) and any other command line options you need:
+
+ ```shell
+ > docker run -it --rm -v /my/local/ceedling/repo: -v /my/local/experiment/path:/home/dev/project throwtheswitch/:
+ ```
+
+For development tasks, from the container shell you can:
+
+1. Run experiment projects you map into the container (e.g. at _/home/dev/project_).
+1. Run the self-test suite. Navigate to the gem installation path discovered in (2) above. From this location, follow the instructions in the section that immediately follows.
+
+## Running Ceedlingâs self-tests
+
+Ceedling uses [RSpec] for its tests.
+
+To execute tests you may run the following from the root of your local
+Ceedling repository. This test suite build option balances test coverage
+with suite execution time.
+
+```shell
+ > rake spec
+```
+
+To run individual test files (Ceedlingâs Ruby-based tests, that is) and
+perform other tasks, use the available Rake tasks. From the root of your
+local Ceedling repo, list those task like this:
+
+```shell
+ > rake -T
+```
-This will install all of Unity, CMock, and Ceedling into a new folder
-named `vendor` inside your project `YourNewProjectName`. It will still create
-the simple directory structure for you with `src` and `test` folders.
+[RSpec]: https://rspec.info
-SCORE!
+## Working in `bin/` vs. `lib/`
-If you want to force a locally installed version of Ceedling to upgrade
-to match your latest gem later, it's easy! Just issue the following command:
+Most of Ceedlingâs functionality is contained in the application code residing
+in `lib/`. Ceedlingâs command line handling, startup configuration, project
+file loading, and mixin handling are contained in a âbootloaderâ in `bin/`.
+The code in `bin/` is the source of the `ceedling` command line tool and
+launches the application from `lib/`.
- ceedling upgrade --local YourNewProjectName
+Depending on what youâre working on you may need to run Ceedling using
+a specialized approach.
-Just like the `new` command, it's called from the parent directory of your
-project.
+If you are only working in `lib/`, you can:
-Are you afraid of losing all your local changes when this happens? You can keep
-Ceedling from updating your project file by issuing `no_configs`.
+1. Run Ceedling using the `ceedling` command line utility you already have
+ installed. The code in `bin/` will run from your locally installed gem or
+ from within your Docker container and launch the Ceedling application for
+ you.
+1. Modify a project file by setting a path value for `:project` âł `:which_ceedling`
+ that points to the local copy of Ceedling you cloned from the Git repository.
+ See _CeedlingPacket_ for details.
- ceedling upgrade --local --no_configs TheProject
+If you are working in `bin/`, running `ceedling` at the command line will not
+call your modified code. Instead, you must execute the path to the executable
+`ceedling` in the `bin/` folder of the local Ceedling repository you are
+working on.
-Git Integration
-===============
-Are you using Git? You might want to automatically have Ceedling create a
-`gitignore` file for you by adding `--gitignore` to your `new` call.
-*HAPPY TESTING!*
diff --git a/Rakefile b/Rakefile
index bcdcdf2a9..6dfe1dc83 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,4 +1,11 @@
#!/usr/bin/env rake
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
require 'bundler'
require 'rspec/core/rake_task'
@@ -7,5 +14,13 @@ RSpec::Core::RakeTask.new(:spec) do |t|
t.pattern = 'spec/**/*_spec.rb'
end
+Dir['spec/**/*_spec.rb'].each do |p|
+ base = File.basename(p,'.*').gsub('_spec','')
+ desc "rspec #{base}"
+ RSpec::Core::RakeTask.new("spec:#{base}") do |t|
+ t.pattern = p
+ end
+end
+
task :default => [:spec]
task :ci => [:spec]
diff --git a/assets/auto_link_deep_dependencies/src/a.c b/assets/auto_link_deep_dependencies/src/a.c
deleted file mode 100644
index 78b18e8ff..000000000
--- a/assets/auto_link_deep_dependencies/src/a.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "a.h"
-#include "b.h"
-
-int function_from_a(int a)
-{
- return 2 * function_from_b(a);
-}
diff --git a/assets/auto_link_deep_dependencies/src/b.c b/assets/auto_link_deep_dependencies/src/b.c
deleted file mode 100644
index f40980081..000000000
--- a/assets/auto_link_deep_dependencies/src/b.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "b.h"
-#include "c.h"
-
-int function_from_b(int b)
-{
- return 2 * function_from_c(b);
-}
diff --git a/assets/auto_link_deep_dependencies/src/c.c b/assets/auto_link_deep_dependencies/src/c.c
deleted file mode 100644
index 810aed80d..000000000
--- a/assets/auto_link_deep_dependencies/src/c.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "c.h"
-#include "never_compiled.h"
-
-int function_from_c(int c)
-{
- function_never_compiled(2);
- return 2 * c;
-}
diff --git a/assets/auto_link_deep_dependencies/src/internal_inc/a.h b/assets/auto_link_deep_dependencies/src/internal_inc/a.h
deleted file mode 100644
index 8cde06168..000000000
--- a/assets/auto_link_deep_dependencies/src/internal_inc/a.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef A_H
-#define A_H
-
-int function_from_a(int a);
-
-#endif /* A_H */
\ No newline at end of file
diff --git a/assets/auto_link_deep_dependencies/src/internal_inc/b.h b/assets/auto_link_deep_dependencies/src/internal_inc/b.h
deleted file mode 100644
index 50035e04d..000000000
--- a/assets/auto_link_deep_dependencies/src/internal_inc/b.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef B_H
-#define B_H
-
-int function_from_b(int b);
-
-#endif /* B_H */
\ No newline at end of file
diff --git a/assets/auto_link_deep_dependencies/src/internal_inc/c.h b/assets/auto_link_deep_dependencies/src/internal_inc/c.h
deleted file mode 100644
index e481ee9bf..000000000
--- a/assets/auto_link_deep_dependencies/src/internal_inc/c.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef C_H
-#define C_H
-
-int function_from_c(int c);
-
-#endif /* C_H */
\ No newline at end of file
diff --git a/assets/auto_link_deep_dependencies/src/internal_inc/never_compiled.h b/assets/auto_link_deep_dependencies/src/internal_inc/never_compiled.h
deleted file mode 100644
index 85ab1e889..000000000
--- a/assets/auto_link_deep_dependencies/src/internal_inc/never_compiled.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef NEVER_COMPILED_H
-#define NEVER_COMPILED_H
-
-int function_never_compiled(int x);
-
-#endif /* NEVER_COMPILED_H */
\ No newline at end of file
diff --git a/assets/auto_link_deep_dependencies/src/never_compiled.c b/assets/auto_link_deep_dependencies/src/never_compiled.c
deleted file mode 100644
index 2e282bca0..000000000
--- a/assets/auto_link_deep_dependencies/src/never_compiled.c
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "never_compiled.h"
-
-int function_never_compiled(int x)
-{
- never runed function
-}
\ No newline at end of file
diff --git a/assets/auto_link_deep_dependencies/test/test_a.c b/assets/auto_link_deep_dependencies/test/test_a.c
deleted file mode 100644
index 2fc6afbeb..000000000
--- a/assets/auto_link_deep_dependencies/test/test_a.c
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "unity.h"
-#include "a.h"
-#include "mock_never_compiled.h"
-
-void setUp(void) {}
-void tearDown(void) {}
-
-void test_function_from_a_should_return_16(void) {
- function_never_compiled_ExpectAndReturn(2, 2);
- TEST_ASSERT_EQUAL(16, function_from_a(2));
-}
diff --git a/assets/auto_link_deep_dependencies/test/test_b.c b/assets/auto_link_deep_dependencies/test/test_b.c
deleted file mode 100644
index 82a36555a..000000000
--- a/assets/auto_link_deep_dependencies/test/test_b.c
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "unity.h"
-#include "b.h"
-#include "mock_never_compiled.h"
-
-void setUp(void) {}
-void tearDown(void) {}
-
-void test_function_from_b_should_return_8(void) {
- function_never_compiled_ExpectAndReturn(2, 2);
- TEST_ASSERT_EQUAL(8, function_from_b(2));
-}
diff --git a/assets/auto_link_deep_dependencies/test/test_c.c b/assets/auto_link_deep_dependencies/test/test_c.c
deleted file mode 100644
index ac8b2d651..000000000
--- a/assets/auto_link_deep_dependencies/test/test_c.c
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "unity.h"
-#include "c.h"
-#include "mock_never_compiled.h"
-
-void setUp(void) {}
-void tearDown(void) {}
-
-void test_function_from_c_should_return_4(void) {
- function_never_compiled_ExpectAndReturn(2, 2);
- TEST_ASSERT_EQUAL(4, function_from_c(2));
-}
diff --git a/assets/ceedling b/assets/ceedling
index 539308570..40cea2cd3 100755
--- a/assets/ceedling
+++ b/assets/ceedling
@@ -1,3 +1,9 @@
#!/bin/bash
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
ruby vendor/ceedling/bin/ceedling $*
diff --git a/assets/default_gitignore b/assets/default_gitignore
index a9ebca2cf..492412d9f 100644
--- a/assets/default_gitignore
+++ b/assets/default_gitignore
@@ -1,5 +1,7 @@
-build/artifacts
-build/gcov
-build/logs
-build/temp
-build/test
+# Ignore the build/ directory in the root of the project.
+# Generally speaking, best practice is to omit generated files from revision control.
+/build/
+
+# But reserve the artifacts/ subdirectory for revision control.
+# Ceedling's notion of artifacts includes reports or release binaries you *may* want to revision.
+!/build/artifacts/
diff --git a/assets/example_file.c b/assets/example_file.c
index a50ae4bbe..631d5fefa 100644
--- a/assets/example_file.c
+++ b/assets/example_file.c
@@ -1,5 +1,16 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
#include "example_file.h"
int add_numbers(int a, int b) {
return a + b;
}
+
+int difference_between_numbers(int a, int b) {
+ return a - b;
+}
diff --git a/assets/example_file.h b/assets/example_file.h
index dab6ee8bf..2e52d9827 100644
--- a/assets/example_file.h
+++ b/assets/example_file.h
@@ -1,6 +1,15 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
#ifndef EXAMPLE_FILE_H
#define EXAMPLE_FILE_H
int add_numbers(int a, int b);
+int difference_between_numbers(int a, int b);
+
#endif /* EXAMPLE_FILE_H */
diff --git a/assets/example_file_call.c b/assets/example_file_call.c
index 9c3583798..00da661b8 100644
--- a/assets/example_file_call.c
+++ b/assets/example_file_call.c
@@ -1,3 +1,10 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
#include "example_file_call.h"
#include "example_file.h"
diff --git a/assets/example_file_call.h b/assets/example_file_call.h
index a56815131..b1781f2e2 100644
--- a/assets/example_file_call.h
+++ b/assets/example_file_call.h
@@ -1,3 +1,10 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
#ifndef EXAMPLE_FILE_CALL_H
#define EXAMPLE_FILE_CALL_H
diff --git a/assets/project_as_gem.yml b/assets/project_as_gem.yml
index 0442db2f0..98b4d47cb 100644
--- a/assets/project_as_gem.yml
+++ b/assets/project_as_gem.yml
@@ -1,84 +1,216 @@
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
---
+:project:
+ # how to use ceedling. If you're not sure, leave this as `gem` and `?`
+ :which_ceedling: gem
+ :ceedling_version: '?'
-# Notes:
-# Sample project C code is not presently written to produce a release artifact.
-# As such, release build options are disabled.
-# This sample, therefore, only demonstrates running a collection of unit tests.
+ # optional features. If you don't need them, keep them turned off for performance
+ :use_mocks: TRUE
+ :use_test_preprocessor: :none
+ :use_backtrace: :simple
+ :use_decorators: :auto #Decorate Ceedling's output text. Your options are :auto, :all, or :none
-:project:
- :use_exceptions: FALSE
- :use_test_preprocessor: TRUE
- :use_auxiliary_dependencies: TRUE
+ # tweak the way ceedling handles automatic tasks
:build_root: build
-# :release_build: TRUE
:test_file_prefix: test_
- :which_ceedling: gem
- :ceedling_version: '?'
:default_tasks:
- test:all
-#:test_build:
-# :use_assembly: TRUE
+ # performance options. If your tools start giving mysterious errors, consider
+ # dropping this to 1 to force single-tasking
+ :test_threads: 8
+ :compile_threads: 8
+
+ # enable release build (more details in release_build section below)
+ :release_build: FALSE
+
+# Specify where to find mixins and any that should be enabled automatically
+:mixins:
+ :enabled: []
+ :load_paths: []
+
+# further details to configure the way Ceedling handles test code
+:test_build:
+ :use_assembly: FALSE
+
+# further details to configure the way Ceedling handles release code
+:release_build:
+ :output: MyApp.out
+ :use_assembly: FALSE
+ :artifacts: []
+
+# Plugins are optional Ceedling features which can be enabled. Ceedling supports
+# a variety of plugins which may effect the way things are compiled, reported,
+# or may provide new command options. Refer to the readme in each plugin for
+# details on how to use it.
+:plugins:
+ :load_paths: []
+ :enabled:
+ #- beep # beeps when finished, so you don't waste time waiting for ceedling
+ - module_generator # handy for quickly creating source, header, and test templates
+ #- gcov # test coverage using gcov. Requires gcc, gcov, and a coverage analyzer like gcovr
+ #- bullseye # test coverage using bullseye. Requires bullseye for your platform
+ #- command_hooks # write custom actions to be called at different points during the build process
+ #- compile_commands_json_db # generate a compile_commands.json file
+ #- dependencies # automatically fetch 3rd party libraries, etc.
+ #- subprojects # managing builds and test for static libraries
+ #- fake_function_framework # use FFF instead of CMock
-#:release_build:
-# :output: MyApp.out
-# :use_assembly: FALSE
+ # Report options (You'll want to choose one stdout option, but may choose multiple stored options if desired)
+ #- report_build_warnings_log
+ #- report_tests_gtestlike_stdout
+ #- report_tests_ide_stdout
+ #- report_tests_log_factory
+ - report_tests_pretty_stdout
+ #- report_tests_raw_output_log
+ #- report_tests_teamcity_stdout
-:environment:
+# Specify which reports you'd like from the log factory
+:report_tests_log_factory:
+ :reports:
+ - json
+ - junit
+ - cppunit
+ - html
+# override the default extensions for your system and toolchain
:extension:
+ #:header: .h
+ #:source: .c
+ #:assembly: .s
+ #:dependencies: .d
+ #:object: .o
:executable: .out
+ #:testpass: .pass
+ #:testfail: .fail
+ #:subprojects: .a
+# This is where Ceedling should look for your source and test files.
+# see documentation for the many options for specifying this.
:paths:
:test:
- +:test/**
- -:test/support
:source:
- src/**
+ :include:
+ - src/** # In simple projects, this entry often duplicates :source
:support:
- test/support
:libraries: []
+# You can even specify specific files to add or remove from your test
+# and release collections. Usually it's better to use paths and let
+# Ceedling do the work for you!
+:files:
+ :test: []
+ :source: []
+
+# Compilation symbols to be injected into builds
+# See documentation for advanced options:
+# - Test name matchers for different symbols per test executable build
+# - Referencing symbols in multiple lists using advanced YAML
+# - Specifiying symbols used during test preprocessing
:defines:
- # in order to add common defines:
- # 1) remove the trailing [] from the :common: section
- # 2) add entries to the :common: section (e.g. :test: has TEST defined)
- :common: &common_defines []
:test:
- - *common_defines
- - TEST
- :test_preprocess:
- - *common_defines
- - TEST
+ - TEST # Simple list option to add symbol 'TEST' to compilation of all files in all test executables
+ :release: []
+ # Enable to inject name of a test as a unique compilation symbol into its respective executable build.
+ :use_test_definition: FALSE
+
+# Configure additional command line flags provided to tools used in each build step
+# :flags:
+# :release:
+# :compile: # Add '-Wall' and '--02' to compilation of all files in release target
+# - -Wall
+# - --O2
+# :test:
+# :compile:
+# '(_|-)special': # Add '-pedantic' to compilation of all files in all test executables with '_special' or '-special' in their names
+# - -pedantic
+# '*': # Add '-foo' to compilation of all files in all test executables
+# - -foo
+
+# Configuration Options specific to CMock. See CMock docs for details
:cmock:
- :mock_prefix: mock_
- :when_no_prototypes: :warn
- :enforce_strict_ordering: TRUE
- :plugins:
+ # Core conffiguration
+ :plugins: # What plugins should be used by CMock?
- :ignore
- :callback
- :treat_as:
+ :verbosity: 2 # the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose
+ :when_no_prototypes: :warn # the options being :ignore, :warn, or :erro
+
+ # File configuration
+ :skeleton_path: '' # Subdirectory to store stubs when generated (default: '')
+ :mock_prefix: 'mock_' # Prefix to append to filenames for mocks
+ :mock_suffix: '' # Suffix to append to filenames for mocks
+
+ # Parser configuration
+ :strippables: ['(?:__attribute__\s*\([ (]*.*?[ )]*\)+)']
+ :attributes:
+ - __ramfunc
+ - __irq
+ - __fiq
+ - register
+ - extern
+ :c_calling_conventions:
+ - __stdcall
+ - __cdecl
+ - __fastcall
+ :treat_externs: :exclude # the options being :include or :exclud
+ :treat_inlines: :exclude # the options being :include or :exclud
+
+ # Type handling configuration
+ #:unity_helper_path: '' # specify a string of where to find a unity_helper.h file to discover custom type assertions
+ :treat_as: # optionally add additional types to map custom types
uint8: HEX8
uint16: HEX16
uint32: UINT32
int8: INT8
bool: UINT8
+ #:treat_as_array: {} # hint to cmock that these types are pointers to something
+ #:treat_as_void: [] # hint to cmock that these types are actually aliases of void
+ :memcmp_if_unknown: true # allow cmock to use the memory comparison assertions for unknown types
+ :when_ptr: :compare_data # hint to cmock how to handle pointers in general, the options being :compare_ptr, :compare_data, or :smart
-# Add -gcov to the plugins list to make sure of the gcov plugin
-# You will need to have gcov and gcovr both installed to make it work.
-# For more information on these options, see docs in plugins/gcov
-:gcov:
- :reports:
- - HtmlDetailed
- :gcovr:
- :html_medium_threshold: 75
- :html_high_threshold: 90
+ # Mock generation configuration
+ :weak: '' # Symbol to use to declare weak functions
+ :enforce_strict_ordering: true # Do we want cmock to enforce ordering of all function calls?
+ :fail_on_unexpected_calls: true # Do we want cmock to fail when it encounters a function call that wasn't expected?
+ :callback_include_count: true # Do we want cmock to include the number of calls to this callback, when using callbacks?
+ :callback_after_arg_check: false # Do we want cmock to enforce an argument check first when using a callback?
+ #:includes: [] # You can add additional includes here, or specify the location with the options below
+ #:includes_h_pre_orig_header: []
+ #:includes_h_post_orig_header: []
+ #:includes_c_pre_header: []
+ #:includes_c_post_header: []
+ #:array_size_type: [] # Specify a type or types that should be used for array lengths
+ #:array_size_name: 'size|len' # Specify a name or names that CMock might automatically recognize as the length of an array
+ :exclude_setjmp_h: false # Don't use setjmp when running CMock. Note that this might result in late reporting or out-of-order failures.
-#:tools:
-# Ceedling defaults to using gcc for compiling, linking, etc.
-# As [:tools] is blank, gcc will be used (so long as it's in your system path)
-# See documentation to configure a given toolchain for use
+# Configuration options specific to Unity.
+:unity:
+ :defines:
+ - UNITY_EXCLUDE_FLOAT
+
+# You can optionally have ceedling create environment variables for you before
+# performing the rest of its tasks.
+:environment: []
+# :environment:
+# # List enforces order allowing later to reference earlier with inline Ruby substitution
+# - :var1: value
+# - :var2: another value
+# - :path: # Special PATH handling with platform-specific path separators
+# - #{ENV['PATH']} # Environment variables can use inline Ruby substitution
+# - /another/path/to/include
# LIBRARIES
# These libraries are automatically injected into the build process. Those specified as
@@ -92,10 +224,187 @@
:test: []
:release: []
-:plugins:
- :load_paths:
- - "#{Ceedling.load_path}"
- :enabled:
- - stdout_pretty_tests_report
- - module_generator
+################################################################
+# PLUGIN CONFIGURATION
+################################################################
+
+# Add -gcov to the plugins list to make sure of the gcov plugin
+# You will need to have gcov and gcovr both installed to make it work.
+# For more information on these options, see docs in plugins/gcov
+:gcov:
+ :summaries: TRUE # Enable simple coverage summaries to console after tests
+ :report_task: FALSE # Disabled dedicated report generation task (this enables automatic report generation)
+ :utilities:
+ - gcovr # Use gcovr to create the specified reports (default).
+ #- ReportGenerator # Use ReportGenerator to create the specified reports.
+ :reports: # Specify one or more reports to generate.
+ # Make an HTML summary report.
+ - HtmlBasic
+ # - HtmlDetailed
+ # - Text
+ # - Cobertura
+ # - SonarQube
+ # - JSON
+ # - HtmlInline
+ # - HtmlInlineAzure
+ # - HtmlInlineAzureDark
+ # - HtmlChart
+ # - MHtml
+ # - Badges
+ # - CsvSummary
+ # - Latex
+ # - LatexSummary
+ # - PngChart
+ # - TeamCitySummary
+ # - lcov
+ # - Xml
+ # - XmlSummary
+ :gcovr:
+ # :html_artifact_filename: TestCoverageReport.html
+ # :html_title: Test Coverage Report
+ :html_medium_threshold: 75
+ :html_high_threshold: 90
+ # :html_absolute_paths: TRUE
+ # :html_encoding: UTF-8
+
+# :module_generator:
+# :project_root: ./
+# :source_root: source/
+# :inc_root: includes/
+# :test_root: tests/
+# :naming: :snake #options: :bumpy, :camel, :caps, or :snake
+# :includes:
+# :tst: []
+# :src: []
+# :boilerplates:
+# :src: ""
+# :inc: ""
+# :tst: ""
+
+# :dependencies:
+# :libraries:
+# - :name: WolfSSL
+# :source_path: third_party/wolfssl/source
+# :build_path: third_party/wolfssl/build
+# :artifact_path: third_party/wolfssl/install
+# :fetch:
+# :method: :zip
+# :source: \\shared_drive\third_party_libs\wolfssl\wolfssl-4.2.0.zip
+# :environment:
+# - CFLAGS+=-DWOLFSSL_DTLS_ALLOW_FUTURE
+# :build:
+# - "autoreconf -i"
+# - "./configure --enable-tls13 --enable-singlethreaded"
+# - make
+# - make install
+# :artifacts:
+# :static_libraries:
+# - lib/wolfssl.a
+# :dynamic_libraries:
+# - lib/wolfssl.so
+# :includes:
+# - include/**
+
+# :subprojects:
+# :paths:
+# - :name: libprojectA
+# :source:
+# - ./subprojectA/source
+# :include:
+# - ./subprojectA/include
+# :build_root: ./subprojectA/build
+# :defines: []
+
+# :command_hooks:
+# :pre_mock_preprocess:
+# :post_mock_preprocess:
+# :pre_test_preprocess:
+# :post_test_preprocess:
+# :pre_mock_generate:
+# :post_mock_generate:
+# :pre_runner_generate:
+# :post_runner_generate:
+# :pre_compile_execute:
+# :post_compile_execute:
+# :pre_link_execute:
+# :post_link_execute:
+# :pre_test_fixture_execute:
+# :post_test_fixture_execute:
+# :pre_test:
+# :post_test:
+# :pre_release:
+# :post_release:
+# :pre_build:
+# :post_build:
+# :post_error:
+
+################################################################
+# TOOLCHAIN CONFIGURATION
+################################################################
+
+#:tools:
+# Ceedling defaults to using gcc for compiling, linking, etc.
+# As [:tools] is blank, gcc will be used (so long as it's in your system path)
+# See documentation to configure a given toolchain for use
+# :tools:
+# :test_compiler:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :test_linker:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :test_assembler:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :test_fixture:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :test_includes_preprocessor:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :test_file_preprocessor:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :test_file_preprocessor_directives:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :test_dependencies_generator:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :release_compiler:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :release_linker:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :release_assembler:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :release_dependencies_generator:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
...
diff --git a/assets/project_with_guts.yml b/assets/project_with_guts.yml
index cb1086fb3..19309b8fe 100644
--- a/assets/project_with_guts.yml
+++ b/assets/project_with_guts.yml
@@ -1,84 +1,216 @@
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
---
+:project:
+ # how to use ceedling. If you're not sure, leave this as `gem` and `?`
+ :which_ceedling: vendor/ceedling
+ :ceedling_version: '?'
-# Notes:
-# Sample project C code is not presently written to produce a release artifact.
-# As such, release build options are disabled.
-# This sample, therefore, only demonstrates running a collection of unit tests.
+ # optional features. If you don't need them, keep them turned off for performance
+ :use_mocks: TRUE
+ :use_test_preprocessor: :none
+ :use_backtrace: :simple
+ :use_decorators: :auto #Decorate Ceedling's output text. Your options are :auto, :all, or :none
-:project:
- :use_exceptions: FALSE
- :use_test_preprocessor: TRUE
- :use_auxiliary_dependencies: TRUE
+ # tweak the way ceedling handles automatic tasks
:build_root: build
-# :release_build: TRUE
:test_file_prefix: test_
- :which_ceedling: vendor/ceedling
- :ceedling_version: '?'
:default_tasks:
- test:all
-#:test_build:
-# :use_assembly: TRUE
+ # performance options. If your tools start giving mysterious errors, consider
+ # dropping this to 1 to force single-tasking
+ :test_threads: 8
+ :compile_threads: 8
+
+ # enable release build (more details in release_build section below)
+ :release_build: FALSE
-#:release_build:
-# :output: MyApp.out
-# :use_assembly: FALSE
+# Specify where to find mixins and any that should be enabled automatically
+:mixins:
+ :enabled: []
+ :load_paths: []
-:environment:
+# further details to configure the way Ceedling handles test code
+:test_build:
+ :use_assembly: FALSE
+
+# further details to configure the way Ceedling handles release code
+:release_build:
+ :output: MyApp.out
+ :use_assembly: FALSE
+ :artifacts: []
+
+# Plugins are optional Ceedling features which can be enabled. Ceedling supports
+# a variety of plugins which may effect the way things are compiled, reported,
+# or may provide new command options. Refer to the readme in each plugin for
+# details on how to use it.
+:plugins:
+ :load_paths: []
+ :enabled:
+ #- beep # beeps when finished, so you don't waste time waiting for ceedling
+ - module_generator # handy for quickly creating source, header, and test templates
+ #- gcov # test coverage using gcov. Requires gcc, gcov, and a coverage analyzer like gcovr
+ #- bullseye # test coverage using bullseye. Requires bullseye for your platform
+ #- command_hooks # write custom actions to be called at different points during the build process
+ #- compile_commands_json_db # generate a compile_commands.json file
+ #- dependencies # automatically fetch 3rd party libraries, etc.
+ #- subprojects # managing builds and test for static libraries
+ #- fake_function_framework # use FFF instead of CMock
+
+ # Report options (You'll want to choose one stdout option, but may choose multiple stored options if desired)
+ #- report_build_warnings_log
+ #- report_tests_gtestlike_stdout
+ #- report_tests_ide_stdout
+ #- report_tests_log_factory
+ - report_tests_pretty_stdout
+ #- report_tests_raw_output_log
+ #- report_tests_teamcity_stdout
+
+# Specify which reports you'd like from the log factory
+:report_tests_log_factory:
+ :reports:
+ - json
+ - junit
+ - cppunit
+ - html
+# override the default extensions for your system and toolchain
:extension:
+ #:header: .h
+ #:source: .c
+ #:assembly: .s
+ #:dependencies: .d
+ #:object: .o
:executable: .out
+ #:testpass: .pass
+ #:testfail: .fail
+ #:subprojects: .a
+# This is where Ceedling should look for your source and test files.
+# see documentation for the many options for specifying this.
:paths:
:test:
- +:test/**
- -:test/support
:source:
- src/**
+ :include:
+ - src/** # In simple projects, this entry often duplicates :source
:support:
- test/support
:libraries: []
+# You can even specify specific files to add or remove from your test
+# and release collections. Usually it's better to use paths and let
+# Ceedling do the work for you!
+:files:
+ :test: []
+ :source: []
+
+# Compilation symbols to be injected into builds
+# See documentation for advanced options:
+# - Test name matchers for different symbols per test executable build
+# - Referencing symbols in multiple lists using advanced YAML
+# - Specifiying symbols used during test preprocessing
:defines:
- # in order to add common defines:
- # 1) remove the trailing [] from the :common: section
- # 2) add entries to the :common: section (e.g. :test: has TEST defined)
- :common: &common_defines []
:test:
- - *common_defines
- - TEST
- :test_preprocess:
- - *common_defines
- - TEST
+ - TEST # Simple list option to add symbol 'TEST' to compilation of all files in all test executables
+ :release: []
+
+ # Enable to inject name of a test as a unique compilation symbol into its respective executable build.
+ :use_test_definition: FALSE
+# Configure additional command line flags provided to tools used in each build step
+# :flags:
+# :release:
+# :compile: # Add '-Wall' and '--02' to compilation of all files in release target
+# - -Wall
+# - --O2
+# :test:
+# :compile:
+# '(_|-)special': # Add '-pedantic' to compilation of all files in all test executables with '_special' or '-special' in their names
+# - -pedantic
+# '*': # Add '-foo' to compilation of all files in all test executables
+# - -foo
+
+# Configuration Options specific to CMock. See CMock docs for details
:cmock:
- :mock_prefix: mock_
- :when_no_prototypes: :warn
- :enforce_strict_ordering: TRUE
- :plugins:
+ # Core conffiguration
+ :plugins: # What plugins should be used by CMock?
- :ignore
- :callback
- :treat_as:
+ :verbosity: 2 # the options being 0 errors only, 1 warnings and errors, 2 normal info, 3 verbose
+ :when_no_prototypes: :warn # the options being :ignore, :warn, or :erro
+
+ # File configuration
+ :skeleton_path: '' # Subdirectory to store stubs when generated (default: '')
+ :mock_prefix: 'mock_' # Prefix to append to filenames for mocks
+ :mock_suffix: '' # Suffix to append to filenames for mocks
+
+ # Parser configuration
+ :strippables: ['(?:__attribute__\s*\([ (]*.*?[ )]*\)+)']
+ :attributes:
+ - __ramfunc
+ - __irq
+ - __fiq
+ - register
+ - extern
+ :c_calling_conventions:
+ - __stdcall
+ - __cdecl
+ - __fastcall
+ :treat_externs: :exclude # the options being :include or :exclud
+ :treat_inlines: :exclude # the options being :include or :exclud
+
+ # Type handling configuration
+ #:unity_helper_path: '' # specify a string of where to find a unity_helper.h file to discover custom type assertions
+ :treat_as: # optionally add additional types to map custom types
uint8: HEX8
uint16: HEX16
uint32: UINT32
int8: INT8
bool: UINT8
+ #:treat_as_array: {} # hint to cmock that these types are pointers to something
+ #:treat_as_void: [] # hint to cmock that these types are actually aliases of void
+ :memcmp_if_unknown: true # allow cmock to use the memory comparison assertions for unknown types
+ :when_ptr: :compare_data # hint to cmock how to handle pointers in general, the options being :compare_ptr, :compare_data, or :smart
-# Add -gcov to the plugins list to make sure of the gcov plugin
-# You will need to have gcov and gcovr both installed to make it work.
-# For more information on these options, see docs in plugins/gcov
-:gcov:
- :reports:
- - HtmlDetailed
- :gcovr:
- :html_medium_threshold: 75
- :html_high_threshold: 90
+ # Mock generation configuration
+ :weak: '' # Symbol to use to declare weak functions
+ :enforce_strict_ordering: true # Do we want cmock to enforce ordering of all function calls?
+ :fail_on_unexpected_calls: true # Do we want cmock to fail when it encounters a function call that wasn't expected?
+ :callback_include_count: true # Do we want cmock to include the number of calls to this callback, when using callbacks?
+ :callback_after_arg_check: false # Do we want cmock to enforce an argument check first when using a callback?
+ #:includes: [] # You can add additional includes here, or specify the location with the options below
+ #:includes_h_pre_orig_header: []
+ #:includes_h_post_orig_header: []
+ #:includes_c_pre_header: []
+ #:includes_c_post_header: []
+ #:array_size_type: [] # Specify a type or types that should be used for array lengths
+ #:array_size_name: 'size|len' # Specify a name or names that CMock might automatically recognize as the length of an array
+ :exclude_setjmp_h: false # Don't use setjmp when running CMock. Note that this might result in late reporting or out-of-order failures.
-#:tools:
-# Ceedling defaults to using gcc for compiling, linking, etc.
-# As [:tools] is blank, gcc will be used (so long as it's in your system path)
-# See documentation to configure a given toolchain for use
+# Configuration options specific to Unity.
+:unity:
+ :defines:
+ - UNITY_EXCLUDE_FLOAT
+
+# You can optionally have ceedling create environment variables for you before
+# performing the rest of its tasks.
+:environment: []
+# :environment:
+# # List enforces order allowing later to reference earlier with inline Ruby substitution
+# - :var1: value
+# - :var2: another value
+# - :path: # Special PATH handling with platform-specific path separators
+# - #{ENV['PATH']} # Environment variables can use inline Ruby substitution
+# - /another/path/to/include
# LIBRARIES
# These libraries are automatically injected into the build process. Those specified as
@@ -92,11 +224,188 @@
:test: []
:release: []
-:plugins:
- :load_paths:
- - vendor/ceedling/plugins
- :enabled:
- - stdout_pretty_tests_report
- - module_generator
- - raw_output_report
+################################################################
+# PLUGIN CONFIGURATION
+################################################################
+
+# Add -gcov to the plugins list to make sure of the gcov plugin
+# You will need to have gcov and gcovr both installed to make it work.
+# For more information on these options, see docs in plugins/gcov
+:gcov:
+ :summaries: TRUE # Enable simple coverage summaries to console after tests
+ :report_task: FALSE # Disabled dedicated report generation task (this enables automatic report generation)
+ :utilities:
+ - gcovr # Use gcovr to create the specified reports (default).
+ #- ReportGenerator # Use ReportGenerator to create the specified reports.
+ :reports: # Specify one or more reports to generate.
+ # Make an HTML summary report.
+ - HtmlBasic
+ # - HtmlDetailed
+ # - Text
+ # - Cobertura
+ # - SonarQube
+ # - JSON
+ # - HtmlInline
+ # - HtmlInlineAzure
+ # - HtmlInlineAzureDark
+ # - HtmlChart
+ # - MHtml
+ # - Badges
+ # - CsvSummary
+ # - Latex
+ # - LatexSummary
+ # - PngChart
+ # - TeamCitySummary
+ # - lcov
+ # - Xml
+ # - XmlSummary
+ :gcovr:
+ # :html_artifact_filename: TestCoverageReport.html
+ # :html_title: Test Coverage Report
+ :html_medium_threshold: 75
+ :html_high_threshold: 90
+ # :html_absolute_paths: TRUE
+ # :html_encoding: UTF-8
+
+# :module_generator:
+# :project_root: ./
+# :source_root: source/
+# :inc_root: includes/
+# :test_root: tests/
+# :naming: :snake #options: :bumpy, :camel, :caps, or :snake
+# :includes:
+# :tst: []
+# :src: []
+# :boilerplates:
+# :src: ""
+# :inc: ""
+# :tst: ""
+
+# :dependencies:
+# :libraries:
+# - :name: WolfSSL
+# :source_path: third_party/wolfssl/source
+# :build_path: third_party/wolfssl/build
+# :artifact_path: third_party/wolfssl/install
+# :fetch:
+# :method: :zip
+# :source: \\shared_drive\third_party_libs\wolfssl\wolfssl-4.2.0.zip
+# :environment:
+# - CFLAGS+=-DWOLFSSL_DTLS_ALLOW_FUTURE
+# :build:
+# - "autoreconf -i"
+# - "./configure --enable-tls13 --enable-singlethreaded"
+# - make
+# - make install
+# :artifacts:
+# :static_libraries:
+# - lib/wolfssl.a
+# :dynamic_libraries:
+# - lib/wolfssl.so
+# :includes:
+# - include/**
+
+# :subprojects:
+# :paths:
+# - :name: libprojectA
+# :source:
+# - ./subprojectA/source
+# :include:
+# - ./subprojectA/include
+# :build_root: ./subprojectA/build
+# :defines: []
+
+# :command_hooks:
+# :pre_mock_preprocess:
+# :post_mock_preprocess:
+# :pre_test_preprocess:
+# :post_test_preprocess:
+# :pre_mock_generate:
+# :post_mock_generate:
+# :pre_runner_generate:
+# :post_runner_generate:
+# :pre_compile_execute:
+# :post_compile_execute:
+# :pre_link_execute:
+# :post_link_execute:
+# :pre_test_fixture_execute:
+# :post_test_fixture_execute:
+# :pre_test:
+# :post_test:
+# :pre_release:
+# :post_release:
+# :pre_build:
+# :post_build:
+# :post_error:
+
+################################################################
+# TOOLCHAIN CONFIGURATION
+################################################################
+
+
+#:tools:
+# Ceedling defaults to using gcc for compiling, linking, etc.
+# As [:tools] is blank, gcc will be used (so long as it's in your system path)
+# See documentation to configure a given toolchain for use
+# :tools:
+# :test_compiler:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :test_linker:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :test_assembler:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :test_fixture:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :test_includes_preprocessor:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :test_file_preprocessor:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :test_file_preprocessor_directives:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :test_dependencies_generator:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :release_compiler:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :release_linker:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :release_assembler:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
+# :release_dependencies_generator:
+# :executable:
+# :arguments: []
+# :name:
+# :optional: FALSE
...
diff --git a/assets/project_with_guts_gcov.yml b/assets/project_with_guts_gcov.yml
deleted file mode 100644
index 29418a1cd..000000000
--- a/assets/project_with_guts_gcov.yml
+++ /dev/null
@@ -1,102 +0,0 @@
----
-
-# Notes:
-# Sample project C code is not presently written to produce a release artifact.
-# As such, release build options are disabled.
-# This sample, therefore, only demonstrates running a collection of unit tests.
-
-:project:
- :use_exceptions: FALSE
- :use_test_preprocessor: TRUE
- :use_auxiliary_dependencies: TRUE
- :build_root: build
-# :release_build: TRUE
- :test_file_prefix: test_
- :which_ceedling: vendor/ceedling
- :ceedling_version: '?'
- :default_tasks:
- - test:all
-
-#:test_build:
-# :use_assembly: TRUE
-
-#:release_build:
-# :output: MyApp.out
-# :use_assembly: FALSE
-
-:environment:
-
-:extension:
- :executable: .out
-
-:paths:
- :test:
- - +:test/**
- - -:test/support
- :source:
- - src/**
- :support:
- - test/support
- :libraries: []
-
-:defines:
- # in order to add common defines:
- # 1) remove the trailing [] from the :common: section
- # 2) add entries to the :common: section (e.g. :test: has TEST defined)
- :common: &common_defines []
- :test:
- - *common_defines
- - TEST
- :test_preprocess:
- - *common_defines
- - TEST
-
-:cmock:
- :mock_prefix: mock_
- :when_no_prototypes: :warn
- :enforce_strict_ordering: TRUE
- :plugins:
- - :ignore
- - :callback
- :treat_as:
- uint8: HEX8
- uint16: HEX16
- uint32: UINT32
- int8: INT8
- bool: UINT8
-
-# Add -gcov to the plugins list to make sure of the gcov plugin
-# You will need to have gcov and gcovr both installed to make it work.
-# For more information on these options, see docs in plugins/gcov
-:gcov:
- :reports:
- - HtmlDetailed
- :gcovr:
- :html_medium_threshold: 75
- :html_high_threshold: 90
-
-#:tools:
-# Ceedling defaults to using gcc for compiling, linking, etc.
-# As [:tools] is blank, gcc will be used (so long as it's in your system path)
-# See documentation to configure a given toolchain for use
-
-# LIBRARIES
-# These libraries are automatically injected into the build process. Those specified as
-# common will be used in all types of builds. Otherwise, libraries can be injected in just
-# tests or releases. These options are MERGED with the options in supplemental yaml files.
-:libraries:
- :placement: :end
- :flag: "-l${1}"
- :path_flag: "-L ${1}"
- :system: [] # for example, you might list 'm' to grab the math library
- :test: []
- :release: []
-
-:plugins:
- :load_paths:
- - vendor/ceedling/plugins
- :enabled:
- - stdout_pretty_tests_report
- - module_generator
- - gcov
-...
diff --git a/assets/test_example_file.c b/assets/test_example_file.c
index e8378aa54..7a43a7a96 100644
--- a/assets/test_example_file.c
+++ b/assets/test_example_file.c
@@ -1,3 +1,10 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
#include "unity.h"
#include "example_file.h"
@@ -5,9 +12,9 @@ void setUp(void) {}
void tearDown(void) {}
void test_add_numbers_adds_numbers(void) {
- TEST_ASSERT_EQUAL(2, add_numbers(1,1));
+ TEST_ASSERT_EQUAL_INT(2, add_numbers(1,1));
}
void test_add_numbers_will_fail(void) {
- TEST_ASSERT_EQUAL(2, add_numbers(2,2));
+ TEST_ASSERT_EQUAL_INT(2, add_numbers(2,2));
}
diff --git a/assets/test_example_file_boom.c b/assets/test_example_file_boom.c
index 1365296b9..fd2b64bc4 100644
--- a/assets/test_example_file_boom.c
+++ b/assets/test_example_file_boom.c
@@ -1,3 +1,10 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
#include "unity.h"
#include "example_file.h"
@@ -5,9 +12,9 @@ void setUp(void) {}
void tearDown(void) {}
void test_add_numbers_adds_numbers(void) {
- TEST_ASSERT_EQUAL(2, add_numbers(1,1) //Removed semicolon & parenthesis to make a compile error.
+ TEST_ASSERT_EQUAL_INT(2, add_numbers(1,1) //Removed semicolon & parenthesis to make a compile error.
}
void test_add_numbers_will_fail(void) {
- TEST_ASSERT_EQUAL(2, add_numbers(2,2));
+ TEST_ASSERT_EQUAL_INT(2, add_numbers(2,2));
}
diff --git a/assets/test_example_file_crash.c b/assets/test_example_file_crash.c
new file mode 100644
index 000000000..dcc86066a
--- /dev/null
+++ b/assets/test_example_file_crash.c
@@ -0,0 +1,25 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
+#include
+#include "unity.h"
+#include "example_file.h"
+
+
+void setUp(void) {}
+void tearDown(void) {}
+
+void test_add_numbers_adds_numbers(void) {
+ TEST_ASSERT_EQUAL_INT(2, add_numbers(1,1));
+}
+
+void test_add_numbers_will_fail(void) {
+ // Platform-independent way of forcing a crash
+ uint32_t* nullptr = (void*) 0;
+ uint32_t i = *nullptr;
+ TEST_ASSERT_EQUAL_INT(2, add_numbers(i,2));
+}
diff --git a/assets/test_example_file_sigsegv.c b/assets/test_example_file_sigsegv.c
deleted file mode 100644
index 8ac1aef8d..000000000
--- a/assets/test_example_file_sigsegv.c
+++ /dev/null
@@ -1,16 +0,0 @@
-#include
-#include "unity.h"
-#include "example_file.h"
-
-
-void setUp(void) {}
-void tearDown(void) {}
-
-void test_add_numbers_adds_numbers(void) {
- TEST_ASSERT_EQUAL(2, add_numbers(1,1));
-}
-
-void test_add_numbers_will_fail(void) {
- raise(SIGSEGV);
- TEST_ASSERT_EQUAL(2, add_numbers(2,2));
-}
diff --git a/assets/test_example_file_success.c b/assets/test_example_file_success.c
index 4bc326492..6800dfd8d 100644
--- a/assets/test_example_file_success.c
+++ b/assets/test_example_file_success.c
@@ -1,3 +1,10 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
#include "unity.h"
#include "example_file.h"
@@ -5,10 +12,10 @@ void setUp(void) {}
void tearDown(void) {}
void test_add_numbers_adds_numbers(void) {
- TEST_ASSERT_EQUAL(2, add_numbers(1,1));
+ TEST_ASSERT_EQUAL_INT(2, add_numbers(1,1));
}
void test_add_numbers_will_fail_but_is_ignored_for_now(void) {
TEST_IGNORE();
- TEST_ASSERT_EQUAL(2, add_numbers(2,2));
+ TEST_ASSERT_EQUAL_INT(2, add_numbers(2,2));
}
diff --git a/assets/test_example_file_unity_printf.c b/assets/test_example_file_unity_printf.c
index 0aee87345..b87da5434 100644
--- a/assets/test_example_file_unity_printf.c
+++ b/assets/test_example_file_unity_printf.c
@@ -1,3 +1,10 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
#include "unity.h"
#include "example_file.h"
#include
@@ -7,6 +14,6 @@ void tearDown(void) {}
void test_add_numbers_adds_numbers(void) {
TEST_PRINTF("1 + 1 =%d", 1 + 1);
- TEST_ASSERT_EQUAL(2, add_numbers(1,1));
+ TEST_ASSERT_EQUAL_INT(2, add_numbers(1,1));
}
diff --git a/assets/test_example_file_verbose.c b/assets/test_example_file_verbose.c
index 9e50ea622..63d2f3819 100644
--- a/assets/test_example_file_verbose.c
+++ b/assets/test_example_file_verbose.c
@@ -1,3 +1,10 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
#include "unity.h"
#include "example_file.h"
#include
@@ -7,6 +14,6 @@ void tearDown(void) {}
void test_add_numbers_adds_numbers(void) {
printf("1 + 1 = 2\n");
- TEST_ASSERT_EQUAL(2, add_numbers(1,1));
+ TEST_ASSERT_EQUAL_INT(2, add_numbers(1,1));
}
diff --git a/assets/test_example_file_with_mock.c b/assets/test_example_file_with_mock.c
index f9e270be1..c3748ccf0 100644
--- a/assets/test_example_file_with_mock.c
+++ b/assets/test_example_file_with_mock.c
@@ -1,3 +1,10 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
#include "unity.h"
#include "example_file_call.h"
// mock header should have higher priority than real file
@@ -9,5 +16,5 @@ void tearDown(void) {}
void test_add_numbers_adds_numbers(void) {
add_numbers_ExpectAndReturn(1, 1, 2);
- TEST_ASSERT_EQUAL(2, call_add_numbers(1, 1));
+ TEST_ASSERT_EQUAL_INT(2, call_add_numbers(1, 1));
}
diff --git a/assets/test_example_with_parameterized_tests.c b/assets/test_example_with_parameterized_tests.c
index 3b511db62..9912bc3c6 100644
--- a/assets/test_example_with_parameterized_tests.c
+++ b/assets/test_example_with_parameterized_tests.c
@@ -1,7 +1,11 @@
-#include "unity.h"
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
-#define TEST_CASE(...)
-#define TEST_RANGE(...)
+#include "unity.h"
void setUp(void) {}
void tearDown(void) {}
@@ -13,6 +17,11 @@ void test_should_handle_divisible_by_5_for_parameterized_test_case(int num) {
TEST_ASSERT_EQUAL_MESSAGE(0, (num % 5), "All The Values Are Divisible By 5");
}
+TEST_RANGE([5, 100, 5])
+void test_should_handle_divisible_by_5_for_parameterized_test_range(int num) {
+ TEST_ASSERT_EQUAL_MESSAGE(0, (num % 5), "All The Values Are Divisible By 5");
+}
+
TEST_RANGE([10, 100, 10], [5, 10, 5])
void test_should_handle_a_divisible_by_b_for_parameterized_test_range(int a, int b) {
TEST_ASSERT_EQUAL_MESSAGE(0, (a % b), "All The a Values Are Divisible By b");
diff --git a/assets/tests_with_defines/src/adc_hardware.c b/assets/tests_with_defines/src/adc_hardware.c
index 244dc6606..e316b9fb9 100644
--- a/assets/tests_with_defines/src/adc_hardware.c
+++ b/assets/tests_with_defines/src/adc_hardware.c
@@ -1,3 +1,10 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
#include "adc_hardware.h"
#include "adc_hardware_configurator.h"
@@ -5,7 +12,7 @@ void AdcHardware_Init(void)
{
#ifdef SPECIFIC_CONFIG
Adc_ResetSpec();
- #elif STANDARD_CONFIG
+ #elif defined(STANDARD_CONFIG)
Adc_Reset();
#endif
}
diff --git a/assets/tests_with_defines/src/adc_hardware.h b/assets/tests_with_defines/src/adc_hardware.h
index aee79daf7..7483ac99a 100644
--- a/assets/tests_with_defines/src/adc_hardware.h
+++ b/assets/tests_with_defines/src/adc_hardware.h
@@ -1,3 +1,10 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
#ifndef _ADCHARDWARE_H
#define _ADCHARDWARE_H
diff --git a/assets/tests_with_defines/src/adc_hardware_configurator.c b/assets/tests_with_defines/src/adc_hardware_configurator.c
index 0ea263c58..bd90c6397 100644
--- a/assets/tests_with_defines/src/adc_hardware_configurator.c
+++ b/assets/tests_with_defines/src/adc_hardware_configurator.c
@@ -1,10 +1,17 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
#include "adc_hardware_configurator.h"
#ifdef SPECIFIC_CONFIG
void Adc_ResetSpec(void)
{
}
-#elif STANDARD_CONFIG
+#elif defined(STANDARD_CONFIG)
void Adc_Reset(void)
{
}
diff --git a/assets/tests_with_defines/src/adc_hardware_configurator.h b/assets/tests_with_defines/src/adc_hardware_configurator.h
index 699eced8e..8a8fe8153 100644
--- a/assets/tests_with_defines/src/adc_hardware_configurator.h
+++ b/assets/tests_with_defines/src/adc_hardware_configurator.h
@@ -1,9 +1,16 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
#ifndef _ADCHARDWARECONFIGURATOR_H
#define _ADCHARDWARECONFIGURATOR_H
#ifdef SPECIFIC_CONFIG
void Adc_ResetSpec(void);
-#elif STANDARD_CONFIG
+#elif defined(STANDARD_CONFIG)
void Adc_Reset(void);
#endif
diff --git a/assets/tests_with_defines/test/test_adc_hardware.c b/assets/tests_with_defines/test/test_adc_hardware.c
index fa424dac4..260098f1d 100644
--- a/assets/tests_with_defines/test/test_adc_hardware.c
+++ b/assets/tests_with_defines/test/test_adc_hardware.c
@@ -1,3 +1,10 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
#include "unity.h"
#include "adc_hardware.h"
#include "mock_adc_hardware_configurator.h"
diff --git a/assets/tests_with_defines/test/test_adc_hardware_special.c b/assets/tests_with_defines/test/test_adc_hardware_special.c
index ef215d49d..fcc3e1f0c 100644
--- a/assets/tests_with_defines/test/test_adc_hardware_special.c
+++ b/assets/tests_with_defines/test/test_adc_hardware_special.c
@@ -1,3 +1,10 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
#include "unity.h"
#include "adc_hardware.h"
#include "mock_adc_hardware_configurator.h"
diff --git a/assets/tests_with_preprocessing/src/adc_hardwareA.c b/assets/tests_with_preprocessing/src/adc_hardwareA.c
new file mode 100644
index 000000000..4a28bbe49
--- /dev/null
+++ b/assets/tests_with_preprocessing/src/adc_hardwareA.c
@@ -0,0 +1,17 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
+#include "adc_hardwareA.h"
+#include "adc_hardware_configuratorA.h"
+
+void AdcHardware_Init(void)
+{
+ // Reusing outer test file preprocessing symbol to prevent linking failure
+ #ifdef PREPROCESSING_TESTS
+ Adc_Reset();
+ #endif
+}
diff --git a/assets/tests_with_preprocessing/src/adc_hardwareA.h b/assets/tests_with_preprocessing/src/adc_hardwareA.h
new file mode 100644
index 000000000..7483ac99a
--- /dev/null
+++ b/assets/tests_with_preprocessing/src/adc_hardwareA.h
@@ -0,0 +1,13 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
+#ifndef _ADCHARDWARE_H
+#define _ADCHARDWARE_H
+
+void AdcHardware_Init(void);
+
+#endif // _ADCHARDWARE_H
diff --git a/assets/tests_with_preprocessing/src/adc_hardwareB.c b/assets/tests_with_preprocessing/src/adc_hardwareB.c
new file mode 100644
index 000000000..0d3e1b2d3
--- /dev/null
+++ b/assets/tests_with_preprocessing/src/adc_hardwareB.c
@@ -0,0 +1,14 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
+#include "adc_hardwareB.h"
+#include "adc_hardware_configuratorB.h"
+
+void AdcHardware_Init(void)
+{
+ Adc_Reset();
+}
diff --git a/assets/tests_with_preprocessing/src/adc_hardwareB.h b/assets/tests_with_preprocessing/src/adc_hardwareB.h
new file mode 100644
index 000000000..7483ac99a
--- /dev/null
+++ b/assets/tests_with_preprocessing/src/adc_hardwareB.h
@@ -0,0 +1,13 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
+#ifndef _ADCHARDWARE_H
+#define _ADCHARDWARE_H
+
+void AdcHardware_Init(void);
+
+#endif // _ADCHARDWARE_H
diff --git a/assets/tests_with_preprocessing/src/adc_hardwareC.c b/assets/tests_with_preprocessing/src/adc_hardwareC.c
new file mode 100644
index 000000000..66f811595
--- /dev/null
+++ b/assets/tests_with_preprocessing/src/adc_hardwareC.c
@@ -0,0 +1,14 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
+#include "adc_hardwareC.h"
+#include "adc_hardware_configuratorC.h"
+
+void AdcHardware_Init(void)
+{
+ Adc_Reset();
+}
diff --git a/assets/tests_with_preprocessing/src/adc_hardwareC.h b/assets/tests_with_preprocessing/src/adc_hardwareC.h
new file mode 100644
index 000000000..7483ac99a
--- /dev/null
+++ b/assets/tests_with_preprocessing/src/adc_hardwareC.h
@@ -0,0 +1,13 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
+#ifndef _ADCHARDWARE_H
+#define _ADCHARDWARE_H
+
+void AdcHardware_Init(void);
+
+#endif // _ADCHARDWARE_H
diff --git a/assets/tests_with_preprocessing/src/adc_hardware_configuratorA.h b/assets/tests_with_preprocessing/src/adc_hardware_configuratorA.h
new file mode 100644
index 000000000..d474d0799
--- /dev/null
+++ b/assets/tests_with_preprocessing/src/adc_hardware_configuratorA.h
@@ -0,0 +1,13 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
+#ifndef _ADCHARDWARECONFIGURATOR_H
+#define _ADCHARDWARECONFIGURATOR_H
+
+void Adc_Reset(void);
+
+#endif // _ADCHARDWARECONFIGURATOR_H
diff --git a/assets/tests_with_preprocessing/src/adc_hardware_configuratorB.h b/assets/tests_with_preprocessing/src/adc_hardware_configuratorB.h
new file mode 100644
index 000000000..4b3ef81a3
--- /dev/null
+++ b/assets/tests_with_preprocessing/src/adc_hardware_configuratorB.h
@@ -0,0 +1,15 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
+#ifndef _ADCHARDWARECONFIGURATOR_H
+#define _ADCHARDWARECONFIGURATOR_H
+
+#ifdef PREPROCESSING_MOCKS
+void Adc_Reset(void);
+#endif
+
+#endif // _ADCHARDWARECONFIGURATOR_H
diff --git a/assets/tests_with_preprocessing/src/adc_hardware_configuratorC.h b/assets/tests_with_preprocessing/src/adc_hardware_configuratorC.h
new file mode 100644
index 000000000..4b3ef81a3
--- /dev/null
+++ b/assets/tests_with_preprocessing/src/adc_hardware_configuratorC.h
@@ -0,0 +1,15 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
+#ifndef _ADCHARDWARECONFIGURATOR_H
+#define _ADCHARDWARECONFIGURATOR_H
+
+#ifdef PREPROCESSING_MOCKS
+void Adc_Reset(void);
+#endif
+
+#endif // _ADCHARDWARECONFIGURATOR_H
diff --git a/assets/tests_with_preprocessing/test/test_adc_hardwareA.c b/assets/tests_with_preprocessing/test/test_adc_hardwareA.c
new file mode 100644
index 000000000..0d2cac8c7
--- /dev/null
+++ b/assets/tests_with_preprocessing/test/test_adc_hardwareA.c
@@ -0,0 +1,41 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
+#include "unity.h"
+#include "adc_hardwareA.h"
+#ifdef PREPROCESSING_TESTS
+#include "mock_adc_hardware_configuratorA.h"
+#endif
+
+void setUp(void)
+{
+}
+
+void tearDown(void)
+{
+}
+
+#ifdef PREPROCESSING_TESTS
+void test_init_should_call_adc_reset(void)
+{
+ Adc_Reset_Expect();
+
+ AdcHardware_Init();
+}
+#endif
+
+#ifndef PREPROCESSING_TESTS
+void test_caseA_should_fail(void)
+{
+ TEST_FAIL_MESSAGE("Intentional failure");
+}
+
+void test_caseB_should_fail(void)
+{
+ TEST_FAIL_MESSAGE("Intentional failure");
+}
+#endif
\ No newline at end of file
diff --git a/assets/tests_with_preprocessing/test/test_adc_hardwareB.c b/assets/tests_with_preprocessing/test/test_adc_hardwareB.c
new file mode 100644
index 000000000..fcd4183a7
--- /dev/null
+++ b/assets/tests_with_preprocessing/test/test_adc_hardwareB.c
@@ -0,0 +1,25 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
+#include "unity.h"
+#include "adc_hardwareB.h"
+#include "mock_adc_hardware_configuratorB.h"
+
+void setUp(void)
+{
+}
+
+void tearDown(void)
+{
+}
+
+void test_init_should_call_adc_reset(void)
+{
+ Adc_Reset_Expect();
+
+ AdcHardware_Init();
+}
diff --git a/assets/tests_with_preprocessing/test/test_adc_hardwareC.c b/assets/tests_with_preprocessing/test/test_adc_hardwareC.c
new file mode 100644
index 000000000..e38dab62b
--- /dev/null
+++ b/assets/tests_with_preprocessing/test/test_adc_hardwareC.c
@@ -0,0 +1,29 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
+#include "unity.h"
+#include "adc_hardwareC.h"
+#ifdef PREPROCESSING_TESTS
+#include "mock_adc_hardware_configuratorC.h"
+#endif
+
+void setUp(void)
+{
+}
+
+void tearDown(void)
+{
+}
+
+#ifdef PREPROCESSING_TESTS
+void test_init_should_call_adc_reset(void)
+{
+ Adc_Reset_Expect();
+
+ AdcHardware_Init();
+}
+#endif
\ No newline at end of file
diff --git a/assets/uncovered_example_file.c b/assets/uncovered_example_file.c
index 830847a50..dc389359e 100644
--- a/assets/uncovered_example_file.c
+++ b/assets/uncovered_example_file.c
@@ -1,3 +1,10 @@
+/* =========================================================================
+ Ceedling - Test-Centered Build System for C
+ ThrowTheSwitch.org
+ Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+ SPDX-License-Identifier: MIT
+========================================================================= */
+
// This file is to test abort on uncovered files feature
int multiply_numbers(int a, int b) {
diff --git a/bin/actions_wrapper.rb b/bin/actions_wrapper.rb
new file mode 100644
index 000000000..43d02f9d6
--- /dev/null
+++ b/bin/actions_wrapper.rb
@@ -0,0 +1,50 @@
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
+require 'thor'
+require 'fileutils'
+
+# Wrapper for handy Thor Actions
+class ActionsWrapper
+ include Thor::Base
+ include Thor::Actions
+
+ JUNK_FILE_EXCLUDE_REGEX =
+
+ # Most important mixin method is Thor::Actions class method `source_root()` we call externally
+
+ def _directory(src, *args)
+ # Insert exclusion of macOS and Windows preview junk files if an exclude pattern is not present
+ # Thor's use of args is an array of call arguments, some of which can be single key/value hash options
+ if !args.any? {|h| h.class != Hash ? false : !h[:exclude_pattern].nil?}
+ args << {:exclude_pattern => /(\.DS_Store)|(thumbs\.db)/}
+ end
+
+ directory( src, *args )
+ end
+
+ def _copy_file(src, *args)
+ copy_file( src, *args )
+ end
+
+ def _touch_file(src)
+ FileUtils.touch(src)
+ end
+
+ def _chmod(src, mode, *args)
+ chmod( src, mode, *args )
+ end
+
+ def _empty_directory(dest, *args)
+ empty_directory( dest, *args )
+ end
+
+ def _gsub_file(path, flag, *args, &block)
+ gsub_file( path, flag, *args, &block )
+ end
+
+end
diff --git a/bin/app_cfg.rb b/bin/app_cfg.rb
new file mode 100644
index 000000000..d04a28c25
--- /dev/null
+++ b/bin/app_cfg.rb
@@ -0,0 +1,134 @@
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
+require "io/console"
+
+# Create our global application configuration option set
+# This approach bridges clean Ruby and Rake
+
+class CeedlingAppConfig
+
+ def initialize()
+ # Default installation location determined from the location of this file
+ ceedling_root_path = File.join( File.dirname( __FILE__ ), '..' )
+
+ # Create internal hash of needed values
+ @app_cfg = {
+ # Base path of any Ceedling installation
+ :ceedling_root_path => '',
+
+ # Ceedling installation base path + /lib
+ :ceedling_lib_base_path => '',
+
+ # Ceedling installation base path + /lib/ceedling
+ :ceedling_lib_path => '',
+
+ # Ceedling installation base path + /plugins
+ :ceedling_plugins_path => '',
+
+ # Ceedling installation base path + /vendor
+ :ceedling_vendor_path => '',
+
+ # Ceedling installation base path + /examples
+ :ceedling_examples_path => '',
+
+ # Ceedling lib path + lib/ceedling/rakefile.rb
+ :ceedling_rakefile_filepath => '',
+
+ # Blank initial value for completeness
+ :project_config => {},
+
+ # Default path (in build directory) to hold logs
+ :logging_path => '',
+
+ # If logging enabled, the filepath for Ceedling's log (may be explicitly set to be outside :logging_path)
+ :log_filepath => '',
+
+ # Only specified in project config (no command line or environment variable)
+ :default_tasks => ['test:all'],
+
+ # Default, blank test case filters
+ :include_test_case => '',
+ :exclude_test_case => '',
+
+ # Default to task categry other than build/plugin tasks
+ :build_tasks? => false,
+
+ # Default to `exit(1)` upon failing test cases
+ :tests_graceful_fail? => false,
+
+ # Set terminal width (in columns) to a default
+ :terminal_width => 120,
+ }
+
+ set_paths( ceedling_root_path )
+
+ # Try to query terminal width (not always available on all platforms)
+ begin
+ @app_cfg[:terminal_width] = (IO.console.winsize)[1]
+ rescue
+ # Do nothing; allow value already set to stand as default
+ end
+ end
+
+ def set_project_config(config)
+ @app_cfg[:project_config] = config
+ end
+
+ def set_logging_path(path)
+ @app_cfg[:logging_path] = path
+ end
+
+ def set_log_filepath(filepath)
+ @app_cfg[:log_filepath] = filepath
+ end
+
+ def set_include_test_case(matcher)
+ @app_cfg[:include_test_case] = matcher
+ end
+
+ def set_exclude_test_case(matcher)
+ @app_cfg[:exclude_test_case] = matcher
+ end
+
+ def set_build_tasks(enable)
+ @app_cfg[:build_tasks?] = enable
+ end
+
+ def set_tests_graceful_fail(enable)
+ @app_cfg[:tests_graceful_fail?] = enable
+ end
+
+ def set_paths(root_path)
+ _root_path = File.expand_path( root_path )
+ lib_base_path = File.join( _root_path, 'lib' )
+ lib_path = File.join( lib_base_path, 'ceedling' )
+
+ @app_cfg[:ceedling_root_path] = _root_path
+ @app_cfg[:ceedling_lib_base_path] = lib_base_path
+ @app_cfg[:ceedling_lib_path] = lib_path
+ @app_cfg[:ceedling_vendor_path] = File.join( _root_path, 'vendor' )
+ @app_cfg[:ceedling_plugins_path] = File.join( _root_path, 'plugins' )
+ @app_cfg[:ceedling_examples_path] = File.join( _root_path, 'examples' )
+
+ @app_cfg[:ceedling_rakefile_filepath] = File.join( lib_path, 'rakefile.rb' )
+ end
+
+ def build_tasks?()
+ return @app_cfg[:build_tasks?]
+ end
+
+ def tests_graceful_fail?()
+ return @app_cfg[:tests_graceful_fail?]
+ end
+
+ # External accessor to preserve hash-like read accesses
+ def [](key)
+ return @app_cfg[key]
+ end
+
+end
diff --git a/bin/ceedling b/bin/ceedling
index 5a1d49584..ad5ea9a62 100755
--- a/bin/ceedling
+++ b/bin/ceedling
@@ -1,364 +1,160 @@
#!/usr/bin/env ruby
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
-#these are always used
require 'rubygems'
-require 'fileutils'
-# Check for the main project file (either the one defined in the ENV or the default)
-main_filepath = ENV['CEEDLING_MAIN_PROJECT_FILE']
-project_found = (!main_filepath.nil? && File.exist?(main_filepath))
-if (!project_found)
- main_filepath = "project.yml"
- project_found = File.exist?(main_filepath)
-end
-
-def is_windows?
- return ((RbConfig::CONFIG['host_os'] =~ /mswin|mingw/) ? true : false) if defined?(RbConfig)
- return ((Config::CONFIG['host_os'] =~ /mswin|mingw/) ? true : false)
-end
-
-def here
- File.join(File.expand_path(File.dirname(__FILE__)),"/..")
-end
-
-unless (project_found)
-#===================================== We Do Not Have A Project ================================================
-
- puts "Welcome to Ceedling!"
- require 'thor'
-
- class CeedlingTasks < Thor
- include Thor::Actions
-
- desc "new PROJECT_NAME", "create a new ceedling project"
- method_option :docs, :type => :boolean, :default => false, :desc => "Add docs in project vendor directory"
- method_option :local, :type => :boolean, :default => false, :desc => "Create a copy of Ceedling in the project vendor directory"
- method_option :gitignore, :type => :boolean, :default => false, :desc => "Create a gitignore file for ignoring ceedling generated files"
- method_option :no_configs, :type => :boolean, :default => false, :desc => "Don't install starter configuration files"
- method_option :noconfigs, :type => :boolean, :default => false
-
- #deprecated:
- method_option :no_docs, :type => :boolean, :default => false
- method_option :nodocs, :type => :boolean, :default => false
- method_option :as_gem, :type => :boolean, :default => false
- method_option :asgem, :type => :boolean, :default => false
- method_option :with_ignore, :type => :boolean, :default => false
- method_option :withignore, :type => :boolean, :default => false
- def new(name, silent = false)
- copy_assets_and_create_structure(name, silent, false, options)
- end
-
- desc "upgrade PROJECT_NAME", "upgrade ceedling for a project (not req'd if gem used)"
- def upgrade(name, silent = false)
- as_local = true
- yaml_path = File.join(name, "project.yml")
- begin
- require File.join(here,"lib","ceedling","yaml_wrapper.rb")
- as_local = (YamlWrapper.new.load(yaml_path)[:project][:which_ceedling] != 'gem')
- rescue
- raise "ERROR: Could not find valid project file '#{yaml_path}'"
- end
- found_docs = File.exist?( File.join(name, "docs", "CeedlingPacket.md") )
- copy_assets_and_create_structure(name, silent, true, {:upgrade => true, :no_configs => true, :local => as_local, :docs => found_docs})
- end
-
- no_commands do
- def copy_assets_and_create_structure(name, silent=false, force=false, options = {})
-
- puts "WARNING: --no_docs deprecated. It is now the default. Specify -docs if you want docs installed." if (options[:no_docs] || options[:nodocs])
- puts "WARNING: --as_gem deprecated. It is now the default. Specify -local if you want ceedling installed to this project." if (options[:as_gem] || options[:asgem])
- puts "WARNING: --with_ignore deprecated. It is now called -gitignore" if (options[:with_ignore] || options[:withignore])
-
- use_docs = options[:docs] || false
- use_configs = !(options[:no_configs] || options[:noconfigs] || false)
- use_gem = !(options[:local])
- use_ignore = options[:gitignore] || false
- is_upgrade = options[:upgrade] || false
-
- ceedling_path = File.join(name, 'vendor', 'ceedling')
- source_path = File.join(name, 'src')
- test_path = File.join(name, 'test')
- test_support_path = File.join(name, 'test/support')
-
- # If it's not an upgrade, make sure we have the paths we expect
- if (!is_upgrade)
- [source_path, test_path, test_support_path].each do |d|
- FileUtils.mkdir_p d
- end
- else
- prj_yaml = YamlWrapper.new.load(File.join(name, 'project.yml'))
- test_support_path = if prj_yaml.key?(:path) && \
- prj_yaml[:path].key?(:support)
- prj_yaml.key?[:path][:support]
- else
- ''
- end
- end
-
- # Genarate gitkeep in test support path
- FileUtils.touch(File.join(test_support_path, '.gitkeep')) unless \
- test_support_path.empty?
-
- # If documentation requested, create a place to dump them and do so
- doc_path = ''
- if use_docs
- doc_path = use_gem ? File.join(name, 'docs') : File.join(ceedling_path, 'docs')
- FileUtils.mkdir_p doc_path
-
- in_doc_path = lambda {|f| File.join(doc_path, f)}
-
- # Add documentation from main projects to list
- doc_files = {}
- ['docs','vendor/unity/docs','vendor/cmock/docs','vendor/cexception/docs'].each do |p|
- Dir[ File.expand_path(File.join(here, p, '*.md')) ].each do |f|
- doc_files[ File.basename(f) ] = f unless(doc_files.include? f)
- end
- end
-
- # Add documentation from plugins to list
- Dir[ File.join(here, 'plugins/**/README.md') ].each do |plugin_path|
- k = "plugin_" + plugin_path.split(/\\|\//)[-2] + ".md"
- doc_files[ k ] = File.expand_path(plugin_path)
- end
-
- # Copy all documentation
- doc_files.each_pair do |k, v|
- copy_file(v, in_doc_path.call(k), :force => force)
- end
- end
-
- # If installed locally to project, copy ceedling, unity, cmock, & supports to vendor
- unless use_gem
- FileUtils.mkdir_p ceedling_path
-
- #copy full folders from ceedling gem into project
- %w{plugins lib bin}.map do |f|
- {:src => f, :dst => File.join(ceedling_path, f)}
- end.each do |f|
- directory(f[:src], f[:dst], :force => force)
- end
+# Get the path for our current code directory
+ceedling_bin_path = File.expand_path( File.join( File.dirname( __FILE__ ), '..', 'bin' ) )
- # mark ceedling as an executable
- File.chmod(0755, File.join(ceedling_path, 'bin', 'ceedling')) unless is_windows?
+# Add load path so we can `require` files in bin/
+$LOAD_PATH.unshift( ceedling_bin_path )
- #copy necessary subcomponents from ceedling gem into project
- sub_components = [
- {:src => 'vendor/c_exception/lib/', :dst => 'vendor/c_exception/lib'},
- {:src => 'vendor/cmock/config/', :dst => 'vendor/cmock/config'},
- {:src => 'vendor/cmock/lib/', :dst => 'vendor/cmock/lib'},
- {:src => 'vendor/cmock/src/', :dst => 'vendor/cmock/src'},
- {:src => 'vendor/diy/lib', :dst => 'vendor/diy/lib'},
- {:src => 'vendor/unity/auto/', :dst => 'vendor/unity/auto'},
- {:src => 'vendor/unity/src/', :dst => 'vendor/unity/src'},
- ]
+# Pull in our startup configuration code in bin/
+require 'app_cfg'
+CEEDLING_APPCFG = CeedlingAppConfig.new()
- sub_components.each do |c|
- directory(c[:src], File.join(ceedling_path, c[:dst]), :force => force)
- end
- end
+# Add load paths for `require 'ceedling/*'` statements in bin/ code
+$LOAD_PATH.unshift( CEEDLING_APPCFG[:ceedling_lib_base_path] )
- # We're copying in a configuration file if we haven't said not to
- if (use_configs)
- dst_yaml = File.join(name, 'project.yml')
- src_yaml = if use_gem
- File.join(here, 'assets', 'project_as_gem.yml')
- else
- if is_windows?
- copy_file(File.join('assets', 'ceedling.cmd'), File.join(name, 'ceedling.cmd'), :force => force)
- else
- copy_file(File.join('assets', 'ceedling'), File.join(name, 'ceedling'), :force => force)
- File.chmod(0755, File.join(name, 'ceedling'))
- end
- File.join(here, 'assets', 'project_with_guts.yml')
- end
+require 'constructor' # Assumed installed via Ceedling gem dependencies
+require 'ceedling/constants'
- # Perform the actual clone of the config file, while updating the version
- File.open(dst_yaml,'w') do |dst|
- require File.expand_path(File.join(File.dirname(__FILE__),"..","lib","ceedling","version.rb"))
- dst << File.read(src_yaml).gsub(":ceedling_version: '?'",":ceedling_version: #{Ceedling::Version::CEEDLING}")
- puts " create #{dst_yaml}"
- end
- end
+# Centralized exception handler for:
+# 1. Bootloader (bin/)
+# 2. Application (lib/) last resort / outer exception handling
+def boom_handler(loginator, exception)
+ $stderr.puts( "\n" )
- # Copy the gitignore file if requested
- if (use_ignore)
- copy_file(File.join('assets', 'default_gitignore'), File.join(name, '.gitignore'), :force => force)
- end
+ if !loginator.nil?
+ loginator.log( exception.message, Verbosity::ERRORS, LogLabels::EXCEPTION )
- unless silent
- puts "\n"
- puts "Project '#{name}' #{force ? "upgraded" : "created"}!"
- puts " - Tool documentation is located in #{doc_path}" if use_docs
- puts " - Execute 'ceedling help' from #{name} to view available test & build tasks"
- puts ''
- end
- end
- end
-
- desc "examples", "list available example projects"
- def examples()
- puts "Available sample projects:"
- FileUtils.cd(File.join(here, "examples")) do
- Dir["*"].each {|proj| puts " #{proj}"}
- end
- end
-
- desc "example PROJ_NAME [DEST]", "new specified example project (in DEST, if specified)"
- def example(proj_name, dest=nil)
- if dest.nil? then dest = proj_name end
-
- copy_assets_and_create_structure(dest, true, false, {:local=>true, :docs=>true})
-
- dest_src = File.join(dest,'src')
- dest_test = File.join(dest,'test')
- dest_project = File.join(dest,'project.yml')
-
- directory "examples/#{proj_name}/src", dest_src
- directory "examples/#{proj_name}/test", dest_test
- remove_file dest_project
- copy_file "examples/#{proj_name}/project.yml", dest_project
-
- puts "\n"
- puts "Example project '#{proj_name}' created!"
- puts " - Tool documentation is located in vendor/ceedling/docs"
- puts " - Execute 'ceedling help' to view available test & build tasks"
- puts ''
- end
-
- desc "version", "return the version of the tools installed"
- def version()
- require File.expand_path(File.join(File.dirname(__FILE__),"..","lib","ceedling","version.rb"))
- puts " Ceedling:: #{Ceedling::Version::CEEDLING}"
- puts " CMock:: #{Ceedling::Version::CMOCK}"
- puts " Unity:: #{Ceedling::Version::UNITY}"
- puts " CException:: #{Ceedling::Version::CEXCEPTION}"
- end
- end
-
- if (ARGV[0] =~ /^\-T$/)
- puts "\n(No Project Detected, Therefore Showing Options to Create Projects)"
- CeedlingTasks.tasks.each_pair do |k,v|
- puts v.usage.ljust(25,' ') + v.description
- end
- puts "\n"
+ # Debug backtrace (only if debug verbosity)
+ loginator.log_debug_backtrace( exception )
+
+ # Something went really wrong... logging isn't even up and running yet
else
- CeedlingTasks.source_root here
- CeedlingTasks.start
- end
-
-#===================================== We Have A Project Already ================================================
-else
- require File.join(here,"lib","ceedling","yaml_wrapper.rb")
- require 'rbconfig'
-
- #determine platform
- platform = begin
- case(RbConfig::CONFIG['host_os'])
- when /mswin|mingw|cygwin/i
- :mswin
- when /darwin/
- :osx
- else
- :linux
- end
- rescue
- :linux
+ $stderr.puts( exception.message )
+ $stderr.puts( "Backtrace ==>" )
+ $stderr.puts( exception.backtrace )
end
+end
- #create our default meta-runner option set
- options = {
- :pretest => nil,
- :args => [],
- :add_path => [],
- :path_connector => (platform == :mswin) ? ";" : ":",
- :graceful_fail => false,
- :which_ceedling => (Dir.exist?("vendor/ceedling") ? "vendor/ceedling" : 'gem'),
- :default_tasks => [ 'test:all' ],
- :list_tasks => false
- }
-
- #guess that we need a special script file first if it exists
- if (platform == :mswin)
- options[:pretest] = File.exist?("#{ platform }_setup.bat") ? "#{ platform }_setup.bat" : nil
- else
- options[:pretest] = File.exist?("#{ platform }_setup.sh") ? "source #{ platform }_setup.sh" : nil
- end
- #merge in project settings if they can be found here
- yaml_options = YamlWrapper.new.load(main_filepath)
- if (yaml_options[:paths])
- options[:add_path] = yaml_options[:paths][:tools] || []
+# Entry point
+begin
+ diy_vendor_path = File.join( CEEDLING_APPCFG[:ceedling_vendor_path], 'diy/lib' )
+
+ # Construct all bootloader objects
+ # 1. Add full path to $LOAD_PATH to simplify objects.yml
+ # 2. Add vendored DIY to $LOAD_PATH so we can use it
+ # 3. Require DIY (used by Ceedling application too)
+ # 4. Perform object construction + dependency injection from bin/objects.yml
+ # 5. Remove all paths added to $LOAD_PATH
+ # (Main application will restore certain paths -- possibly updated by :which_ceedling)
+ $LOAD_PATH.unshift(
+ CEEDLING_APPCFG[:ceedling_lib_path],
+ diy_vendor_path
+ )
+
+ require 'diy'
+ bin_objects_filepath = File.join( ceedling_bin_path, 'objects.yml' )
+ objects = {} # Empty initial hash to be redefined (fingers crossed)
+ objects = DIY::Context.from_yaml( File.read( bin_objects_filepath ) )
+ objects.build_everything()
+
+ # Extract objects shared between bootloader and application
+ # This prevents double instantiation and preserves object state in handoff
+ handoff_objects = {}
+ handoff = [
+ :loginator,
+ :file_wrapper,
+ :yaml_wrapper,
+ :config_walkinator,
+ :system_wrapper,
+ :verbosinator
+ ]
+ CEEDLING_HANDOFF_OBJECTS = handoff_objects
+ handoff.each {|name| handoff_objects[name] = objects[name] }
+
+ # Load Thor-based top-level CLI after:
+ # 1. CEEDLING_BIN load path set
+ # 2. `objects` hash filled with DIY output
+ # 3. CEEDLING_HANDOFF_OBJECTS global is set
+ require 'cli'
+
+ # Remove all load paths we've relied on (main application will set up load paths again)
+ $LOAD_PATH.delete( ceedling_bin_path )
+ $LOAD_PATH.delete( CEEDLING_APPCFG[:ceedling_lib_path] )
+ $LOAD_PATH.delete( diy_vendor_path )
+
+ # Keep a copy of the command line for edge case CLI hacking (Thor consumes ARGV)
+ _ARGV = ARGV.clone
+
+ # Especially on Windows, tell Thor & Rake how wide the terminal is
+ ENV['THOR_COLUMNS'] = CEEDLING_APPCFG[:terminal_width].to_s()
+ ENV['RAKE_COLUMNS'] = ENV['THOR_COLUMNS']
+
+ #
+ # NOTE: See comment block in cli.rb to understand CLI handling
+ # ------------------------------------------------------------
+ #
+
+ # Command line filtering hacks
+ # - Backwards compatibility to silently preserve Rake `-T` CLI handling
+ # - Add in common `--version` or `-v` version alias handling
+ # Note: This `if` logic is necessary to ensure any other argument lists of size 1 end up with Thor
+ if (ARGV.size() == 1) and (ARGV[0] == '-T' or ARGV[0] == '--version' or ARGV[0] == '-v')
+ case ARGV[0]
+ when '-T'
+ # Call Rake task listing handler w/ default handling of project file and mixins
+ objects[:cli_handler].rake_help( env:ENV, app_cfg:CEEDLING_APPCFG )
+
+ when '--version', '-v'
+ # Call Ceedling's version handler directly
+ objects[:cli_handler].version( ENV, CEEDLING_APPCFG )
+ end
+
+ # Run command line args through Thor (including "naked" Rake tasks)
else
- options[:add_path] = []
- end
- options[:graceful_fail] = yaml_options[:graceful_fail] if yaml_options[:graceful_fail]
- options[:which_ceedling] = yaml_options[:project][:which_ceedling] if (yaml_options[:project] && yaml_options[:project][:which_ceedling])
- options[:default_tasks] = yaml_options[:default_tasks] if yaml_options[:default_tasks]
-
- #sort through command line options
- ARGV.each do |v|
- case(v)
- when /^(?:new|examples?|templates?)$/
- puts "\nOops. You called ceedling with argument '#{v}'.\n" +
- " This is an operation that will create a new project... \n" +
- " but it looks like you're already in a project. If you really \n" +
- " want to do this, try moving to an empty folder.\n\n"
- abort
- when /^help$/
- options[:list_tasks] = true
- when /^-T$/
- options[:list_tasks] = true
- when /^--tasks$/
- options[:list_tasks] = true
- when /^project:(\w+)/
- ENV['CEEDLING_USER_PROJECT_FILE'] = "#{$1}.yml"
- when /^--test_case=(\w+)/
- ENV['CEEDLING_INCLUDE_TEST_CASE_NAME'] = $1
- when /^--exclude_test_case=(\w+)/
- ENV['CEEDLING_EXCLUDE_TEST_CASE_NAME'] = $1
- else
- options[:args].push(v)
- end
+ CeedlingTasks::CLI.start( ARGV,
+ {
+ :app_cfg => CEEDLING_APPCFG,
+ :objects => objects,
+ }
+ )
end
- #add to the path
- if (options[:add_path] && !options[:add_path].empty?)
- path = ENV["PATH"]
- options[:add_path].each do |p|
- f = File.expand_path(File.dirname(__FILE__),p)
- path = (f + options[:path_connector] + path) unless path.include? f
- end
- ENV["PATH"] = path
+# Handle case of Thor application CLI failing to handle command line arguments.
+rescue Thor::UndefinedCommandError
+ # Marrying Thor & Rake command line handling creates a gap (see comments in CLI handling).
+ # If a user enters only Rake build tasks at the command line followed by Thor flags,
+ # our Thor configuration doesn't see those flags.
+ # We catch the exception of unrecognized Thor commands here (i.e. any "naked" Rake tasks),
+ # and try again by forcing the Thor `build` command at the beginning of the command line.
+ # This way, our Thor handling will process option flags and properly pass the Rake tasks
+ # along as well.
+
+ # Necessary nested exception handling
+ begin
+ CeedlingTasks::CLI.start( _ARGV.unshift( 'build' ),
+ {
+ :app_cfg => CEEDLING_APPCFG,
+ :objects => objects,
+ }
+ )
+ rescue StandardError => ex
+ boom_handler( objects[:loginator], ex )
+ exit(1)
end
- # Load Ceedling (either through the rakefile OR directly)
- if (File.exist?("rakefile.rb"))
- load 'rakefile.rb'
- else
- if (options[:which_ceedling] == 'gem')
- require 'ceedling'
- else
- load "#{options[:which_ceedling]}/lib/ceedling.rb"
- end
- Ceedling.load_project
- end
-
- Rake.application.standard_exception_handling do
- if options[:list_tasks]
- # Display helpful task list when requested. This required us to dig into Rake internals a bit
- Rake.application.define_singleton_method(:name=) {|n| @name = n}
- Rake.application.name = 'ceedling'
- Rake.application.options.show_tasks = :tasks
- Rake.application.options.show_task_pattern = /^(?!.*build).*$/
- Rake.application.display_tasks_and_comments()
- else
- task :default => options[:default_tasks]
-
- # Run our Tasks!
- Rake.application.collect_command_line_tasks(options[:args])
- Rake.application.top_level
- end
- end
- true
-#===================================================================================================================
+# Bootloader boom handling
+rescue StandardError => ex
+ boom_handler( objects[:loginator], ex )
+ exit(1)
end
+
diff --git a/bin/cli.rb b/bin/cli.rb
new file mode 100644
index 000000000..af42ae6c3
--- /dev/null
+++ b/bin/cli.rb
@@ -0,0 +1,542 @@
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
+require 'thor'
+require 'ceedling/constants' # From Ceedling application
+
+##
+## Command Line Handling
+## =====================
+##
+## OVERVIEW
+## --------
+## Ceedling's command line handling marries Thor and Rake. Thor does not call
+## Rake. Rather, a handful of command line conventions, edge case handling,
+## and Thor features are stitched together to ensure a given command line is
+## processed by Thor and/or Rake.
+##
+## Ceedling's command line is processed with these mechanisms:
+## 1. Special / edge case hacking of ARGV directly.
+## 2. Thor for all application commands and flags.
+## 3. Handing off to Rake from either (1) or (2) for task listing or running
+## build tasks.
+##
+## EDGE CASE HACKING
+## -----------------
+## Special / edge cases:
+## 1. Silent backwards compatibility support for Rake's `-T`.
+## 2. Thor does not recognize "naked" Rake build tasks as application commands
+## (`ceedling test:all` instead of `ceedling build test:all`). So, we catch
+## this exception and then provide the command line back to Thor as a `build`
+## command line. This also allows us to ensure Thor processes `build` option
+## flags following naked build tasks that would otherwise be ignored if
+## we simply passed a failing command line to Rake.
+##
+## THOR
+## ----
+## Thor is configured or overridden with these special attributes:
+## * The default task is `build`. This means that if the `build` keyword is
+## omitted but Thor otherwise recognizes the command line (a `build` flag is
+## the first item on the command line), it will process it as the `build`
+## command. The build command takes flags and tasks. Tasks are handed off to
+## Rake to process. If no `build` keyword is present and `build` flags come
+## after tasks, Thor sees the command line as unhandled commands.
+## * The PermissiveCLI code handles unrecognized command exception so as to
+## eat the Thor complaint and re-throw the exception for edge case handling.
+##
+## NOTES
+## -----
+## * Ultimately, any unrecognized command or task is processed by Rake, and
+## Rake makes the complaint.
+##
+
+
+##
+## This Class
+## ==========
+##
+## The nature of Thor more-or-less requires this class to be used as a class
+## and not as an insantiated object. This shows up in a variety of ways:
+## * The calling convention is `CeedlingTasks::CLI.start( ARGV )`
+## * Many of the methods necessary to configure the CLI class are class
+## methods in Thor and are called that way.
+##
+## The nature of Thor both requires and allows for some slightly ugly or
+## brittle code -- relying on globals, etc.
+##
+## Because of this, care has been taken that this class contains as little
+## logic as possible and is the funnel for any and all necessary global
+## references and other little oddball needs.
+##
+
+
+# Special handling to prevent Thor from barfing on unrecognized CLI arguments
+# (i.e. Rake tasks)
+module PermissiveCLI
+ def self.extended(base)
+ super
+ base.check_unknown_options!
+ end
+
+ # Redefine the Thor CLI entrypoint and exception handling
+ def start(args, config={})
+ begin
+ # Copy args as Thor changes them within the call chain of dispatch()
+ _args = args.clone()
+
+ # Call Thor's handlers as it does in start()
+ config[:shell] ||= Thor::Base.shell.new
+ dispatch(nil, args, nil, config)
+
+ # Handle undefined commands at top-level and for `help `
+ rescue Thor::UndefinedCommandError => ex
+ # Handle `help` for an argument that is not an application command such as `new` or `build`
+ if _args[0].downcase() == 'help'
+
+ # Raise fatal StandardError to differentiate from UndefinedCommandError
+ msg = "Argument '#{_args[1]}' is not a recognized application command with detailed help. " +
+ "It may be a build / plugin task without detailed help or simply a goof."
+ raise( msg )
+
+ # Otherwise, eat unhandled command errors
+ else
+ # - No error message
+ # - No `exit()`
+ # - Re-raise to allow special, external CLI handling logic
+ raise ex
+ end
+ end
+ end
+end
+
+module CeedlingTasks
+
+ VERBOSITY_NORMAL = 'normal'
+ VERBOSITY_DEBUG = 'debug'
+
+ DOC_LOCAL_FLAG = "Install Ceedling plus supporting tools to vendor/"
+
+ DOC_DOCS_FLAG = "Copy all documentation to docs/ subdirectory of project"
+
+ DOC_PROJECT_FLAG = "Loads the filepath as your base project configuration"
+
+ DOC_MIXIN_FLAG = "Merges the configuration mixin by name or filepath."
+
+ LONGDOC_LOCAL_FLAG = "`--local` copies Ceedling and its dependencies to a vendor/
+ subdirectory in the root of the project. It also installs a
+ platform-appropriate executable script `ceedling` at the root of the
+ project."
+
+ LONGDOC_MIXIN_FLAG = "`--mixin` merges the specified configuration mixin. This
+ flag may be repeated for multiple mixins. A simple mixin name initiates a
+ lookup from within mixin load paths in your project file and among built-in
+ mixins. A filepath and/or filename (with extension) will instead merge the
+ specified YAML file. See documentation for complete details.
+ \x5> --mixin my_compiler --mixin my/path/mixin.yml"
+
+ # Intentionally disallowed Linux/Unix/Windows filename characters to minimize the chance
+ # of mistakenly filtering various string-base flags missing a parmeter
+ CLI_MISSING_PARAMETER_DEFAULT = "/<>\\||*"
+
+ class CLI < Thor
+ include Thor::Actions
+ extend PermissiveCLI
+
+ # Ensure we bail out with non-zero exit code if the command line is wrong
+ def self.exit_on_failure?() true end
+
+ # Allow `build` to be omitted in command line
+ default_command( :build )
+
+ # Intercept construction to extract configuration and injected dependencies
+ def initialize(args, config, options)
+ super(args, config, options)
+
+ @app_cfg = options[:app_cfg]
+ @handler = options[:objects][:cli_handler]
+
+ @loginator = options[:objects][:loginator]
+
+ # Set the name for labelling CLI interactions
+ CLI::package_name( @loginator.decorate( 'Ceedling application', LogLabels::TITLE ) )
+ end
+
+
+ # Override Thor help to list Rake tasks as well
+ desc "help [COMMAND]", "Describe available commands and list build operations"
+ method_option :project, :type => :string, :default => nil, :lazy_default => CLI_MISSING_PARAMETER_DEFAULT, :aliases => ['-p'], :desc => DOC_PROJECT_FLAG
+ method_option :mixin, :type => :string, :default => [], :repeatable => true, :aliases => ['-m'], :desc => DOC_MIXIN_FLAG
+ method_option :debug, :type => :boolean, :default => false, :hide => true
+ long_desc( CEEDLING_HANDOFF_OBJECTS[:loginator].sanitize(
+ <<-LONGDESC
+ `ceedling help` provides summary help for all available application commands
+ and build tasks.
+
+ COMMAND is optional and will produce detailed help for a specific application command --
+ not a build or plugin task, however.
+
+ `ceedling help` also lists the available build operations from loading your
+ project configuration. Optionally, a project filepath and/or mixins may be
+ provided to load a different project configuration than the default.
+
+ Notes on Optional Flags:
+
+ âą #{LONGDOC_MIXIN_FLAG}
+ LONGDESC
+ ) )
+ def help(command=nil)
+ @handler.validate_string_param(
+ options[:project],
+ CLI_MISSING_PARAMETER_DEFAULT,
+ "--project is missing a required filepath parameter"
+ )
+
+ # Get unfrozen copies so we can add / modify
+ _options = options.dup()
+ _options[:project] = options[:project].dup() if !options[:project].nil?
+ _options[:mixin] = []
+ options[:mixin].each {|mixin| _options[:mixin] << mixin.dup() }
+
+ _options[:verbosity] = options[:debug] ? VERBOSITY_DEBUG : nil
+
+ # Call application help with block to execute Thor's built-in help in the help logic
+ @handler.app_help( ENV, @app_cfg, _options, command ) { |command| super(command) }
+ end
+
+
+ desc "new NAME [DEST]", "Create a new project structure at optional DEST path"
+ method_option :local, :type => :boolean, :default => false, :desc => DOC_LOCAL_FLAG
+ method_option :docs, :type => :boolean, :default => false, :desc => DOC_DOCS_FLAG
+ method_option :configs, :type => :boolean, :default => true, :desc => "Install starter project file in project root"
+ method_option :force, :type => :boolean, :default => false, :desc => "Ignore any existing project and recreate destination"
+ method_option :debug, :type => :boolean, :default => false, :hide => true
+ method_option :gitsupport, :type => :boolean, :default => false, :desc => "Create .gitignore / .gitkeep files for convenience"
+ long_desc( CEEDLING_HANDOFF_OBJECTS[:loginator].sanitize(
+ <<-LONGDESC
+ `ceedling new` creates a new project structure.
+
+ NAME is required and will be the containing directory for the new project.
+
+ DEST is an optional directory path for the new project (e.g. /).
+ The default is your working directory. Nonexistent paths will be created.
+
+ Notes on Optional Flags:
+
+ âą #{LONGDOC_LOCAL_FLAG}
+
+ âą `--force` completely destroys anything found in the target path for the
+ new project.
+ LONGDESC
+ ) )
+ def new(name, dest=nil)
+ require 'version' # lib/version.rb for TAG constant
+
+ # Get unfrozen copies so we can add / modify
+ _options = options.dup()
+ _dest = dest.dup() if !dest.nil?
+
+ _options[:verbosity] = options[:debug] ? VERBOSITY_DEBUG : nil
+
+ @handler.new_project( ENV, @app_cfg, Ceedling::Version::TAG, _options, name, _dest )
+ end
+
+ desc "upgrade PATH", "Upgrade vendored installation of Ceedling for a project at PATH"
+ method_option :project, :type => :string, :default => DEFAULT_PROJECT_FILENAME, :lazy_default => CLI_MISSING_PARAMETER_DEFAULT, :desc => "Project filename"
+ method_option :debug, :type => :boolean, :default => false, :hide => true
+ long_desc( CEEDLING_HANDOFF_OBJECTS[:loginator].sanitize(
+ <<-LONGDESC
+ `ceedling upgrade` updates an existing project.
+
+ PATH is required and should be the root of the project to upgrade.
+
+ This command only meaningfully operates on projects wth a local vendored copy
+ of Ceedling (in /vendor/) and optional documentation (in
+ /docs/).
+
+ Running this command replaces vendored Ceedling with the version running
+ this command. If docs are found, they will be replaced.
+
+ A basic check for project existence looks for vendored ceedlng and a project
+ configuration file.
+
+ Notes on Optional Flags:
+
+ âą `--project` specifies a filename (optionally with leading path) for the
+ project configuration file used in the project existence check. Otherwise,
+ the default ./#{DEFAULT_PROJECT_FILENAME} at the root of the project is
+ checked.
+ LONGDESC
+ ) )
+ def upgrade(path)
+ @handler.validate_string_param(
+ options[:project],
+ CLI_MISSING_PARAMETER_DEFAULT,
+ "--project is missing a required filename parameter"
+ )
+
+ # Get unfrozen copies so we can add / modify
+ _options = options.dup()
+ _options[:project] = options[:project].dup()
+ _path = path.dup()
+
+ _options[:verbosity] = options[:debug] ? VERBOSITY_DEBUG : nil
+
+ @handler.upgrade_project( ENV, @app_cfg, _options, _path )
+ end
+
+
+ desc "build [TASKS...]", "Run build tasks (`build` keyword not required)"
+ method_option :project, :type => :string, :default => nil, :lazy_default => CLI_MISSING_PARAMETER_DEFAULT, :aliases => ['-p'], :desc => DOC_PROJECT_FLAG
+ method_option :mixin, :type => :string, :default => [], :repeatable => true, :aliases => ['-m'], :desc => DOC_MIXIN_FLAG
+ method_option :verbosity, :type => :string, :default => VERBOSITY_NORMAL, :lazy_default => CLI_MISSING_PARAMETER_DEFAULT, :aliases => ['-v'],
+ :desc => "Sets logging level"
+ method_option :log, :type => :boolean, :default => nil,
+ :desc => "Enable logging to /#{DEFAULT_BUILD_LOGS_PATH}/#{DEFAULT_CEEDLING_LOGFILE}"
+ # :lazy_default allows us to check for missing parameters (if no filepath given Thor unhelpfully provides the flag name as its value)
+ method_option :logfile, :type => :string, :aliases => ['-l'], :default => '', :lazy_default => CLI_MISSING_PARAMETER_DEFAULT,
+ :desc => "Enables logging to specified filepath"
+ method_option :graceful_fail, :type => :boolean, :default => nil, :desc => "Force exit code of 0 for unit test failures"
+ method_option :test_case, :type => :string, :default => '', :lazy_default => CLI_MISSING_PARAMETER_DEFAULT,
+ :desc => "Filter for individual unit test names"
+ method_option :exclude_test_case, :type => :string, :default => '', :lazy_default => CLI_MISSING_PARAMETER_DEFAULT,
+ :desc => "Prevent matched unit test names from running"
+ # Include for consistency with other commands (override --verbosity)
+ method_option :debug, :type => :boolean, :default => false, :hide => true
+ long_desc( CEEDLING_HANDOFF_OBJECTS[:loginator].sanitize(
+ <<-LONGDESC
+ `ceedling build` executes build tasks created from your project configuration.
+
+ NOTE: `build` is not required to run tasks. The following are equivalent:
+ \x5 > ceedling test:all
+ \x5 > ceedling build test:all
+
+ TASKS are zero or more build operations created from your project configuration.
+ If no tasks are provided, built-in default tasks or your :project âł
+ :default_tasks will be executed.
+
+ Notes on Optional Flags:
+
+ âą #{LONGDOC_MIXIN_FLAG}
+
+ âą `--test-case` and its inverse `--exclude-test-case` set test case name
+ matchers to run only a subset of the unit test suite. See docs for full details.
+
+ âą `If --log and --logfile are both specified, --logfile will set the log file path.
+ If --no-log and --logfile are both specified, no logging will occur.
+ LONGDESC
+ ) )
+ def build(*tasks)
+ @handler.validate_string_param(
+ options[:project],
+ CLI_MISSING_PARAMETER_DEFAULT,
+ "--project is missing a required filepath parameter"
+ )
+
+ @handler.validate_string_param(
+ options[:verbosity],
+ CLI_MISSING_PARAMETER_DEFAULT,
+ "--verbosity is missing a required parameter"
+ )
+
+ @handler.validate_string_param(
+ options[:logfile],
+ CLI_MISSING_PARAMETER_DEFAULT,
+ "--logfile is missing a required filepath parameter"
+ )
+
+ @handler.validate_string_param(
+ options[:test_case],
+ CLI_MISSING_PARAMETER_DEFAULT,
+ "--test-case is missing a required test case name parameter"
+ )
+
+ @handler.validate_string_param(
+ options[:exclude_test_case],
+ CLI_MISSING_PARAMETER_DEFAULT,
+ "--exclude-test-case is missing a required test case name parameter"
+ )
+
+ # Get unfrozen copies so we can add / modify
+ _options = options.dup()
+ _options[:project] = options[:project].dup() if !options[:project].nil?
+ _options[:mixin] = []
+ options[:mixin].each {|mixin| _options[:mixin] << mixin.dup() }
+ _options[:verbosity] = VERBOSITY_DEBUG if options[:debug]
+ _options[:logfile] = options[:logfile].dup()
+
+ @handler.build( env:ENV, app_cfg:@app_cfg, options:_options, tasks:tasks )
+ end
+
+
+ desc "dumpconfig FILEPATH [SECTIONS...]", "Process project configuration and write final config to a YAML file"
+ method_option :project, :type => :string, :default => nil, :lazy_default => CLI_MISSING_PARAMETER_DEFAULT, :aliases => ['-p'],
+ :desc => DOC_PROJECT_FLAG
+ method_option :mixin, :type => :string, :default => [], :repeatable => true, :aliases => ['-m'], :desc => DOC_MIXIN_FLAG
+ method_option :app, :type => :boolean, :default => true, :desc => "Runs Ceedling application and its config manipulations"
+ method_option :debug, :type => :boolean, :default => false, :hide => true
+ long_desc( CEEDLING_HANDOFF_OBJECTS[:loginator].sanitize(
+ <<-LONGDESC
+ `ceedling dumpconfig` loads your project configuration, including all manipulations & merges,
+ and writes the final config to a YAML file.
+
+ FILEPATH is a required path to a destination YAML file. A nonexistent path will be created.
+
+ SECTIONS is an optional config âpathâ that extracts a portion of a configuration. The
+ top-level YAML container will be the pathâs last element.
+ The following example will produce config.yml containing ':test_compiler: {...}'.
+ \x5> ceedling dumpconfig my/path/config.yml tools test_compiler
+
+ Notes on Optional Flags:
+
+ âą #{LONGDOC_MIXIN_FLAG}
+
+ âą `--app` loads various settings, merges defaults, loads plugin config changes, and validates
+ the configuration. Disabling it dumps project config after any mixins but before any
+ application manipulations.
+ LONGDESC
+ ) )
+ def dumpconfig(filepath, *sections)
+ @handler.validate_string_param(
+ options[:project],
+ CLI_MISSING_PARAMETER_DEFAULT,
+ "--project is missing a required filepath parameter"
+ )
+
+ # Get unfrozen copies so we can add / modify
+ _options = options.dup()
+ _options[:project] = options[:project].dup() if !options[:project].nil?
+ _options[:mixin] = []
+ options[:mixin].each {|mixin| _options[:mixin] << mixin.dup() }
+ _filepath = filepath.dup()
+
+ _options[:verbosity] = options[:debug] ? VERBOSITY_DEBUG : nil
+
+ @handler.dumpconfig( ENV, @app_cfg, _options, _filepath, sections )
+ end
+
+
+ desc "environment", "List all configured environment variable names with values."
+ method_option :project, :type => :string, :default => nil, :lazy_default => CLI_MISSING_PARAMETER_DEFAULT, :aliases => ['-p'],
+ :desc => DOC_PROJECT_FLAG
+ method_option :mixin, :type => :string, :default => [], :repeatable => true, :aliases => ['-m'], :desc => DOC_MIXIN_FLAG
+ method_option :debug, :type => :boolean, :default => false, :hide => true
+ long_desc( CEEDLING_HANDOFF_OBJECTS[:loginator].sanitize(
+ <<-LONGDESC
+ `ceedling environment` displays all environment variables that have been set for project use.
+
+ Notes on Optional Flags:
+
+ âą #{LONGDOC_MIXIN_FLAG}
+ LONGDESC
+ ) )
+ def environment()
+ @handler.validate_string_param(
+ options[:project],
+ CLI_MISSING_PARAMETER_DEFAULT,
+ "--project is missing a required filepath parameter"
+ )
+
+ # Get unfrozen copies so we can add / modify
+ _options = options.dup()
+ _options[:project] = options[:project].dup() if !options[:project].nil?
+ _options[:mixin] = []
+ options[:mixin].each {|mixin| _options[:mixin] << mixin.dup() }
+
+ _options[:verbosity] = options[:debug] ? VERBOSITY_DEBUG : nil
+
+ @handler.environment( ENV, @app_cfg, _options )
+ end
+
+
+ desc "examples", "List available example projects"
+ method_option :debug, :type => :boolean, :default => false, :hide => true
+ long_desc( CEEDLING_HANDOFF_OBJECTS[:loginator].sanitize(
+ <<-LONGDESC
+ `ceedling examples` lists the names of the example projects that come packaged with Ceedling.
+
+ The output of this list is most useful when used by the `ceedling example` (no âsâ) command
+ to extract an example project to your filesystem.
+ LONGDESC
+ ) )
+ def examples()
+ # Get unfrozen copies so we can add / modify
+ _options = options.dup()
+
+ _options[:verbosity] = options[:debug] ? VERBOSITY_DEBUG : nil
+
+ @handler.list_examples( ENV, @app_cfg, _options )
+ end
+
+
+ desc "example NAME [DEST]", "Create named example project in optional DEST path"
+ method_option :local, :type => :boolean, :default => false, :desc => DOC_LOCAL_FLAG
+ method_option :docs, :type => :boolean, :default => false, :desc => DOC_DOCS_FLAG
+ method_option :debug, :type => :boolean, :default => false, :hide => true
+ long_desc( CEEDLING_HANDOFF_OBJECTS[:loginator].sanitize(
+ <<-LONGDESC
+ `ceedling example` extracts the named example project from within Ceedling to
+ your filesystem.
+
+ NAME is required to specify the example to extract. A list of example projects
+ is available with the `examples` command. NAME will be the containing directory
+ for the extracted project.
+
+ DEST is an optional containing directory path (ex: /). The default
+ is your working directory. A nonexistent path will be created.
+
+ Notes on Optional Flags:
+
+ âą #{LONGDOC_LOCAL_FLAG}
+
+ NOTE: `example` is destructive. If the destination path is a previoulsy created
+ example project, `ceedling example` will overwrite the contents.
+ LONGDESC
+ ) )
+ def example(name, dest=nil)
+ # Get unfrozen copies so we can add / modify
+ _options = options.dup()
+ _dest = dest.dup() if !dest.nil?
+
+ _options[:verbosity] = options[:debug] ? VERBOSITY_DEBUG : nil
+
+ @handler.create_example( ENV, @app_cfg, _options, name, _dest )
+ end
+
+
+ desc "version", "Display version details of Ceedling components"
+ long_desc( CEEDLING_HANDOFF_OBJECTS[:loginator].sanitize(
+ <<-LONGDESC
+ `ceedling version` displays the version details of Ceedling and its supporting
+ frameworks along with Ceedlingâs installation paths.
+
+ Ceedling contains launcher and application components. The launcher
+ handles set up, loading your project configuration, and processing your
+ command line. The application runs your build and plugin tasks. The
+ launcher hands off to the application. The two components are not
+ necessarily from the same installation or of the same version. Local
+ vendoring options, the WHICH_CEEDLING environment variable, and more can
+ cause the Ceedling launcher to load a Ceedling application that is run
+ from a different path than the launcher.
+
+ If the launcher and application are from different locations, the version
+ output lists details for both. If they are from the same location, only a
+ single Ceedling version is provided.
+
+ NOTES:
+
+ âą `version` does not load your project file.
+
+ âą The build frameworks Unity, CMock, and CException are always sourced from
+ the Ceedling application.
+ LONGDESC
+ ) )
+ def version()
+ @handler.version( ENV, @app_cfg )
+ end
+
+ end
+end
diff --git a/bin/cli_handler.rb b/bin/cli_handler.rb
new file mode 100644
index 000000000..7b2d4a58d
--- /dev/null
+++ b/bin/cli_handler.rb
@@ -0,0 +1,480 @@
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
+require 'thor'
+require 'mixins' # Built-in Mixins
+require 'ceedling/constants' # From Ceedling application
+require 'versionator' # Outisde DIY context
+
+class CliHandler
+
+ constructor :configinator, :projectinator, :cli_helper, :path_validator, :actions_wrapper, :loginator
+
+ # Override to prevent exception handling from walking & stringifying the object variables.
+ # Object variables are lengthy and produce a flood of output.
+ def inspect
+ return this.class.name
+ end
+
+
+ def setup()
+ # Aliases
+ @helper = @cli_helper
+ @actions = @actions_wrapper
+ end
+
+
+ def validate_string_param( param, missing, message )
+ if param == missing
+ raise Thor::Error.new( message )
+ end
+ end
+
+
+ # Thor application help + Rake help (if available)
+ def app_help(env, app_cfg, options, command, &thor_help)
+ verbosity = @helper.set_verbosity( options[:verbosity] )
+
+ # If help requested for a command, show it and skip listing build tasks
+ if !command.nil?
+ # Block handler
+ thor_help.call( command ) if block_given?
+ return
+ end
+
+ # Display Thor-generated help listing
+ thor_help.call( command ) if block_given?
+
+ # If it was help for a specific command, we're done
+ return if !command.nil?
+
+ # If project configuration is available, also display Rake tasks
+ @path_validator.standardize_paths( options[:project], *options[:mixin], )
+ return if !@projectinator.config_available?( filepath:options[:project], env:env )
+
+ list_rake_tasks(
+ env:env,
+ app_cfg: app_cfg,
+ filepath: options[:project],
+ mixins: options[:mixin],
+ # Silent Ceedling loading unless debug verbosity
+ silent: !(verbosity == Verbosity::DEBUG)
+ )
+ end
+
+
+ # Public to be used by `-T` ARGV hack handling
+ def rake_help(env:, app_cfg:)
+ @helper.set_verbosity() # Default to normal
+
+ list_rake_tasks( env:env, app_cfg:app_cfg )
+ end
+
+
+ def new_project(env, app_cfg, ceedling_tag, options, name, dest)
+ @helper.set_verbosity( options[:verbosity] )
+
+ @path_validator.standardize_paths( dest )
+
+ # If destination is nil, reassign it to name
+ # Otherwise, join the destination and name into a new path
+ dest = dest.nil? ? ('./' + name) : File.join( dest, name )
+
+ # Check for existing project (unless --force)
+ if @helper.project_exists?( dest, :|, DEFAULT_PROJECT_FILENAME, 'src', 'test' )
+ msg = "It appears a project already exists at #{dest}/. Use --force to destroy it and create a new project."
+ raise msg
+ end unless options[:force]
+
+ # Update app_cfg paths (ignore return values)
+ @helper.which_ceedling?( env:env, app_cfg:app_cfg )
+
+ # Thor Actions for project tasks use paths in relation to this path
+ ActionsWrapper.source_root( app_cfg[:ceedling_root_path] )
+
+ # Blow away any existing directories and contents if --force
+ @actions.remove_dir( dest ) if options[:force]
+
+ # Create blank directory structure
+ ['.', 'src', 'test', 'test/support'].each do |path|
+ @actions._empty_directory( File.join( dest, path) )
+ end
+
+ # Vendor the tools and install command line helper scripts
+ @helper.vendor_tools( app_cfg[:ceedling_root_path], dest ) if options[:local]
+
+ # Copy in documentation
+ @helper.copy_docs( app_cfg[:ceedling_root_path], dest ) if options[:docs]
+
+ # Copy / set up project file
+ @helper.create_project_file( dest, options[:local], ceedling_tag ) if options[:configs]
+
+ # Copy Git Ignore file
+ if options[:gitsupport]
+ @actions._copy_file(
+ File.join( 'assets', 'default_gitignore' ),
+ File.join( dest, '.gitignore' ),
+ :force => true
+ )
+ @actions._touch_file( File.join( dest, 'test/support', '.gitkeep') )
+ end
+
+ @loginator.log() # Blank line
+ @loginator.log( "New project '#{name}' created at #{dest}/\n", Verbosity::NORMAL, LogLabels::TITLE )
+ end
+
+
+ def upgrade_project(env, app_cfg, options, path)
+ @helper.set_verbosity( options[:verbosity] )
+
+ @path_validator.standardize_paths( path, options[:project] )
+
+ # Check for existing project
+ if !@helper.project_exists?( path, :&, options[:project], 'vendor/ceedling/lib/version.rb' )
+ msg = "Could not find an existing project at #{path}/."
+ raise msg
+ end
+
+ which, _ = @helper.which_ceedling?( env:env, app_cfg:app_cfg )
+ if (which == :gem)
+ msg = "Project configuration specifies the Ceedling gem, not vendored Ceedling"
+ @loginator.log( msg, Verbosity::NORMAL, LogLabels::NOTICE )
+ end
+
+ # Thor Actions for project tasks use paths in relation to this path
+ ActionsWrapper.source_root( app_cfg[:ceedling_root_path] )
+
+ # Recreate vendored tools
+ vendor_path = File.join( path, 'vendor', 'ceedling' )
+ @actions.remove_dir( vendor_path )
+ @helper.vendor_tools( app_cfg[:ceedling_root_path], path )
+
+ # Recreate documentation if we find docs/ subdirectory
+ docs_path = File.join( path, 'docs' )
+ founds_docs = @helper.project_exists?( path, :&, File.join( 'docs', 'CeedlingPacket.md' ) )
+ if founds_docs
+ @actions.remove_dir( docs_path )
+ @helper.copy_docs( app_cfg[:ceedling_root_path], path )
+ end
+
+ @loginator.log() # Blank line
+ @loginator.log( "Upgraded project at #{path}/\n", Verbosity::NORMAL, LogLabels::TITLE )
+ end
+
+
+ def build(env:, app_cfg:, options:{}, tasks:)
+ @helper.set_verbosity( options[:verbosity] )
+
+ @path_validator.standardize_paths( options[:project], options[:logfile], *options[:mixin] )
+
+ _, config = @configinator.loadinate( builtin_mixins:BUILTIN_MIXINS, filepath:options[:project], mixins:options[:mixin], env:env )
+
+ default_tasks = @configinator.default_tasks( config:config, default_tasks:app_cfg[:default_tasks] )
+
+ @helper.process_testcase_filters(
+ config: config,
+ include: options[:test_case],
+ exclude: options[:exclude_test_case],
+ tasks: tasks,
+ default_tasks: default_tasks
+ )
+
+ logging_path = @helper.process_logging_path( config )
+ log_filepath = @helper.process_log_filepath( logging_path, options[:log], options[:logfile] )
+
+ @loginator.log( " > Logfile: #{log_filepath}" ) if !log_filepath.empty?
+
+ # Save references
+ app_cfg.set_project_config( config )
+ app_cfg.set_logging_path( logging_path )
+ app_cfg.set_log_filepath( log_filepath )
+ app_cfg.set_include_test_case( options[:test_case] )
+ app_cfg.set_exclude_test_case( options[:exclude_test_case] )
+
+ # Set graceful_exit from command line & configuration options
+ app_cfg.set_tests_graceful_fail(
+ @helper.process_graceful_fail(
+ config: config,
+ cmdline_graceful_fail: options[:graceful_fail],
+ tasks: tasks,
+ default_tasks: default_tasks
+ )
+ )
+
+ # Enable setup / operations duration logging in Rake context
+ app_cfg.set_build_tasks( @helper.build_or_plugin_task?( tasks:tasks, default_tasks:default_tasks ) )
+
+ _, path = @helper.which_ceedling?( env:env, config:config, app_cfg:app_cfg )
+
+ # Log Ceedling Application version information
+ _version = Versionator.new(
+ app_cfg[:ceedling_root_path],
+ app_cfg[:ceedling_vendor_path]
+ )
+
+ version = <<~VERSION
+ Application & Build Frameworks
+ Ceedling => #{_version.ceedling_build}
+ CMock => #{_version.cmock_tag}
+ Unity => #{_version.unity_tag}
+ CException => #{_version.cexception_tag}
+ VERSION
+
+ @loginator.log( '', Verbosity::OBNOXIOUS )
+ @loginator.log( version, Verbosity::OBNOXIOUS, LogLabels::CONSTRUCT )
+
+ @helper.load_ceedling(
+ config: config,
+ rakefile_path: path,
+ default_tasks: default_tasks
+ )
+
+ # Hand Rake tasks off to be executed
+ @helper.run_rake_tasks( tasks )
+ end
+
+
+ def dumpconfig(env, app_cfg, options, filepath, sections)
+ @helper.set_verbosity( options[:verbosity] )
+
+ @path_validator.standardize_paths( filepath, options[:project], *options[:mixin] )
+
+ _, config = @configinator.loadinate( builtin_mixins:BUILTIN_MIXINS, filepath:options[:project], mixins:options[:mixin], env:env )
+
+ # Exception handling to ensure we dump the configuration regardless of config validation errors
+ begin
+ # If enabled, process the configuration through Ceedling automatic settings, defaults, plugins, etc.
+ if options[:app]
+ default_tasks = @configinator.default_tasks( config:config, default_tasks:app_cfg[:default_tasks] )
+
+ # Save references
+ app_cfg.set_project_config( config )
+ app_cfg.set_logging_path( @helper.process_logging_path( config ) )
+
+ _, path = @helper.which_ceedling?( env:env, config:config, app_cfg:app_cfg )
+
+ config = @helper.load_ceedling(
+ config: config,
+ rakefile_path: path,
+ default_tasks: default_tasks
+ )
+ else
+ @loginator.log( " > Skipped loading Ceedling application", Verbosity::OBNOXIOUS )
+ end
+ ensure
+ @helper.dump_yaml( config, filepath, sections )
+
+ @loginator.log() # Blank line
+ @loginator.log( "Dumped project configuration to #{filepath}\n", Verbosity::NORMAL, LogLabels::TITLE )
+ end
+ end
+
+
+ def environment(env, app_cfg, options)
+ @helper.set_verbosity( options[:verbosity] )
+
+ @path_validator.standardize_paths( options[:project], *options[:mixin] )
+
+ _, config = @configinator.loadinate( builtin_mixins:BUILTIN_MIXINS, filepath:options[:project], mixins:options[:mixin], env:env )
+
+ # Save references
+ app_cfg.set_project_config( config )
+ app_cfg.set_logging_path( @helper.process_logging_path( config ) )
+
+ _, path = @helper.which_ceedling?( env:env, config:config, app_cfg:app_cfg )
+
+ config = @helper.load_ceedling(
+ config: config,
+ rakefile_path: path
+ )
+
+ env_list = []
+
+ # Process external environment -- filter for Ceedling variables
+ env.each do |var, value|
+ next if !(var =~ /ceedling/i)
+ name = var.to_s
+ env_list << "#{name}: \"#{value}\""
+ end
+
+ # Process environment created by configuration
+ config[:environment].each do |env|
+ env.each_key do |key|
+ name = key.to_s.upcase
+ env_list << "#{name}: \"#{env[key]}\""
+ end
+ end
+
+ output = "Environment variables:\n"
+
+ env_list.sort.each do |line|
+ output << " âą #{line}\n"
+ end
+
+ @loginator.log() # Blank line
+ @loginator.log( output + "\n", Verbosity::NORMAL, LogLabels::TITLE )
+ end
+
+
+ def list_examples(env, app_cfg, options)
+ @helper.set_verbosity( options[:verbosity] )
+
+ # Process which_ceedling for app_cfg modifications but ignore return values
+ @helper.which_ceedling?( env:env, app_cfg:app_cfg )
+
+ examples = @helper.lookup_example_projects( app_cfg[:ceedling_examples_path] )
+
+ raise( "No examples projects found") if examples.empty?
+
+ output = "Available example projects:\n"
+
+ examples.each {|example| output << " âą #{example}\n" }
+
+ @loginator.log() # Blank line
+ @loginator.log( output + "\n", Verbosity::NORMAL, LogLabels::TITLE )
+ end
+
+
+ def create_example(env, app_cfg, options, name, dest)
+ @helper.set_verbosity( options[:verbosity] )
+
+ @path_validator.standardize_paths( dest )
+
+ # Process which_ceedling for app_cfg modifications but ignore return values
+ @helper.which_ceedling?( env:env, app_cfg:app_cfg )
+
+ examples = @helper.lookup_example_projects( app_cfg[:ceedling_examples_path] )
+
+ if !examples.include?( name )
+ raise( "No example project '#{name}' could be found" )
+ end
+
+ # If destination is nil, reassign it to name
+ # Otherwise, join the destination and name into a new path
+ dest = dest.nil? ? ('./' + name) : File.join( dest, name )
+
+ dest_src = File.join( dest, 'src' )
+ dest_test = File.join( dest, 'test' )
+ dest_mixin = File.join( dest, 'mixin' )
+ dest_project = File.join( dest, DEFAULT_PROJECT_FILENAME )
+ dest_readme = File.join( dest, 'README.md' )
+
+ # Thor Actions for project tasks use paths in relation to this path
+ ActionsWrapper.source_root( app_cfg[:ceedling_root_path] )
+
+ @actions._directory( "examples/#{name}/src", dest_src, :force => true )
+ @actions._directory( "examples/#{name}/test", dest_test, :force => true )
+ @actions._directory( "examples/#{name}/mixin", dest_mixin, :force => true )
+ @actions._copy_file( "examples/#{name}/#{DEFAULT_PROJECT_FILENAME}", dest_project, :force => true )
+ @actions._copy_file( "examples/#{name}/README.md", dest_readme, :force => true )
+
+ # Vendor the tools and install command line helper scripts
+ @helper.vendor_tools( app_cfg[:ceedling_root_path], dest ) if options[:local]
+
+ # Copy in documentation
+ @helper.copy_docs( app_cfg[:ceedling_root_path], dest ) if options[:docs]
+
+ @loginator.log() # Blank line
+ @loginator.log( "Example project '#{name}' created at #{dest}/\n", Verbosity::NORMAL, LogLabels::TITLE )
+ end
+
+
+ def version(env, app_cfg)
+ # Versionator is not needed to persist. So, it's not built in the DIY collection.
+
+ @helper.set_verbosity() # Default to normal
+
+ # Ceedling bootloader
+ launcher = Versionator.new( app_cfg[:ceedling_root_path] )
+
+ # This call updates Ceedling paths in app_cfg if which Ceedling has been modified
+ @helper.which_ceedling?( env:env, app_cfg:app_cfg )
+
+ # Ceedling application
+ application = Versionator.new(
+ app_cfg[:ceedling_root_path],
+ app_cfg[:ceedling_vendor_path]
+ )
+
+ # Blank Ceedling version block to be built out conditionally below
+ ceedling = nil
+
+ # A simple Ceedling version block because launcher and application are the same
+ if launcher.ceedling_install_path == application.ceedling_install_path
+ ceedling = <<~CEEDLING
+ Ceedling => #{application.ceedling_build}
+ ----------------------
+ #{application.ceedling_install_path + '/'}
+ CEEDLING
+
+ # Full Ceedling version block because launcher and application are not the same
+ else
+ ceedling = <<~CEEDLING
+ Ceedling Launcher => #{launcher.ceedling_build}
+ ----------------------
+ #{launcher.ceedling_install_path + '/'}
+
+ Ceedling App => #{application.ceedling_build}
+ ----------------------
+ #{application.ceedling_install_path + '/'}
+ CEEDLING
+ end
+
+ build_frameworks = <<~BUILD_FRAMEWORKS
+ Build Frameworks
+ ----------------------
+ CMock => #{application.cmock_tag}
+ Unity => #{application.unity_tag}
+ CException => #{application.cexception_tag}
+ BUILD_FRAMEWORKS
+
+ # Assemble version details
+ version = ceedling + "\n" + build_frameworks
+
+ # Add some indent
+ version = version.split( "\n" ).map {|line| ' ' + line}.join( "\n" )
+
+ # Add a header
+ version = "Welcome to Ceedling!\n\n" + version
+
+ @loginator.log( version, Verbosity::NORMAL, LogLabels::TITLE )
+ end
+
+
+ ### Private ###
+
+ private
+
+ def list_rake_tasks(env:, app_cfg:, filepath:nil, mixins:[], silent:false)
+ _, config =
+ @configinator.loadinate(
+ builtin_mixins:BUILTIN_MIXINS,
+ filepath: filepath,
+ mixins: mixins,
+ env: env,
+ silent: silent
+ )
+
+ # Save reference to loaded configuration
+ app_cfg.set_project_config( config )
+ app_cfg.set_logging_path( @helper.process_logging_path( config ) )
+
+ _, path = @helper.which_ceedling?( env:env, config:config, app_cfg:app_cfg )
+
+ @helper.load_ceedling(
+ config: config,
+ rakefile_path: path,
+ default_tasks: app_cfg[:default_tasks]
+ )
+
+ msg = "Ceedling build & plugin tasks:\n(Parameterized tasks tend to need enclosing quotes or escape sequences in most shells)"
+ @loginator.log( msg, Verbosity::NORMAL, LogLabels::TITLE )
+
+ @helper.print_rake_tasks()
+ end
+
+end
diff --git a/bin/cli_helper.rb b/bin/cli_helper.rb
new file mode 100644
index 000000000..25c50b50f
--- /dev/null
+++ b/bin/cli_helper.rb
@@ -0,0 +1,507 @@
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
+require 'app_cfg'
+
+# From Ceedling application
+require 'ceedling/constants'
+require 'ceedling/exceptions'
+
+class CliHelper
+
+ constructor :file_wrapper, :actions_wrapper, :config_walkinator, :path_validator, :loginator, :system_wrapper
+
+ def setup
+ # Aliases
+ @actions = @actions_wrapper
+ end
+
+
+ def project_exists?( path, op, *components )
+ exists = []
+
+ components.each do |f|
+ _path = File.join( path, f )
+ exists << (@file_wrapper.exist?( _path ) or @file_wrapper.directory?( _path ))
+ end
+
+ return exists.reduce(op)
+ end
+
+
+ def create_project_file(dest, local, ceedling_tag)
+ project_filepath = File.join( dest, DEFAULT_PROJECT_FILENAME )
+ source_filepath = ''
+
+ if local
+ source_filepath = File.join( 'assets', 'project_with_guts.yml' )
+ else
+ source_filepath = File.join( 'assets', 'project_as_gem.yml' )
+ end
+
+ # Clone the project file
+ @actions._copy_file( source_filepath, project_filepath, :force => true)
+ # Silently update internal version
+ @actions._gsub_file(
+ project_filepath,
+ /:ceedling_version:\s+'\?'/,
+ ":ceedling_version: #{ceedling_tag}",
+ :verbose => false
+ )
+ end
+
+
+ # Returns two value: (1) symbol :gem or :path and (2) path for Ceedling installation
+ def which_ceedling?(env:, config:{}, app_cfg:)
+ # Determine which Ceedling we're running (in priority)
+ # 1. If there's an environment variable set, validate it, and return :gem or a path
+ # 2. If :project âł :which_ceedling exists in the config, validate it, and return :gem or a path
+ # 3. If there's a vendor/ceedling/ path in our working directory, return it as a path
+ # 4. If nothing is set, default to :gem and return it
+ # 5. Update app_cfg paths if not the gem
+
+ # Nil for prioritized case checking logic blocks that follow
+ which_ceedling = nil
+
+ # Environment variable
+ if !env['WHICH_CEEDLING'].nil?
+ @loginator.log( " > Set which Ceedling using environment variable WHICH_CEEDLING", Verbosity::OBNOXIOUS )
+ which_ceedling = env['WHICH_CEEDLING'].strip()
+ which_ceedling = :gem if (which_ceedling.casecmp( 'gem' ) == 0)
+ end
+
+ # Configuration file
+ if which_ceedling.nil?
+ value, _ = @config_walkinator.fetch_value( :project, :which_ceedling, hash:config )
+ if !value.nil?
+ which_ceedling = value.strip()
+ @loginator.log( " > Set which Ceedling from config :project âł :which_ceedling => #{which_ceedling}", Verbosity::OBNOXIOUS )
+ which_ceedling = :gem if (which_ceedling.casecmp( 'gem' ) == 0)
+ end
+ end
+
+ # Working directory
+ if which_ceedling.nil?
+ if @file_wrapper.directory?( 'vendor/ceedling' )
+ which_ceedling = 'vendor/ceedling'
+ @loginator.log( " > Set which Ceedling to be vendored installation", Verbosity::OBNOXIOUS )
+ end
+ end
+
+ # Default to gem
+ if which_ceedling.nil?
+ which_ceedling = :gem
+ @loginator.log( " > Defaulting to running Ceedling from Gem", Verbosity::OBNOXIOUS )
+ end
+
+ # If we're launching from the gem, return :gem and initial Rakefile path
+ if which_ceedling == :gem
+ @loginator.log( " > Launching Ceedling from #{app_cfg[:ceedling_root_path]}/", Verbosity::OBNOXIOUS )
+ return which_ceedling, app_cfg[:ceedling_rakefile_filepath]
+ end
+
+ # Otherwise, handle which_ceedling as a base path
+ ceedling_path = which_ceedling.dup()
+ @path_validator.standardize_paths( ceedling_path )
+ if !@file_wrapper.directory?( ceedling_path )
+ raise "Configured Ceedling launch path #{ceedling_path}/ does not exist"
+ end
+
+ # Update Ceedling installation paths
+ app_cfg.set_paths( ceedling_path )
+
+ # Check updated Ceedling paths
+ if !@file_wrapper.exist?( app_cfg[:ceedling_rakefile_filepath] )
+ raise "Configured Ceedling launch path #{ceedling_path}/ contains no Ceedling installation"
+ end
+
+ # Update variable to full application start path
+ ceedling_path = app_cfg[:ceedling_rakefile_filepath]
+
+ @loginator.log( " > Launching Ceedling from #{app_cfg[:ceedling_root_path]}/", Verbosity::OBNOXIOUS )
+
+ return :path, ceedling_path
+ end
+
+
+ def load_ceedling(config:, rakefile_path:, default_tasks:[])
+ # Set default tasks
+ Rake::Task.define_task(:default => default_tasks) if !default_tasks.empty?
+
+ # Load Ceedling application from Rakefile path
+ require( rakefile_path )
+
+ # Loading the Rakefile manipulates the config hash, return it as a convenience
+ return config
+ end
+
+
+ def process_testcase_filters(config:, include:, exclude:, tasks:, default_tasks:)
+ # Do nothing if no test case filters
+ return if (include.nil? || include.empty?) && (exclude.nil? || exclude.empty?)
+
+ # TODO: When we can programmatically check if a task is a test task,
+ # raise an exception if --graceful-fail is set without test operations
+
+ # Add test runner configuration setting necessary to use test case filters
+ value, _ = @config_walkinator.fetch_value( :test_runner, hash:config )
+ if value.nil?
+ # If no :test_runner section, create the whole thing
+ config[:test_runner] = {:cmdline_args => true}
+ else
+ # If a :test_runner section, just set :cmdlne_args
+ value[:cmdline_args] = true
+ end
+ end
+
+
+ def process_graceful_fail(config:, cmdline_graceful_fail:, tasks:, default_tasks:)
+ # TODO: When we can programmatically check if a task is a test task,
+ # raise an exception if --graceful-fail is set without test operations
+
+ # Precedence
+ # 1. Command line option
+ # 2. Configuration entry
+
+ # If command line option was set, use it
+ return cmdline_graceful_fail if !cmdline_graceful_fail.nil?
+
+ # If configuration contains :graceful_fail, use it
+ value, _ = @config_walkinator.fetch_value( :test_build, :graceful_fail, hash:config )
+ return value if value.nil?
+
+ return false
+ end
+
+
+ def process_logging_path(config)
+ build_root, _ = @config_walkinator.fetch_value( :project, :build_root, hash:config )
+
+ return '' if build_root.nil?
+
+ return File.join( build_root, DEFAULT_BUILD_LOGS_PATH )
+ end
+
+
+ def process_log_filepath(logging_path, log, logfile)
+ filepath = nil
+
+ # --log => nil (default / not set), false (explicitly disabled), true (explicitly enabled)
+ if log == false
+ return ''
+ end
+
+ # --logfile => '' default or a path
+ if not logfile.empty?
+ filepath = logfile
+ # If logging is enabled without a filepath in --logfile, then set up the default path
+ elsif log
+ filepath = File.join( logging_path, DEFAULT_CEEDLING_LOGFILE )
+ elsif logfile.empty?
+ return ''
+ end
+
+ filepath = File.expand_path( filepath )
+
+ dir = File.dirname( filepath )
+
+ # Ensure logging directory path exists
+ if !File.exist?( dir )
+ @file_wrapper.mkdir( dir )
+ end
+
+ # Return filename/filepath
+ return filepath
+ end
+
+
+ # TODO: This is a hack until Rake is fully removed and plugin/build tasks incorporate a purpose classification
+ def build_or_plugin_task?(tasks:, default_tasks:)
+ _tasks = tasks.empty?() ? default_tasks.dup() : tasks.dup()
+
+ # These namespace-less tasks are definitely build tasks
+ return true if _tasks.include?('test')
+ return true if _tasks.include?('release')
+
+ # Namespace-less (clobber, clean, etc.), files:, and paths: tasks are not build / plugin tasks
+ # 1. Filter out tasks lacking a namespace
+ # 2. Look for any tasks other than paths: or files:
+ _tasks.select! {|t| t.include?( ':') }
+ _tasks.reject! {|t| t =~ /(^files:|^paths:)/}
+
+ return !_tasks.empty?
+ end
+
+
+ def print_rake_tasks()
+ # (This required digging into Rake internals a bit.)
+ Rake.application.define_singleton_method(:name=) {|n| @name = n}
+ Rake.application.name = 'ceedling'
+ Rake.application.options.show_tasks = :tasks
+ Rake.application.options.show_task_pattern = /^(?!.*build).*$/
+ Rake.application.display_tasks_and_comments()
+ end
+
+
+ def run_rake_tasks(tasks)
+ Rake.application.collect_command_line_tasks( tasks )
+
+ # Replace Rake's exception message to reduce any confusion
+ begin
+ Rake.application.top_level()
+
+ rescue RuntimeError => ex
+ # Check if exception contains an unknown Rake task message
+ matches = ex.message.match( /how to build task '(.+)'/i )
+
+ # If it does, replacing the message with our own
+ if !matches.nil? and matches.size == 2
+ message = "Unrecognized build task '#{matches[1]}'. List available build tasks with `ceedling help`."
+ raise CeedlingException.new( message )
+
+ # Otherwise, just re-raise
+ else
+ raise
+ end
+ end
+
+ end
+
+
+ # Set global consts for verbosity and debug
+ def set_verbosity(verbosity=nil)
+ # If we have already set verbosity, there's nothing to do here
+ return PROJECT_VERBOSITY if @system_wrapper.constants_include?('PROJECT_VERBOSITY')
+
+ verbosity = if verbosity.nil?
+ Verbosity::NORMAL
+ elsif verbosity.to_i.to_s == verbosity
+ verbosity.to_i
+ elsif VERBOSITY_OPTIONS.include? verbosity.to_sym
+ VERBOSITY_OPTIONS[verbosity.to_sym]
+ else
+ raise "Unkown Verbosity '#{verbosity}' specified"
+ end
+
+ # Create global constant PROJECT_VERBOSITY
+ Object.module_eval("PROJECT_VERBOSITY = verbosity")
+ PROJECT_VERBOSITY.freeze()
+
+ # Create global constant PROJECT_DEBUG
+ debug = (verbosity == Verbosity::DEBUG)
+ Object.module_eval("PROJECT_DEBUG = debug")
+ PROJECT_DEBUG.freeze()
+
+ return verbosity
+ end
+
+
+ def dump_yaml(config, filepath, sections)
+ # Default to dumping entire configuration
+ _config = config
+
+ # If sections were provided, process them
+ if !sections.empty?
+ # Symbolify section names
+ _sections = sections.map {|section| section.to_sym}
+
+ # Try to extract subconfig from section path
+ value, _ = @config_walkinator.fetch_value( *_sections, hash:config )
+
+ # If we fail to find the section path, blow up
+ if value.nil?
+ # Reformat list of symbols to list of :s
+ _sections.map! {|section| ":#{section.to_s}"}
+ msg = "Cound not find configuration section #{_sections.join(' âł ')}"
+ raise(msg)
+ end
+
+ # Update _config to subconfig with final sections path element as container
+ _config = { _sections.last => value }
+ end
+
+ File.open( filepath, 'w' ) {|out| YAML.dump( _config, out )}
+ end
+
+
+ def lookup_example_projects(examples_path)
+ examples = []
+
+ # Examples directory listing glob
+ glob = File.join( examples_path, '*' )
+
+ @file_wrapper.directory_listing(glob).each do |path|
+ # Skip anything that's not a directory
+ next if !@file_wrapper.directory?( path )
+
+ # Split the directory path into elements, indexing the last one
+ project = (path.split( File::SEPARATOR ))[-1]
+
+ examples << project
+ end
+
+ return examples
+ end
+
+
+ def copy_docs(ceedling_root, dest)
+ docs_path = File.join( dest, 'docs' )
+
+ # Hash that will hold documentation copy paths
+ # - Key: (modified) destination documentation path
+ # - Value: source path
+ doc_files = {}
+
+ # Add docs to list from Ceedling (docs/) and supporting projects (docs/)
+ { # Source path => docs/ destination path
+ 'docs' => '.',
+ 'vendor/unity/docs' => 'unity',
+ 'vendor/cmock/docs' => 'cmock',
+ 'vendor/c_exception/docs' => 'c_exception'
+ }.each do |src, dest|
+ # Form glob to collect all markdown files
+ glob = File.join( ceedling_root, src, '*.md' )
+ # Look up markdown files
+ listing = @file_wrapper.directory_listing( glob ) # Already case-insensitive
+ # For each markdown filepath, add to hash
+ listing.each do |filepath|
+ # Reassign destination
+ _dest = File.join( dest, File.basename(filepath) )
+ doc_files[ _dest ] = filepath
+ end
+ end
+
+ # Add docs to list from Ceedling plugins (docs/plugins)
+ glob = File.join( ceedling_root, 'plugins/**/README.md' )
+ listing = @file_wrapper.directory_listing( glob ) # Already case-insensitive
+ listing.each do |path|
+ # 'README.md' => '.md' where name extracted from containing path
+ rename = path.split(/\\|\//)[-2] + '.md'
+ # For each Ceedling plugin readme, add to hash
+ dest = File.join( 'plugins', rename )
+ doc_files[ dest ] = path
+ end
+
+ # Add licenses from Ceedling (docs/) and supporting projects (docs/)
+ { # Destination path => Source path
+ '.' => '.', # Ceedling
+ 'unity' => 'vendor/unity',
+ 'cmock' => 'vendor/cmock',
+ 'c_exception' => 'vendor/c_exception',
+ }.each do |dest, src|
+ glob = File.join( ceedling_root, src, 'license.txt' )
+ # Look up licenses (use glob as capitalization can be inconsistent)
+ listing = @file_wrapper.directory_listing( glob ) # Already case-insensitive
+ # Safety check on nil references since we explicitly reference first element
+ next if listing.empty?
+ filepath = listing.first
+ # Reassign dest
+ dest = File.join( dest, File.basename( filepath ) )
+ doc_files[ dest ] = filepath
+ end
+
+ # Copy all documentation
+ doc_files.each_pair do |dest, src|
+ @actions._copy_file(src, File.join( docs_path, dest ), :force => true)
+ end
+ end
+
+
+ def vendor_tools(ceedling_root, dest)
+ vendor_path = File.join( dest, 'vendor', 'ceedling' )
+
+ # Copy folders from current Ceedling into project
+ %w{plugins lib bin}.each do |folder|
+ @actions._directory(
+ folder,
+ File.join( vendor_path, folder ),
+ :force => true
+ )
+ end
+
+ # Mark ceedling as an executable
+ @actions._chmod( File.join( vendor_path, 'bin', 'ceedling' ), 0755 ) unless @system_wrapper.windows?
+
+ # Assembly necessary subcomponent dirs
+ components = [
+ 'vendor/c_exception/lib/',
+ 'vendor/cmock/config/',
+ 'vendor/cmock/lib/',
+ 'vendor/cmock/src/',
+ 'vendor/diy/lib/',
+ 'vendor/unity/auto/',
+ 'vendor/unity/src/',
+ ]
+
+ # Copy necessary subcomponent dirs into project
+ components.each do |path|
+ _src = path
+ _dest = File.join( vendor_path, path )
+ # Copy entire directory, filter out any junk files
+ @actions._directory(
+ _src, _dest,
+ :force => true
+ )
+ end
+
+ # Add licenses from Ceedling and supporting projects
+ license_files = {}
+ [ # Source paths
+ '.', # Ceedling
+ 'vendor/unity',
+ 'vendor/cmock',
+ 'vendor/c_exception',
+ 'vendor/diy'
+ ].each do |src|
+ # Look up licenses using a Glob as capitalization can be inconsistent
+ glob = File.join( ceedling_root, src, 'license.txt' )
+ listing = @file_wrapper.directory_listing( glob ) # Already case-insensitive
+
+ # Safety check on nil references since we explicitly reference first element
+ next if listing.empty?
+
+ # Add license copying to hash
+ license = listing.first
+ filepath = File.join( vendor_path, src, File.basename( license ) )
+ license_files[ filepath ] = license
+ end
+
+ # Copy license files into place
+ license_files.each_pair do |dest, src|
+ @actions._copy_file( src, dest, :force => true)
+ end
+
+ # Silently copy Git SHA file for version #.#.#-build lookups if it exists
+ if @file_wrapper.exist?( File.join( ceedling_root, GIT_COMMIT_SHA_FILENAME) )
+ @actions._copy_file(
+ GIT_COMMIT_SHA_FILENAME,
+ File.join( vendor_path, GIT_COMMIT_SHA_FILENAME ),
+ :force => true, :verbose => false
+ )
+ end
+
+ # Create executable helper scripts in project root
+ if @system_wrapper.windows?
+ # Windows command prompt launch script
+ @actions._copy_file(
+ File.join( 'assets', 'ceedling.cmd'),
+ File.join( dest, 'ceedling.cmd'),
+ :force => true
+ )
+ else
+ # Unix shell launch script
+ launch = File.join( dest, 'ceedling')
+ @actions._copy_file(
+ File.join( 'assets', 'ceedling'),
+ launch,
+ :force => true
+ )
+ @actions._chmod( launch, 0755 )
+ end
+ end
+
+end
diff --git a/bin/configinator.rb b/bin/configinator.rb
new file mode 100644
index 000000000..28fe3ada4
--- /dev/null
+++ b/bin/configinator.rb
@@ -0,0 +1,111 @@
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
+require 'deep_merge'
+
+class Configinator
+
+ constructor :config_walkinator, :projectinator, :mixinator
+
+ def loadinate(builtin_mixins:, filepath:nil, mixins:[], env:{}, silent:false)
+ # Aliases for clarity
+ cmdline_filepath = filepath
+ cmdline_mixins = mixins || []
+
+ # Load raw config from command line, environment variable, or default filepath
+ project_filepath, config = @projectinator.load( filepath:cmdline_filepath, env:env, silent:silent )
+
+ # Extract cfg_enabled_mixins mixins list plus load paths list from config
+ cfg_enabled_mixins, cfg_load_paths = @projectinator.extract_mixins( config: config )
+
+ # Get our YAML file extension
+ yaml_ext = @projectinator.lookup_yaml_extension( config:config )
+
+ # Remove any silly redundancies
+ cfg_enabled_mixins.uniq!
+ # Use absolute path to ensure proper deduplication
+ cfg_load_paths.uniq! { |path| File.expand_path(path) }
+ cmdline_mixins.uniq!
+
+ # Validate :cfg_load_paths from :mixins section of project configuration
+ @projectinator.validate_mixin_load_paths( cfg_load_paths )
+
+ # Validate enabled mixins from :mixins section of project configuration
+ if not @projectinator.validate_mixins(
+ mixins: cfg_enabled_mixins,
+ load_paths: cfg_load_paths,
+ builtins: builtin_mixins,
+ source: 'Config :mixins âł :enabled =>',
+ yaml_extension: yaml_ext
+ )
+ raise 'Project configuration file section :mixins failed validation'
+ end
+
+ # Validate command line mixins
+ if not @projectinator.validate_mixins(
+ mixins: cmdline_mixins,
+ load_paths: cfg_load_paths,
+ builtins: builtin_mixins,
+ source: 'Mixin',
+ yaml_extension: yaml_ext
+ )
+ raise 'Command line failed validation'
+ end
+
+ # Find mixins in project file among load paths or built-in mixins
+ # Return ordered list of filepaths or built-in mixin names
+ config_mixins = @projectinator.lookup_mixins(
+ mixins: cfg_enabled_mixins,
+ load_paths: cfg_load_paths,
+ builtins: builtin_mixins,
+ yaml_extension: yaml_ext
+ )
+
+ # Find mixins from command line among load paths or built-in mixins
+ # Return ordered list of filepaths or built-in mixin names
+ cmdline_mixins = @projectinator.lookup_mixins(
+ mixins: cmdline_mixins,
+ load_paths: cfg_load_paths,
+ builtins: builtin_mixins,
+ yaml_extension: yaml_ext
+ )
+
+ # Fetch CEEDLING_MIXIN_# environment variables
+ # Sort into ordered list of hash tuples [{env variable => filepath}...]
+ env_mixins = @mixinator.fetch_env_filepaths( env )
+ @mixinator.validate_env_filepaths( env_mixins )
+
+ # Eliminate duplicate mixins and return list of mixins in merge order
+ # [{source => filepath}...]
+ mixins_assembled = @mixinator.assemble_mixins(
+ config: config_mixins,
+ env: env_mixins,
+ cmdline: cmdline_mixins
+ )
+
+ # Merge mixins
+ @mixinator.merge( builtins:builtin_mixins, config:config, mixins:mixins_assembled )
+
+ return project_filepath, config
+ end
+
+ def default_tasks(config:, default_tasks:)
+ # 1. If :default_tasks set in config, use it
+ # 2. Otherwise use the function argument (most likely a default set in the first moments of startup)
+ value, _ = @config_walkinator.fetch_value( :project, :default_tasks, hash:config )
+ if value
+ # Update method parameter to config value
+ default_tasks = value.dup()
+ else
+ # Set key/value in config if it's not set
+ config.deep_merge( {:project => {:default_tasks => default_tasks}} )
+ end
+
+ return default_tasks
+ end
+
+end
\ No newline at end of file
diff --git a/bin/mixinator.rb b/bin/mixinator.rb
new file mode 100644
index 000000000..5ff81d628
--- /dev/null
+++ b/bin/mixinator.rb
@@ -0,0 +1,136 @@
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
+require 'deep_merge'
+
+class Mixinator
+
+ constructor :path_validator, :yaml_wrapper, :loginator
+
+ def setup
+ # ...
+ end
+
+ def validate_cmdline_filepaths(paths)
+ validated = @path_validator.validate(
+ paths: paths,
+ source: 'Filepath argument',
+ )
+
+ if !validated
+ raise 'Mixins command line failed validation'
+ end
+ end
+
+ def fetch_env_filepaths(env)
+ var_names = []
+
+ env.each do |var, filepath|
+ # Explicitly ignores CEEDLING_MIXIN_0
+ var_names << var if var =~ /CEEDLING_MIXIN_[1-9]\d*/
+ end
+
+ # Extract numeric string (guranteed to exist) and convert to integer for ascending sorting
+ var_names.sort_by! {|name| name.match(/\d+$/)[0].to_i() }
+
+ _vars = []
+ # Iterate over sorted environment variable names
+ var_names.each do |name|
+ # Duplicate the filepath string to get unfrozen copy
+ # Handle any Windows path shenanigans
+ # Insert in array {env var name => filepath}
+ path = env[name].dup()
+ @path_validator.standardize_paths( path )
+ _vars << {name => path}
+ end
+
+ # Remove any duplicate filepaths by comparing the full absolute path
+ # Higher numbered environment variables removed
+ _vars.uniq! {|entry| File.expand_path( entry.values.first )}
+
+ return _vars
+ end
+
+ def validate_env_filepaths(vars)
+ validated = true
+
+ vars.each do |entry|
+ validated &= @path_validator.validate(
+ paths: [entry.values.first],
+ source: "Environment variable `#{entry.keys.first}` filepath",
+ )
+ end
+
+ if !validated
+ raise 'Mixins environment variables failed validation'
+ end
+ end
+
+ def assemble_mixins(config:, env:, cmdline:)
+ assembly = []
+
+ # Build list of hashses in precedence order to facilitate deduplication
+ # Any duplicates at greater indexes are removed
+ cmdline.each {|mixin| assembly << {'command line' => mixin}}
+ assembly += env
+ config.each {|mixin| assembly << {'project configuration' => mixin}}
+
+ # Remove duplicates inline
+ # 1. Expand filepaths to absolute paths for correct deduplication (skip expanding simple mixin names)
+ # 2. Remove duplicates
+ assembly.uniq! do |entry|
+ # If entry is filepath, expand it, otherwise leave entry untouched (it's a mixin name only)
+ mixin = entry.values.first
+ @path_validator.filepath?( mixin ) ? File.expand_path( mixin ) : mixin
+ end
+
+ # Return the compacted list in merge order
+ # 1. Config
+ # 2. Environment variable
+ # 3. Command line
+ # Later merges take precedence (e.g. command line mixins are last merge)
+ return assembly.reverse()
+ end
+
+ def merge(builtins:, config:, mixins:)
+ mixins.each do |mixin|
+ source = mixin.keys.first
+ filepath = mixin.values.first
+
+ _mixin = {} # Empty initial value
+
+ # Load mixin from filepath if it is a filepath
+ if @path_validator.filepath?( filepath )
+ _mixin = @yaml_wrapper.load( filepath )
+
+ # Log what filepath we used for this mixin
+ @loginator.log( " + Merging #{'(empty) ' if _mixin.nil?}#{source} mixin using #{filepath}", Verbosity::OBNOXIOUS )
+
+ # Reference mixin from built-in hash-based mixins
+ else
+ _mixin = builtins[filepath.to_sym()]
+
+ # Log built-in mixin we used
+ @loginator.log( " + Merging built-in mixin '#{filepath}' from #{source}", Verbosity::OBNOXIOUS )
+ end
+
+ # Hnadle an empty mixin (it's unlikely but logically coherent and a good safety check)
+ _mixin = {} if _mixin.nil?
+
+ # Sanitize the mixin config by removing any :mixins section (these should not end up in merges)
+ _mixin.delete(:mixins)
+
+ # Merge this bad boy
+ config.deep_merge( _mixin )
+ end
+
+ # Validate final configuration
+ msg = "Final configuration is empty"
+ raise msg if config.empty?
+ end
+
+end
diff --git a/bin/mixins.rb b/bin/mixins.rb
new file mode 100644
index 000000000..2c95a228e
--- /dev/null
+++ b/bin/mixins.rb
@@ -0,0 +1,5 @@
+
+BUILTIN_MIXINS = {
+ # Mixin name as symbol => mixin config hash
+ # :mixin => {}
+}
diff --git a/bin/objects.yml b/bin/objects.yml
new file mode 100644
index 000000000..cf63d15aa
--- /dev/null
+++ b/bin/objects.yml
@@ -0,0 +1,80 @@
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
+#
+# Loaded from lib/
+# ----------------
+#
+
+file_wrapper:
+
+yaml_wrapper:
+
+config_walkinator:
+
+system_wrapper:
+
+verbosinator:
+
+loginator:
+ compose:
+ - verbosinator
+ - file_wrapper
+ - system_wrapper
+
+#
+# Loaded from bin/
+# ----------------
+#
+
+actions_wrapper:
+
+# Separation of logic from CLI user interface
+cli_handler:
+ compose:
+ - configinator
+ - projectinator
+ - cli_helper
+ - path_validator
+ - actions_wrapper
+ - loginator
+
+cli_helper:
+ compose:
+ - file_wrapper
+ - config_walkinator
+ - path_validator
+ - actions_wrapper
+ - loginator
+ - system_wrapper
+
+path_validator:
+ compose:
+ - file_wrapper
+ - loginator
+
+mixinator:
+ compose:
+ - path_validator
+ - yaml_wrapper
+ - loginator
+
+projectinator:
+ compose:
+ - file_wrapper
+ - path_validator
+ - yaml_wrapper
+ - loginator
+ - system_wrapper
+
+configinator:
+ compose:
+ - config_walkinator
+ - projectinator
+ - mixinator
+
+
diff --git a/bin/path_validator.rb b/bin/path_validator.rb
new file mode 100644
index 000000000..91dd793f5
--- /dev/null
+++ b/bin/path_validator.rb
@@ -0,0 +1,54 @@
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
+class PathValidator
+
+ constructor :file_wrapper, :loginator
+
+ def validate(paths:, source:, type: :filepath)
+ validated = true
+
+ paths.each do |path|
+ # Error out on empty paths
+ if path.empty?
+ validated = false
+ @loginator.log( "#{source} contains an empty path", Verbosity::ERRORS )
+ next
+ end
+
+ # Error out if path is not a directory / does not exist
+ if (type == :directory) and !@file_wrapper.directory?( path )
+ validated = false
+ @loginator.log( "#{source} '#{path}' does not exist as a directory in the filesystem", Verbosity::ERRORS )
+ end
+
+ # Error out if filepath does not exist
+ if (type == :filepath) and !@file_wrapper.exist?( path )
+ validated = false
+ @loginator.log( "#{source} '#{path}' does not exist in the filesystem", Verbosity::ERRORS )
+ end
+ end
+
+ return validated
+ end
+
+ # Ensure any Windows backslashes are converted to Ruby path forward slashes
+ # Santization happens inline
+ def standardize_paths( *paths )
+ paths.each do |path|
+ next if path.nil? or path.empty?
+ path.gsub!( "\\", '/' )
+ end
+ end
+
+
+ def filepath?(str)
+ # If argument includes a file extension or a path separator, it's a filepath
+ return (!File.extname( str ).empty?) || (str.include?( File::SEPARATOR ))
+ end
+
+end
\ No newline at end of file
diff --git a/bin/projectinator.rb b/bin/projectinator.rb
new file mode 100644
index 000000000..7e7bc221b
--- /dev/null
+++ b/bin/projectinator.rb
@@ -0,0 +1,244 @@
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
+require 'ceedling/constants' # From Ceedling application
+
+class Projectinator
+
+ PROJECT_FILEPATH_ENV_VAR = 'CEEDLING_PROJECT_FILE'
+ DEFAULT_PROJECT_FILEPATH = './' + DEFAULT_PROJECT_FILENAME
+ DEFAULT_YAML_FILE_EXTENSION = '.yml'
+
+ constructor :file_wrapper, :path_validator, :yaml_wrapper, :loginator, :system_wrapper
+
+ # Discovers project file path and loads configuration.
+ # Precendence of attempts:
+ # 1. Explcit flepath from argument
+ # 2. Environment variable
+ # 3. Default filename in working directory
+ # Returns:
+ # - Absolute path of project file found and used
+ # - Config hash loaded from project file
+ def load(filepath:nil, env:{}, silent:false)
+ # Highest priority: command line argument
+ if filepath
+ @path_validator.standardize_paths( filepath )
+ _filepath = File.expand_path( filepath )
+ config = load_and_log( _filepath, 'from command line argument', silent )
+ return _filepath, config
+
+ # Next priority: environment variable
+ elsif env[PROJECT_FILEPATH_ENV_VAR]
+ # ENV lookup is frozen so dup() to operate on the string
+ filepath = env[PROJECT_FILEPATH_ENV_VAR].dup()
+ @path_validator.standardize_paths( filepath )
+ _filepath = File.expand_path( filepath )
+ config = load_and_log(
+ _filepath,
+ "from environment variable `#{PROJECT_FILEPATH_ENV_VAR}`",
+ silent
+ )
+ return _filepath, config
+
+ # Final option: default filepath
+ elsif @file_wrapper.exist?( DEFAULT_PROJECT_FILEPATH )
+ filepath = DEFAULT_PROJECT_FILEPATH
+ _filepath = File.expand_path( filepath )
+ config = load_and_log( _filepath, "from working directory", silent )
+ return _filepath, config
+
+ # If no user provided filepath and the default filepath does not exist,
+ # we have a big problem
+ else
+ raise "No project filepath provided and default #{DEFAULT_PROJECT_FILEPATH} not found"
+ end
+
+ # We'll never get here but return nil/empty for completeness
+ return nil, {}
+ end
+
+
+ # Determine if project configuration is available.
+ # - Simplest, default case simply tries to load default project file location.
+ # - Otherwise, attempts to load a filepath, the default environment variable,
+ # or both can be specified.
+ def config_available?(filepath:nil, env:{}, silent:true)
+ available = true
+
+ begin
+ load(filepath:filepath, env:env, silent:silent)
+ rescue
+ available = false
+ end
+
+ return available
+ end
+
+
+ def lookup_yaml_extension(config:)
+ return DEFAULT_YAML_FILE_EXTENSION if config[:extension].nil?
+
+ return DEFAULT_YAML_FILE_EXTENSION if config[:extension][:yaml].nil?
+
+ return config[:extension][:yaml]
+ end
+
+
+ # Pick apart a :mixins projcet configuration section and return components
+ # Layout mirrors :plugins section
+ def extract_mixins(config:)
+ # Get mixins config hash
+ _mixins = config[:mixins]
+
+ # If no :mixins section, return:
+ # - Empty enabled list
+ # - Empty load paths
+ return [], [] if _mixins.nil?
+
+ # Build list of load paths
+ # Configured load paths are higher in search path ordering
+ load_paths = _mixins[:load_paths] || []
+
+ # Get list of mixins
+ enabled = _mixins[:enabled] || []
+ enabled = enabled.clone # Ensure it's a copy of configuration section
+
+ # Handle any inline Ruby string expansion
+ load_paths.each do |load_path|
+ load_path.replace( @system_wrapper.module_eval( load_path ) ) if (load_path =~ RUBY_STRING_REPLACEMENT_PATTERN)
+ end
+
+ enabled.each do |mixin|
+ mixin.replace( @system_wrapper.module_eval( mixin ) ) if (mixin =~ RUBY_STRING_REPLACEMENT_PATTERN)
+ end
+
+ # Remove the :mixins section of the configuration
+ config.delete( :mixins )
+
+ return enabled, load_paths
+ end
+
+
+ # Validate :load_paths from :mixins section in project configuration
+ def validate_mixin_load_paths(load_paths)
+ validated = @path_validator.validate(
+ paths: load_paths,
+ source: 'Config :mixins âł :load_paths =>',
+ type: :directory
+ )
+
+ if !validated
+ raise 'Project configuration file section :mixins failed validation'
+ end
+ end
+
+
+ # Validate mixins list
+ def validate_mixins(mixins:, load_paths:, builtins:, source:, yaml_extension:)
+ validated = true
+
+ mixins.each do |mixin|
+ # Validate mixin filepaths
+ if @path_validator.filepath?( mixin )
+ if !@file_wrapper.exist?( mixin )
+ @loginator.log( "Cannot find mixin at #{mixin}", Verbosity::ERRORS )
+ validated = false
+ end
+
+ # Otherwise, validate that mixin name can be found in load paths or builtins
+ else
+ found = false
+ load_paths.each do |path|
+ if @file_wrapper.exist?( File.join( path, mixin + yaml_extension ) )
+ found = true
+ break
+ end
+ end
+
+ builtins.keys.each {|key| found = true if (mixin == key.to_s)}
+
+ if !found
+ msg = "#{source} '#{mixin}' cannot be found in mixin load paths as '#{mixin + yaml_extension}' or among built-in mixins"
+ @loginator.log( msg, Verbosity::ERRORS )
+ validated = false
+ end
+ end
+ end
+
+ return validated
+ end
+
+
+ # Yield ordered list of filepaths or built-in mixin names
+ def lookup_mixins(mixins:, load_paths:, builtins:, yaml_extension:)
+ _mixins = []
+
+ # Already validated, so we know:
+ # 1. Any mixin filepaths exists
+ # 2. Built-in mixin names exist in the internal hash
+
+ # Fill filepaths array with filepaths or builtin names
+ mixins.each do |mixin|
+ # Handle explicit filepaths
+ if @path_validator.filepath?( mixin )
+ _mixins << mixin
+ next # Success, move on in mixin iteration
+ end
+
+ # Look for mixin in load paths.
+ # Move on in mixin iteration if mixin is found.
+ next if load_paths.any? do |path|
+ filepath = File.join( path, mixin + yaml_extension )
+ exist = @file_wrapper.exist?( filepath )
+ _mixins << filepath if exist
+ exist
+ end
+
+ # Finally, fall through to simply add the unmodified name to the list.
+ # It's a built-in mixin.
+ _mixins << mixin
+ end
+
+ return _mixins
+ end
+
+ ### Private ###
+
+ private
+
+ def load_and_log(filepath, method, silent)
+ begin
+ # Load the filepath we settled on as our project configuration
+ config = @yaml_wrapper.load( filepath )
+
+ # A blank configuration file is technically an option (assuming mixins are merged)
+ # Redefine config as empty hash
+ config = {} if config.nil?
+
+ # Log what the heck we loaded
+ if !silent
+ msg = "Loaded #{'(empty) ' if config.empty?}project configuration #{method}.\n"
+ msg += " > Using: #{filepath}\n"
+ msg += " > Working directory: #{Dir.pwd()}"
+
+ @loginator.log( msg, Verbosity::NORMAL, LogLabels::CONSTRUCT )
+ end
+
+ return config
+ rescue Errno::ENOENT
+ # Handle special case of user-provided blank filepath
+ filepath = filepath.empty?() ? '' : filepath
+ raise "Could not find project filepath #{filepath} #{method}"
+
+ rescue StandardError => e
+ # Catch-all error handling
+ raise "Error loading project filepath #{filepath} #{method}: #{e.message}"
+ end
+
+ end
+
+end
diff --git a/bin/versionator.rb b/bin/versionator.rb
new file mode 100644
index 000000000..c90a53682
--- /dev/null
+++ b/bin/versionator.rb
@@ -0,0 +1,81 @@
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
+require 'exceptions'
+require 'constants' # Filename constants
+require 'version' # Import Ceedling constant symbols from lib/version.rb
+
+## Definitions
+## TAG: <#.#.#> version string used to package the software bundle
+## BUILD: TAG combined with git commit hash (<#.#.#>-)
+
+class Versionator
+
+ attr_reader :ceedling_tag, :ceedling_build, :ceedling_install_path
+ attr_reader :unity_tag, :cmock_tag, :cexception_tag
+
+ def initialize(ceedling_root_path, ceedling_vendor_path=nil)
+
+ ##
+ ## Ceedling version info
+ ##
+
+ @ceedling_install_path = ceedling_root_path.clone()
+ ceedling_git_sha = nil
+
+ # Set Ceedling tag
+ @ceedling_tag = Ceedling::Version::TAG
+
+ # Create Ceedling build string
+ # Lookup the Ceedling Git commit SHA if it exists as simple text file in the root of the codebase
+ ceedling_commit_sha_filepath = File.join( ceedling_root_path, GIT_COMMIT_SHA_FILENAME )
+ @ceedling_build =
+ if File.exist?( ceedling_commit_sha_filepath )
+ # Ingest text from commit SHA file and clean it up
+ sha = File.read( ceedling_commit_sha_filepath ).strip()
+ # -
+ "#{@ceedling_tag}-#{sha}"
+ else
+ #
+ @ceedling_tag
+ end
+
+ ##
+ ## Build frameworks version info
+ ##
+
+ # Do no framework version gathering if it's not asked for
+ return if ceedling_vendor_path.nil?
+
+ # Create _tag accessors in the Versionator object
+
+ # Anonymous hash to iterate through complementary vendor projects
+ { 'UNITY' => File.join( 'unity', 'src', 'unity.h' ),
+ 'CMOCK' => File.join( 'cmock', 'src', 'cmock.h' ),
+ 'CEXCEPTION' => File.join( 'c_exception', 'lib', 'CException.h' )
+ }.each_pair do |name, path|
+ filename = File.join( ceedling_vendor_path, path )
+
+ # Actually look up the vendor project version number components
+ version = [0,0,0]
+
+ begin
+ File.readlines( filename ).each do |line|
+ ['VERSION_MAJOR', 'VERSION_MINOR', 'VERSION_BUILD'].each_with_index do |field, i|
+ m = line.match(/#{name}_#{field}\s+(\d+)/)
+ version[i] = m[1] unless (m.nil?)
+ end
+ end
+ rescue
+ raise CeedlingException.new( "Could not collect version information for vendor component: #{filename}" )
+ end
+
+ # Splat version and evaluate it to create Versionator object accessor
+ eval("@#{name.downcase}_tag = '#{version.join(".")}'")
+ end
+ end
+end
diff --git a/ceedling.gemspec b/ceedling.gemspec
index 2c1f6b6d8..d29342e9c 100644
--- a/ceedling.gemspec
+++ b/ceedling.gemspec
@@ -1,6 +1,13 @@
# -*- encoding: utf-8 -*-
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
+
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), 'lib'))
-require "ceedling/version"
+require "version" # lib/version.rb
require 'date'
Gem::Specification.new do |s|
@@ -9,12 +16,14 @@ Gem::Specification.new do |s|
s.platform = Gem::Platform::RUBY
s.authors = ["Mark VanderVoord", "Michael Karlesky", "Greg Williams"]
s.email = ["mark@vandervoord.net", "michael@karlesky.net", "barney.williams@gmail.com"]
- s.homepage = "http://throwtheswitch.org/ceedling"
- s.summary = "Ceedling is a build automation tool for C unit test suites that packages up Unity, CMock, and Rake-based build management functionality"
+ s.homepage = "https://throwtheswitch.org/ceedling"
+ s.summary = "Ceedling is a build automation tool for C unit tests and releases. It's a member of the ThrowTheSwitch.org family of tools. It's built upon Unity and CMock."
s.description = <<-DESC
Ceedling is a build automation tool that helps you create and run C unit test suites.
-Ceedling provides two core functions: [1] It packages up several tools including the C unit test framework Unity, the Ruby-based mock generation tool CMock, and a C exception library CException. [2] It extends Rake with functionality specific to generating, building, and executing C test suites.
+Ceedling provides two core functions:
+ [1] It packages up several tools including the C unit test framework Unity, the mock generation tool CMock, and other features.
+ [2] It simplifies tool configuration for embedded or native C toolchains and automates the running and reporting of tests.
Ceedling projects are created with a YAML configuration file. A variety of conventions within the tool simplify generating mocks from C files and assembling suites of unit test functions.
DESC
@@ -28,12 +37,14 @@ Ceedling projects are created with a YAML configuration file. A variety of conve
"source_code_uri" => "https://github.com/ThrowTheSwitch/Ceedling"
}
- s.required_ruby_version = ">= 2.7.0"
+ s.required_ruby_version = ">= 3.0.0"
- s.add_dependency "thor", ">= 0.14"
+ s.add_dependency "thor", "~> 1.3"
s.add_dependency "rake", ">= 12", "< 14"
s.add_dependency "deep_merge", "~> 1.2"
+ s.add_dependency "diy", "~> 1.1"
s.add_dependency "constructor", "~> 2"
+ s.add_dependency "unicode-display_width", "~> 3.1"
# Files needed from submodules
s.files = []
@@ -45,9 +56,9 @@ Ceedling projects are created with a YAML configuration file. A variety of conve
s.files += Dir['vendor/unity/auto/**/*.rb']
s.files += Dir['vendor/unity/src/**/*.[ch]']
- s.files += Dir['**/*']
- s.test_files = Dir['test/**/*', 'spec/**/*', 'features/**/*']
- s.executables = Dir['bin/**/*'].map{|f| File.basename(f)}
+ s.files += Dir['**/*']
+ s.test_files = Dir['test/**/*', 'spec/**/*', 'features/**/*']
+ s.executables = ['ceedling'] # bin/ceedling
s.require_paths = ["lib", "vendor/cmock/lib"]
end
diff --git a/config/test_environment.rb b/config/test_environment.rb
index 377aa1935..b2572abc0 100644
--- a/config/test_environment.rb
+++ b/config/test_environment.rb
@@ -1,10 +1,14 @@
+# =========================================================================
+# Ceedling - Test-Centered Build System for C
+# ThrowTheSwitch.org
+# Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams
+# SPDX-License-Identifier: MIT
+# =========================================================================
# Setup our load path:
[
'lib',
'test',
- 'vendor/behaviors/lib',
- 'vendor/hardmock/lib',
].each do |dir|
$LOAD_PATH.unshift( File.join( File.expand_path(File.dirname(__FILE__) + "/../"), dir) )
end
diff --git a/docs/BreakingChanges.md b/docs/BreakingChanges.md
new file mode 100644
index 000000000..13ad8c7d6
--- /dev/null
+++ b/docs/BreakingChanges.md
@@ -0,0 +1,250 @@
+# đ± Ceedling Breaking Changes
+
+These breaking changes are complemented by two other documents:
+
+1. đ **[Release Notes](ReleaseNotes.md)** for announcements, education, acknowledgements, and known issues.
+1. đȘ” **[Changelog](Changelog.md)** for a structured list of additions, fixes, changes, and removals.
+
+---
+
+# [1.0.0 pre-release] â 2024-11-28
+
+## Explicit `:paths` âł `:include` entries in the project file
+
+The `:paths` âł `:include` entries in the project file must now be explicit and complete.
+
+Eaerlier versions of Ceedling were rather accomodating when assembling the search paths for header files. The full list of directories was pulled from multiple `:paths` entries with de-duplication. If you had header files in your `:source` directories but did not explicitly list those directories in your `:include` paths, Ceedling would helpfully figure it out and use all the paths.
+
+This behavior is no more. Why? For two interrelated reasons.
+
+1. For large or complex projects, expansive header file search path lists can exceed command line maximum lengths on some platforms. An enforced, tailored set of search paths helps prevent this problem.
+1. In order to support the desired behavior of `TEST_INCLUDE_PATH()` a concice set of âbaseâ header file search paths is necessary. `:paths` âł `:include` is that base list.
+
+Using 0.32 Ceedling with older project files can lead to errors when generating mocks or compiler errors on finding header files. Add all relevant header file search paths to the `:paths` âł `:include` project file entry to fix this problem.
+
+## Format change for `:defines` in the project file
+
+To better support per-test-executable configurations, the format of `:defines` has changed. See the [official documentation](CeedlingPacket.md) for specifics.
+
+In brief:
+
+1. A more logically named hierarchy differentiates `#define`s for test preprocessing, test compilation, and release compilation.
+1. Previously, compilation symbols could be specified for a specific C file by name, but these symbols were only defined when compiling that specific file. Further, this matching was only against a fileâs full name. Now, pattern matching is also an option.
+1. Filename matching for test compilation symbols happens against _only test file names_. More importantly, the configured symbols are applied in compilation of each C file that comprises a test executable. Each test executable is treated as a mini-project.
+
+Symbols specified for release builds are applied to all files in the release build.
+
+## Format change for `:flags` in the project file
+
+To better support per-test-executable configurations, the format and function of `:flags` has changed somewhat. See the [official documentation](CeedlingPacket.md) for specifics.
+
+In brief:
+
+1. The format of the `:flags` configuration section is largely the same as in previous versions of Ceedling. However, the behavior of the matching rules is slightly different with more matching options.
+1. Within the `:flags` âł `:test` context, all matching of file names is now limited to *_test files_*. For any test file name that matches, the specified flags are added to the named build step for _all files that comprise that test executable_. Previously, matching was against individual files (source, test, whatever), and flags were applied to only operations on that single file. Now, all files part of a test executable build get the same treatment as a mini-project.
+
+Flags specified for release builds are applied to all files in the release build.
+
+## New `:project` âł `:use_test_preprocessor` configuration settings
+
+Ceedlingâs preprocessing features have been greatly improved. Preprocessing is now no longer all-or-nothing with a simple boolean value.
+
+In place of `true` or `false`, `:use_test_preprocessing` now accepts:
+
+* `:none` disables preprocessing (equivalent to previous `false` setting).
+* `:all` enables preprpocessing for all mockable header files and test C files (equivalent to previous `true` setting).
+* `:mocks` enables only preprocessing of header files that are to be mocked.
+* `:tests` enables only preprocessing of your test files.
+
+## `TEST_FILE()` âĄïž `TEST_SOURCE_FILE()`
+
+The previously undocumented `TEST_FILE()` build directive macro (#796) available within test files has been renamed and is now officially documented.
+
+## Preprocessing is unable to handle Unityâs `TEST_CASE()` and `TEST_RANGE()` and has limits for `TEST_INCLUDE_PATH()`
+
+Ceedlingâs preprocessing abilities have been nearly entirely rewritten. The one case Ceedling cannot yet handle is preprocessing test files that contain Unityâs parameterized test case macros.
+
+`TEST_CASE()` and `TEST_RANGE()` are Unity macros that are positional in a file in relation to the test case functions they modify. While Ceedling's test preprocessing can preserve these macro calls, their position cannot be preserved.
+
+You may want to wrap `TEST_INCLUDE_PATH()` in conditional compilation preprocessor statements (e.g. `#ifdef`). This will not work as you expect. This macro âmarkerâ must be discovered at the beginning of a test build by Ceedling parsing a test file as plain text. Cyclical dependencies related to preprocessing prevent anything more sophisticated.
+
+Note: `:project` âł `:use_test_preprocessor` is no longer a binary setting (`true`/`false`). Mockable header file preprocessing can now be enabled with a `:mocks` setting while test files are left untouched by preprocessing. This can allow test preprocessing in the common cases of sophtisticate mockable headers while Unityâs `TEST_CASE()` and `TEST_RANGE()` are utilized in a test file untouched by preprocessing.
+
+## Quoted executables in tool definitions
+
+While unusual, some executables have names with spaces. This is more common on Windows than Unix derivatives, particularly with proprietary compiler toolchains.
+
+Originally, Ceedling would automatically add quotes around an executable containing a space when it built a full command line before passing it to a command shell.
+
+This automagical help can break tools in certain contexts. For example, script-based executables in many Linux shells do not work (e.g. `"python path/script.py" --arg`).
+
+Automatic quoting has been removed. If you need a quoted executable, simply explicitly include quotes in the appropriate string for your executable (this can occur in multiple locations throughout a Ceedling project). An example of a YAML tool defition follows:
+
+```yaml
+:tools:
+ :funky_compiler:
+ :executable: \"Code Cranker\"
+```
+
+## Build output directory structure changes
+
+### Test builds
+
+Each test is now treated as its own mini-project. Differentiating components of the same name that are a part of multiple test executables required further subdirectories in the build directory structure. Generated mocks, compiled object files, linked executables, and preprocessed output all end up one directory deeper than in previous versions of Ceedling. In each case, these files are found inside a subdirectory named for their containing test.
+
+### Release builds
+
+Release build object files were previously segregated by their source. The release build output directory had subdirectories `c/` and `asm/`. These subdirectories are no longer in use.
+
+## Configuration defaults and configuration set up order
+
+Ceedlingâs previous handling of defaults and configuration processing order certainly worked, but it was not as proper as it could be. To oversimplify, default values were applied in an ordering that caused complications for advanced plugins and advanced users. This has been rectified. Default settings are now processed after all user configurations and plugins.
+
+For some users and some custom plugins, the new ordering may cause unexpected results. The changes had no known impact on existing plugins and typical project configurations.
+
+## Changes to global constants & accessors
+
+Some global constant âcollectionsâ that were previously key elements of Ceedling have changed or gone away as the build pipeline is now able to process a configuration for each individual test executable in favor of for the entire suite.
+
+Similarly, various global constant project file accessors have changed, specifically the values within the configuration file they point to as various configuration sections have changed format (examples above).
+
+See the [official documentation](CeedlingPacket.md) on global constants & accessors for updated lists and information.
+
+## `raw_output_report` plugin
+
+This plugin (renamed -- see next section) no longer generates empty log files and no longer generates log files with _test_ and _pass_ in their filenames. Log files are now simply named `.raw.log`.
+
+## Consolidation of test report generation plugins âĄïž `report_tests_log_factory`
+
+The individual `json_tests_report`, `xml_tests_report`, and `junit_tests_report` plugins are superseded by a single plugin `report_tests_log_factory` able to generate each or all of the previous test reports as well as an HTML report and user-defined tests reports. The new plugin requires a small amount of extra configuration the previous individual plugins did not. See the [`report_tests_log_factory` documentation](../plugins/report_tests_log_factory).
+
+In addition, all references and naming connected to the previous `xml_tests_report` plugin have been updated to refer to _CppUnit_ rather than generic _XML_ as this is the actual format of the report that is processed.
+
+## Built-in Plugin Name Changes
+
+The following plugin names must be updated in the `:plugins` âł `:enabled` list of your Ceedling project file.
+
+This renaming was primarily enacted to more clearly organize and relate reporting-oriented plugins. Secondarily, some names were changed simply for greater clarity.
+
+Some test report generation plugins were not simply renamed but superseded by a new plugin (see preceding section).
+
+- `fake_function_framework` âĄïž `fff`
+- `compile_commands_json` âĄïž `compile_commands_json_db`
+- `json_tests_report`, `xml_tests_report` & `junit_tests_report` âĄïž `report_tests_log_factory`
+- `raw_output_report` âĄïž `report_tests_raw_output_log`
+- `stdout_gtestlike_tests_report` âĄïž `report_tests_gtestlike_stdout`
+- `stdout_ide_tests_report` âĄïž `report_tests_ide_stdout`
+- `stdout_pretty_tests_report` âĄïž `report_tests_pretty_stdout`
+- `stdout_teamcity_tests_report` âĄïž `report_tests_teamcity_stdout`
+- `warnings_report` âĄïž `report_build_warnings_log`
+- `test_suite_reporter` âĄïž `report_tests_log_factory`
+
+## `gcov` plugin coverage report generation name and behavior changes
+
+The `gcov` plugin and its [documentation](../plugins/gcov) has been significantly revised. See [release notes](ReleaseNotes.md) for all the details.
+
+The report generation task `utils:gcov` has been renamed and its behavior has been altered.
+
+Coverage reports are now generated automatically unless the manual report generation task is enabled with a configuration option (the manual report generation option disables the automatc option). See below. If automatic report generation is disabled, the task `report:gcov` becomes available to trigger report generation (a `gcov:` task must be executed before `report:gcov` just as was the case with `utils:gcov`).
+
+```yaml
+:gcov:
+ :report_task: TRUE
+```
+
+## Exit code handling (a.k.a. `:graceful_fail`)
+
+Be default Ceedling terminates with an exit code of `1` when a build succeeds but unit tests fail.
+
+A previously undocumented project configuration option `:graceful_fail` could force a Ceedling exit code of `0` upon test failures.
+
+This configuration option has moved (and is now [documented](CeedlingPacket.md)).
+
+Previously:
+```yaml
+:graceful_fail: TRUE
+```
+
+Now:
+```yaml
+:test_build:
+ :graceful_fail: TRUE
+```
+
+## Project file environment variable name change `CEEDLING_MAIN_PROJECT_FILE` âĄïž `CEEDLING_PROJECT_FILE`
+
+Options and support for loading a project configuration have expanded significantly, mostly notably with the addition of Mixins.
+
+The environment variable option for pointing Ceedling to a project file other than _project.yml_ in your working directory has been renamed `CEEDLING_MAIN_PROJECT_FILE` âĄïž `CEEDLING_PROJECT_FILE`.
+
+In addition, a previously undocumented feature for merging a second configuration via environment variable `CEEDLING_USER_PROJECT_FILE` has been removed. This feature has been superseded by the new Mixins functionality.
+
+Thorough documentation on Mixins and the new options for loading a project configuration can be found in _[CeedlingPacket](CeedlingPacket.md))_.
+
+## Tool definition inline Ruby evaluation replacement removed (inline Ruby string expansion remains)
+
+Reaching back to the earliest days of Ceedling, tool definitions supported two slightly different string replacement options that executed at different points in a buildâs lifetime. Yeah. It was maybe not great.
+
+Support for `{...}` Ruby evaluation in tool definitions has been removed.
+
+Support for `#{...}` Ruby string expansion in tool definitions remains and is now evaluated each time a tool is executed during a build.
+
+## Command Hooks plugin configuration change
+
+In previous versions of Ceedling, the Command Hooks plugin associated tools and hooks by a naming convention within the top-level `:tools` section of your project configuration. This required some semi-ugly tool names and could lead to a rather unwieldy `:tools` list. Further, this convention also limited a hook to an association with only a single tool.
+
+Hooks are now enabled within a top-level `:command_hooks` section in your project configuration. Each hook key in this configuration block can now support one or more tools organized beneath it. As such, each hook can execute one or more tools.
+
+## Subprojects plugin replaced
+
+The `subprojects` plugin has been completely replaced by the more-powerful `dependencies` plugin. To retain your previous functionality, you need to do a little reorganizing in your `project.yml` file. Obviously the `:subprojects` section is now called `:dependencies`. The collection of `:paths` is now `:deps`. We'll have a little more organizing to do once we're inside that section as well. Your `:source` is now organized in `:paths` âł `:source` and, since you're not fetching it form another project, the `:fetch` âł `:method` should be set to `:none`. The `:build_root` now becomes `:paths` âł `:build`. You'll also need to specify the name of the library produced under `:artifacts` âł `:static_libraries`.
+
+For example:
+
+```
+:subprojects:
+ :paths:
+ - :name: libprojectA
+ :source:
+ - ./subprojectA/
+ :include:
+ - ./subprojectA/inc
+ :build_root: ./subprojectA/build/dir
+ :defines:
+ - DEFINE_JUST_FOR_THIS_FILE
+ - AND_ANOTHER
+```
+
+The above subproject definition will now look like the following:
+
+```
+:dependencies:
+ :deps:
+ - :name: Project A
+ :paths:
+ :fetch: ./subprojectA/
+ :source: ./subprojectA/
+ :build: ./subprojectA/build/dir
+ :artifact: ./subprojectA/build/dir
+ :fetch:
+ :method: :none
+ :environment: []
+ :build:
+ - :build_lib
+ :artifacts:
+ :static_libraries:
+ - libprojectA.a
+ :dynamic_libraries: []
+ :includes:
+ - ../subprojectA/subprojectA.h
+ :defines:
+ - DEFINE_JUST_FOR_THIS_FILE
+ - AND_ANOTHER
+```
+
+## Undocumented `:project` âł `:debug` has been removed
+
+This project setting existed from Ceedlingâs earliest days and was a crude stand-in for command line debug verbosity handling.
+
+It has been removed as it was rarely if ever utilized and needlessly complicated internal mechanisms for verbosity handling and project validation.
+
diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md
new file mode 100644
index 000000000..84e34806a
--- /dev/null
+++ b/docs/CODE_OF_CONDUCT.md
@@ -0,0 +1,138 @@
+
+# ThrowTheSwitch.org Code of Conduct
+
+Thank you for participating in a ThrowTheSwitch.org community project! We want
+this to continue to be a warm and inviting place for everyone to share ideas
+and get help. To accomplish this goal, we've developed this Code of Conduct.
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, caste, color, religion, or sexual
+identity and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the overall
+ community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or advances of
+ any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email address,
+ without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official email address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+hello@thingamabyte.com.
+
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series of
+actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or permanent
+ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within the
+community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.1, available at
+[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
+
+Community Impact Guidelines were inspired by
+[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
+
+For answers to common questions about this code of conduct, see the FAQ at
+[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
+[https://www.contributor-covenant.org/translations][translations].
+
+[homepage]: https://www.contributor-covenant.org
+[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
+[Mozilla CoC]: https://github.com/mozilla/diversity
+[FAQ]: https://www.contributor-covenant.org/faq
+[translations]: https://www.contributor-covenant.org/translations
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
new file mode 100644
index 000000000..b233a039b
--- /dev/null
+++ b/docs/CONTRIBUTING.md
@@ -0,0 +1,250 @@
+# Contributing to a ThrowTheSwitch.org Project
+
+đđ _First off, thanks for taking the time to contribute!_ đđ
+
+The following is a set of guidelines for contributing to any of ThrowTheSwitch.org's projects or the website itself, hosted at throwtheswitch.org or ThrowTheSwitch's organization on GitHub. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
+
+### Table Of Contents
+
+- [Code of Conduct](#book-code-of-conduct)
+- [Asking Questions](#bulb-asking-questions)
+- [Opening an Issue](#inbox_tray-opening-an-issue)
+- [Feature Requests](#love_letter-feature-requests)
+- [Triaging Issues](#mag-triaging-issues)
+- [Submitting Pull Requests](#repeat-submitting-pull-requests)
+- [Writing Commit Messages](#memo-writing-commit-messages)
+- [Code Review](#white_check_mark-code-review)
+- [Coding Style](#nail_care-coding-style)
+- [Certificate of Origin](#medal_sports-certificate-of-origin)
+- [Credits](#pray-credits)
+
+## :book: Code of Conduct
+
+Please review our [Code of Conduct](CODE_OF_CONDUCT.md). It is in effect at all times. We expect it to be honored by everyone who contributes to this project. Be a Good Human!
+
+## :bulb: Asking Questions
+
+> **Note:** Please don't file an issue to ask a question. We have an official forum where the community chimes in with helpful advice if you have questions.
+
+* [ThrowTheSwitch Forums](https://throwtheswitch.org/forums)
+
+### What should I know before I get started?
+
+ThrowTheSwitch hosts a number of open source projects — Ceedling is the entrypoint for many users. Ceedling is actually built upon the foundation of Unity Test (a flexible C testing framework) and CMock (a mocking tool for C) and it coordinates many other open source and proprietary tools. Please do your best to focus your ideas and questions at the correct tool. We'll do our best to help you find your way, but there will be times where we'll have to direct your attention to another subtool.
+
+Here are some of the main projects hosted by ThrowTheSwitch.org:
+
+ - [Ceedling](https://www.github.com/throwtheswitch/ceedling) -- Build coordinator for testing C applications, especially embedded C (and optionally your release build too!)
+ - [CMock](https://www.github.com/throwtheswitch/cmock) -- Mocking tool for automatically creating stubs, mocks, and skeletons in C
+ - [Unity](https://www.github.com/throwtheswitch/unity) -- Unit Testing framework for C, specially embedded C.
+ - [MadScienceLabDocker](https://www.github.com/throwtheswitch/madsciencelabdocker) -- Docker image giving you a shortcut to getting running with Ceedling
+ - [CException](https://www.github.com/throwtheswitch/cexception) -- An exception framework for using simple exceptions in C.
+
+There are many more, but this list should be a good starting point.
+
+## :inbox_tray: Opening an Issue
+
+Before [creating an issue](https://help.github.com/en/github/managing-your-work-on-github/creating-an-issue), check if you are using the latest version of the project. If you are not up-to-date, see if updating fixes your issue first.
+
+### :beetle: Bug Reports and Other Issues
+
+A great way to contribute to the project is to send a detailed issue when you encounter a problem. We always appreciate a well-written, thorough bug report. :v:
+
+In short, since you are most likely a developer, **provide a ticket that you would like to receive**.
+
+- **Review the documentation** before opening a new issue.
+
+- **Do not open a duplicate issue!** Search through existing issues to see if your issue has previously been reported. If your issue exists, comment with any additional information you have. You may simply note "I have this problem too", which helps prioritize the most common problems and requests.
+
+- **Prefer using [reactions](https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/)**, not comments, if you simply want to "+1" an existing issue.
+
+- **Fully complete the provided issue template.** The bug report template requests all the information we need to quickly and efficiently address your issue. Be clear, concise, and descriptive. Provide as much information as you can, including steps to reproduce, stack traces, compiler errors, library versions, OS versions, and screenshots (if applicable).
+
+- **Use [GitHub-flavored Markdown](https://help.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax).** Especially put code blocks and console outputs in backticks (```). This improves readability.
+
+## :seedling: Feature Requests
+
+Feature requests are welcome! We don't have all the answers and we truly love the collaborative experience of building software together! That being said, we cannot guarantee your request will be accepted. We want to avoid [feature creep](https://en.wikipedia.org/wiki/Feature_creep). Your idea may be great, but also out-of-scope for the project. If accepted, we'll do our best to tackle it in a timely manner, but cannot make any commitments regarding the timeline for implementation and release. However, you are welcome to submit a pull request to help!
+
+- **Please don't open a duplicate feature request.** Search for existing feature requests first. If you find your feature (or one very similar) previously requested, comment on that issue.
+
+- **Fully complete the provided issue template.** The feature request template asks for all necessary information for us to begin a productive conversation.
+
+- Be precise about the proposed outcome of the feature and how it relates to existing features. Include implementation details if possible.
+
+## :mag: Triaging Issues
+
+You can triage issues which may include reproducing bug reports or asking for additional information, such as version numbers or reproduction instructions. Any help you can provide to quickly resolve an issue is very much appreciated!
+
+## :repeat: Submitting Pull Requests
+
+We **love** pull requests! Before [forking the repo](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) and [creating a pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/proposing-changes-to-your-work-with-pull-requests) for non-trivial changes, it is usually best to first open an issue to discuss the changes, or discuss your intended approach for solving the problem in the comments for an existing issue.
+
+For most contributions, after your first pull request is accepted and merged, you will be [invited to the project](https://help.github.com/en/github/setting-up-and-managing-your-github-user-account/inviting-collaborators-to-a-personal-repository) and given **push access**. :tada:
+
+*Note: All contributions will be licensed under the project's license.*
+
+- **Smaller is better.** Submit **one** pull request per bug fix or feature. A pull request should contain isolated changes pertaining to a single bug fix or feature implementation. **Do not** refactor or reformat code that is unrelated to your change. It is better to **submit many small pull requests** rather than a single large one. Enormous pull requests will take enormous amounts of time to review, or may be rejected altogether.
+
+- **Coordinate bigger changes.** For large and non-trivial changes, open an issue to discuss a strategy with the maintainers. Otherwise, you risk doing a lot of work for nothing!
+
+- **Prioritize understanding over cleverness.** Write code clearly and concisely. Remember that source code usually gets written once and read often. Ensure the code is clear to the reader. The purpose and logic should be obvious to a reasonably skilled developer, otherwise you should add a comment that explains it.
+
+- **Follow existing coding style and conventions.** Keep your code consistent with the style, formatting, and conventions in the rest of the code base. When possible, these will be enforced with a linter. Consistency makes it easier to review and modify in the future.
+
+- **Include test coverage.** Add unit tests when possible. Follow existing patterns for implementing tests.
+
+- **Update the example project** if one exists to exercise any new functionality you have added.
+
+- **Add documentation.** Document your changes with code doc comments or in existing guides.
+
+- **Update the CHANGELOG** for all enhancements and bug fixes. Include the corresponding issue number if one exists, and your GitHub username. (example: "- Fixed crash in profile view. #123 @jessesquires")
+
+- **Use the repo's default branch.** Branch from and [submit your pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork) to the repo's default branch. Usually this is `main`, but it could be `dev`, `develop`, or `master`.
+
+- **[Resolve any merge conflicts](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/resolving-a-merge-conflict-on-github)** that occur.
+
+- **Promptly address any CI failures**. If your pull request fails to build or pass tests, please push another commit to fix it.
+
+- When writing comments, use properly constructed sentences, including punctuation.
+
+- Use spaces, not tabs.
+
+## :memo: Writing Commit Messages
+
+Please [write a great commit message](https://chris.beams.io/posts/git-commit/).
+
+1. Separate subject from body with a blank line
+1. Limit the subject line to 50 characters
+1. Capitalize the subject line
+1. Do not end the subject line with a period
+1. Wrap the body at _about_ 72 characters
+1. Use the body to explain **why**, *not what and how* (the code shows that!)
+1. If applicable, prefix the title with the relevant component name or emoji (see below. examples: "[Docs] Fix typo", "[Profile] Fix missing avatar")
+
+```
+:palm_tree: Summary of Amazing Feature Here
+
+Add a more detailed explanation here, if necessary. Possibly give
+some background about the issue being fixed, etc. The body of the
+commit message can be several paragraphs. Further paragraphs come
+after blank lines and please do proper word-wrap.
+
+Wrap it to about 72 characters or so. In some contexts,
+the first line is treated as the subject of the commit and the
+rest of the text as the body. The blank line separating the summary
+from the body is critical (unless you omit the body entirely);
+various tools like `log`, `shortlog` and `rebase` can get confused
+if you run the two together.
+
+Explain the problem that this commit is solving. Focus on why you
+are making this change as opposed to how or what. The code explains
+how or what. Reviewers and your future self can read the patch,
+but might not understand why a particular solution was implemented.
+Are there side effects or other unintuitive consequences of this
+change? Here's the place to explain them.
+
+ - Bullet points are awesome, too
+
+ - A hyphen should be used for the bullet, preceded
+ by a single space, with blank lines in between
+
+Note the fixed or relevant GitHub issues at the end:
+
+Resolves: #123
+See also: #456, #789
+```
+
+## :white_check_mark: Pull Request Checklist
+
+Not all Pull Requests require these things, but here's a great list of things to check to see if it makes sense for your situation:
+
+ - [ ] Are the changes complete?
+ - [ ] Are there tests for the new functionality?
+ - [ ] Are the changes passing the style checks?
+ - [ ] Is there documentation for the new functionality?
+ - [ ] Has the change been added to `Changelog.md`?
+ - [ ] Has the change been added to `ReleaseNotes.md`?
+ - [ ] Have new config options been added as defaults to the `project.yml` files?
+
+## :heart: Who Loves Emoji?
+
+Commit comments, Issues, Feature Requests... they can all use a little sprucing up, right? Consider using the following emoji for a mix of function and :sparkles: dazzle! We encourage loosely following the conventions of [gitmoji](https://gitmoji.dev) for contributing to Ceedling.
+
+ - actions
+ - :seedling: `:seedling:` (or other plants) when growing new features. Choose your fav! :cactus: :herb: :evergreen_tree: :palm_tree: :deciduous_tree: :blossom:
+ - :art: `:art:` when improving the format/structure of the code
+ - :racehorse: `:racehorse:` when improving performance
+ - :non-potable_water: `:non-potable_water:` when plugging memory leaks
+ - :memo: `:memo:` when writing docs
+ - :bug: `:bug:` (or other insects) when fixing a bug. Maybe :beetle: :ant: or :honeybee: ?
+ - :fire: `:fire:` when removing code or files
+ - :green_heart: `:green_heart:` when fixing the CI build
+ - :white_check_mark: `:white_check_mark:` when adding tests
+ - :lock: `:lock:` when dealing with security
+ - :arrow_up: `:arrow_up:` when upgrading dependencies
+ - :arrow_down: `:arrow_down:` when downgrading dependencies
+ - :shirt: `:shirt:` when removing linter warnings
+
+ - platforms
+ - :penguin: `:penguin:` when fixing something on Linux
+ - :apple: `:apple:` when fixing something on macOS
+ - :checkered_flag: `:checkered_flag:` when fixing something on Windows
+
+## :white_check_mark: Code Review
+
+- **Review the code, not the author.** Look for and suggest improvements without disparaging or insulting the author. Provide actionable feedback and explain your reasoning.
+
+- **You are not your code.** When your code is critiqued, questioned, or constructively criticized, remember that you are not your code. Do not take code review personally.
+
+- **Always do your best.** No one writes bugs on purpose. Do your best, and learn from your mistakes.
+
+- Kindly note any violations to the guidelines specified in this document.
+
+## :violin: Coding Style
+
+Consistency is the most important. Following the existing style, formatting, and naming conventions of the file you are modifying and of the overall project. Failure to do so will result in a prolonged review process that has to focus on updating the superficial aspects of your code, rather than improving its functionality and performance.
+
+For example, if all private properties are prefixed with an underscore `_`, then new ones you add should be prefixed in the same way. Or, if methods are named using camelcase, like `thisIsMyNewMethod`, then do not diverge from that by writing `this_is_my_new_method`. You get the idea. If in doubt, please ask or search the codebase for something similar.
+
+When possible, style and format will be enforced with a linter.
+
+### C Styleguide
+
+C code is linted with [AStyle](https://astyle.sourceforge.net/).
+
+### Ruby Styleguide
+
+Ruby code is linted with [Rubocop](https://github.com/rubocop/rubocop)
+
+## :medal_sports: Certificate of Origin
+
+*Developer's Certificate of Origin 1.1*
+
+By making a contribution to this project, I certify that:
+
+> 1. The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or
+> 1. The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or
+> 1. The contribution was provided directly to me by some other person who certified (1), (2) or (3) and I have not modified it.
+> 1. I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved.
+
+## [No Brown M&M's](https://en.wikipedia.org/wiki/Van_Halen#Contract_riders)
+
+If you are reading this, bravo dear user and (hopefully) contributor for making it this far! You are awesome. :100:
+
+To confirm that you have read this guide and are following it as best as possible, **include this emoji at the top** of your issue or pull request: :pineapple: `:pineapple:`
+
+## :pray: Credits
+
+Written by [@jessesquires](https://github.com/jessesquires). Lovingly adapted to ThrowTheSwitch.org by [@mvandervoord](https://github.com/mvandervoord).
+
+**Please feel free to adopt this guide in your own projects. Fork it wholesale or remix it for your needs.**
+
+*Many of the ideas and prose for the statements in this document were based on or inspired by work from the following communities:*
+
+- [Alamofire](https://github.com/Alamofire/Alamofire/blob/master/CONTRIBUTING.md)
+- [CocoaPods](https://github.com/CocoaPods/CocoaPods/blob/master/CONTRIBUTING.md)
+- [Docker](https://github.com/moby/moby/blob/master/CONTRIBUTING.md)
+- [Linux](https://elinux.org/Developer_Certificate_Of_Origin)
+
+*We commend them for their efforts to facilitate collaboration in their projects.*
diff --git a/docs/Ceedling Powerful Plugins.pdf b/docs/Ceedling Powerful Plugins.pdf
deleted file mode 100755
index 4596b6ab1..000000000
Binary files a/docs/Ceedling Powerful Plugins.pdf and /dev/null differ
diff --git a/docs/CeedlingPacket.md b/docs/CeedlingPacket.md
index 97d59b09b..b7c9d0ffb 100644
--- a/docs/CeedlingPacket.md
+++ b/docs/CeedlingPacket.md
@@ -1,26 +1,225 @@
-[All code is copyright © 2010-2021 Ceedling Project
-by Mike Karlesky, Mark VanderVoord, and Greg Williams.
-
-This Documentation Is Released Under a
-Creative Commons 3.0 Attribution Share-Alike License]
-
-What the What?
-
-Assembling build environments for C projects - especially with
-automated unit tests - is a pain. Whether it's Make or Rake or Premake
-or what-have-you, set up with an all-purpose build environment
-tool is tedious and requires considerable glue code to pull together
-the necessary tools and libraries. Ceedling allows you to generate
-an entire test and build environment for a C project from a single
-YAML configuration file. Ceedling is written in Ruby and works
-with the Rake build tool plus other goodness like Unity and CMock â
-the unit testing and mocking frameworks for C. Ceedling and
-its complementary tools can support the tiniest of embedded
-processors, the beefiest 64 bit power houses available, and
+
+# Ceedling
+
+All code is copyright © 2010-2023 Ceedling Project
+by Michael Karlesky, Mark VanderVoord, and Greg Williams.
+
+This Documentation is released under a
+[Creative Commons 4.0 Attribution Share-Alike Deed][CC4SA].
+
+[CC4SA]: https://creativecommons.org/licenses/by-sa/4.0/deed.en
+
+# Quick Start
+
+Ceedling is a fancypants build system that greatly simplifies building
+C projects. While it can certainly build release targets, it absolutely
+shines at running unit test suites.
+
+## Steps
+
+Below is a quick overview of how to get started from Ceedling installation
+through running build tasks. Jump down just a teeny bit to see what the Ceedling
+command line looks like and navigate to all the documentation for the steps
+listed immediately below.
+
+1. Install Ceedling
+1. Create a project
+ * Use Ceedling to generate an example project, or
+ * Add a Ceedling project file to the root of an existing project, or
+ * Create a project from scratch:
+ 1. Create a project directory
+ 1. Add source code and optionally test code however you'd like it organized
+ 1. Create a Ceedling project file in the root of your project directory
+1. Run Ceedling tasks from the working directory of your project
+
+Ceedling requires a command line C toolchain be available in your path. It's
+flexible enough to work with most anything on any platform. By default, Ceedling
+is ready to work with [GCC] out of the box (we recommend the [MinGW] project
+on Windows).
+
+A common build strategy with tooling other than GCC is to use your target
+toolchain for release builds (with or without Ceedling) but rely on Ceedling +
+GCC for test builds (more on all this [here][packet-section-2]).
+
+[GCC]: https://gcc.gnu.org
+
+## Ceedling Command Line & Build Tasks
+
+Once you have Ceedling installed, you always have access to `ceedling help`.
+
+And, once you have Ceedling installed, you have options for project creation
+using Ceedlingâs application commands:
+
+* `ceedling new `
+* `ceedling examples` to list available example projects and
+ `ceedling example ` to create a readymade sample
+ project whose project file you can copy and modify.
+
+Once you have a Ceedling project file and a project directory structure for your
+code, Ceedling build tasks go like this:
+
+* `ceedling test:MyCodeModule`, or
+* `ceedling test:all`, or
+* `ceedling release`, or, if you fancy and have the GCov plugin enabled,
+* `ceedling clobber test:all gcov:all release --log --verbosity=obnoxious`
+
+## Quick Start Documentation
+
+* [Installation][quick-start-1]
+* [Sample test code file + Example Ceedling projects][quick-start-2]
+* [Simple Ceedling project file][quick-start-3]
+* [Ceedling at the command line][quick-start-4]
+* [All your Ceedling project configuration file options][quick-start-5]
+
+[quick-start-1]: #ceedling-installation--set-up
+[quick-start-2]: #commented-sample-test-file
+[quick-start-3]: #simple-sample-project-file
+[quick-start-4]: #now-what-how-do-i-make-it-go-the-command-line
+[quick-start-5]: #the-almighty-project-configuration-file-in-glorious-yaml
+
+
+
+---
+
+# Contents
+
+(Be sure to review **[breaking changes](BreakingChanges.md)** if you are working with
+a new release of Ceedling.)
+
+Building test suites in C requires much more scaffolding than for
+a release build. As such, much of Ceedlingâs documentation is concerned
+with test builds. But, release build documentation is here too. We promise.
+It's just all mixed together.
+
+1. **[Ceedling, a C Build System for All Your Mad Scientisting Needs][packet-section-1]**
+
+ This section provides lots of background, definitions, and links for Ceedling
+ and its bundled frameworks. It also presents a very simple, example Ceedling
+ project file.
+
+1. **[Ceedling, Unity, and CMockâs Testing Abilities][packet-section-2]**
+
+ This section speaks to the philosophy of and practical options for unit testing
+ code in a variety of scenarios.
+
+1. **[How Does a Test Case Even Work?][packet-section-3]**
+
+ A brief overview of what a test case is and several simple examples illustrating
+ how test cases work.
+
+1. **[Commented Sample Test File][packet-section-4]**
+
+ This sample test file illustrates how to create test cases as well as many of the
+ conventions that Ceedling relies on to do its work. There's also a brief
+ discussion of what gets compiled and linked to create an executable test.
+
+1. **[Anatomy of a Test Suite][packet-section-5]**
+
+ This documentation explains how a unit test grows up to become a test suite.
+
+1. **[Ceedling Installation & Set Up][packet-section-6]**
+
+ This one is pretty self explanatory.
+
+1. **[Now What? How Do I Make It _GO_? The Command Line.][packet-section-7]**
+
+ Ceedlingâs command line.
+
+1. **[Important Conventions & Behaviors][packet-section-8]**
+
+ Much of what Ceedling accomplishes â particularly in testing â is by convention.
+ Code and files structured and named in certain ways trigger sophisticated
+ Ceedling build features. This section explains all such conventions.
+
+ This section also covers essential high-level behaviors and features including
+ how to work with search paths, directory structures & file extensions, release
+ build binary artifacts, build time logging, and Ceedlingâs abilities to
+ preprocess certain code files before they are incorporated into a test build.
+
+1. **[Using Unity, CMock & CException][packet-section-9]**
+
+ Not only does Ceedling direct the overall build of your code, it also links
+ together several key tools and frameworks. Those can require configuration of
+ their own. Ceedling facilitates this.
+
+1. **[How to Load a Project Configuration. You Have Options, My Friend.][packet-section-10]**
+
+ You can use a command line flag, an environment variable, or rely on a default
+ file in your working directory to load your base configuration.
+
+ Once your base project configuration is loaded, you have **_Mixins_** for merging
+ additional configuration for different build scenarios as needed via command line,
+ environment variable, and/or your project configuration file.
+
+1. **[The Almighty Ceedling Project Configuration File (in Glorious YAML)][packet-section-11]**
+
+ This is the exhaustive documentation for all of Ceedlingâs project file
+ configuration options â from project paths to command line tools to plugins and
+ much, much more.
+
+1. **[Which Ceedling][packet-section-12]**
+
+ Sometimes you may need to point to a different Ceedling to run.
+
+1. **[Build Directive Macros][packet-section-13]**
+
+ These code macros can help you accomplish your build goals When Ceedlingâs
+ conventions arenât enough.
+
+1. **[Ceedling Plugins][packet-section-14]**
+
+ Ceedling is extensible. It includes a number of built-in plugins for code coverage,
+ test report generation, continuous integration reporting, test file scaffolding
+ generation, sophisticated release builds, and more.
+
+1. **[Global Collections][packet-section-15]**
+
+ Ceedling is built in Ruby. Collections are globally available Ruby lists of paths,
+ files, and more that can be useful for advanced customization of a Ceedling project
+ file or in creating plugins.
+
+[packet-section-1]: #ceedling-a-c-build-system-for-all-your-mad-scientisting-needs
+[packet-section-2]: #ceedling-unity-and-c-mocks-testing-abilities
+[packet-section-3]: #how-does-a-test-case-even-work
+[packet-section-4]: #commented-sample-test-file
+[packet-section-5]: #anatomy-of-a-test-suite
+[packet-section-6]: #ceedling-installation--set-up
+[packet-section-7]: #now-what-how-do-i-make-it-go-the-command-line
+[packet-section-8]: #important-conventions--behaviors
+[packet-section-9]: #using-unity-cmock--cexception
+[packet-section-10]: #how-to-load-a-project-configuration-you-have-options-my-friend
+[packet-section-11]: #the-almighty-ceedling-project-configuration-file-in-glorious-yaml
+[packet-section-12]: #which-ceedling
+[packet-section-13]: #build-directive-macros
+[packet-section-14]: #ceedling-plugins
+[packet-section-15]: #global-collections
+
+---
+
+
+
+# Ceedling, a C Build System for All Your Mad Scientisting Needs
+
+Ceedling allows you to generate an entire test and release build
+environment for a C project from a single, short YAML configuration
+file.
+
+Ceedling and its bundled tools, Unity, CMock, and CException, donât
+want to brag, but theyâre also quite adept at supporting the tiniest of
+embedded processors, the beefiest 64-bit powerhouses available, and
everything in between.
-For a build project including unit tests and using the default
-toolchain gcc, the configuration file could be as simple as this:
+Assembling build environments for C projects â especially with
+automated unit tests â is a pain. No matter the all-purpose build
+environment tool you use, configuration is tedious and requires
+considerable glue code to pull together the necessary tools and
+libraries to run unit tests. The Ceedling bundle handles all this
+for you.
+
+## Simple Sample Project File
+
+For a project including Unity/CMock unit tests and using the default
+toolchain `gcc`, the configuration file could be as simple as this:
```yaml
:project:
@@ -32,39 +231,59 @@ toolchain gcc, the configuration file could be as simple as this:
- tests/**
:source:
- source/**
+ :include:
+ - inc/**
```
-From the command line, to build the release version of your project,
-you would simply run `ceedling release`. To run all your unit tests,
-you would run `ceedling test:all`. That's it!
+From the command line, to run all your unit tests, you would run
+`ceedling test:all`. To build the release version of your project,
+you would simply run `ceedling release`. That's it!
Of course, many more advanced options allow you to configure
your project with a variety of features to meet a variety of needs.
Ceedling can work with practically any command line toolchain
and directory structure â all by way of the configuration file.
-Further, because Ceedling piggy backs on Rake, you can add your
-own Rake tasks to accomplish project tasks outside of testing
-and release builds. A facility for plugins also allows you to
-extend Ceedling's capabilities for needs such as custom code
-metrics reporting and coverage testing.
-What's with this Name?
+See this [commented project file][example-config-file]
+for a much more complete and sophisticated example of a project
+configuration.
+
+See the later [configuration section][project-configuration] for
+way more details on your project configuration options.
+
+A facility for [plugins](#ceedling-plugins) also allows you to
+extend Ceedlingâs capabilities for needs such as custom code metrics
+reporting, build artifact packaging, and much more. A variety of
+built-in plugins come with Ceedling.
+
+[example-config-file]: ../assets/project_as_gem.yml
+[project-configuration]: #the-almighty-ceedling-project-configuration-file-in-glorious-yaml
+
+## Whatâs with This Name?
+
+Glad you asked. Ceedling is tailored for unit tested C projects and is built
+upon Rake, a Make replacement implemented in the Ruby scripting language.
+
+So, we've got C, our Rake, and the fertile soil of a build environment in which
+to grow and tend your project and its unit tests. Ta da â _Ceedling_.
-Glad you asked. Ceedling is tailored for unit tested C projects
-and is built upon / around Rake (Rake is a Make replacement implemented
-in the Ruby scripting language). So, we've got C, our Rake, and
-the fertile soil of a build environment in which to grow and tend
-your project and its unit tests. Ta da - _Ceedling_.
+Incidentally, though Rake was the backbone of the earliest versions of
+Ceedling, it is now being phased out incrementally in successive releases
+of this tool. The name Ceedling is not going away, however!
-What Do You Mean "tailored for unit tested C projects"?
+## What Do You Mean âTailored for unit tested C projectsâ?
Well, we like to write unit tests for our C code to make it lean and
-mean (that whole [Test-Driven Development][tdd]
-thing). Along the way, this style of writing C code spawned two
-tools to make the job easier: a unit test framework for C called
-_Unity_ and a mocking library called _CMock_. And, though it's
-not directly related to testing, a C framework for exception
-handling called _CException_ also came along.
+mean â that whole [Test-Driven Development][tdd] thing.
+
+Along the way, this style of writing C code spawned two
+tools to make the job easier:
+
+1. A unit test framework for C called _Unity_
+1. A mocking library called _CMock_
+
+And, though it's not directly related to testing, a C framework for
+exception handling called _CException_ also came along.
[tdd]: http://en.wikipedia.org/wiki/Test-driven_development
@@ -76,31 +295,41 @@ or created anew for each new project. Ceedling replaces all that
tedium and rework with a configuration file that ties everything
together.
-Though Ceedling is tailored for unit testing, it can also go right ahead
-and build your final binary release artifact for you as well. Or,
-Ceedling and your tests can live alongside your existing release build
-setup. That said, Ceedling is more powerful as a unit test build
-environment than it is a general purpose release build environment;
-complicated projects including separate bootloaders or multiple library
-builds, etc. are not its strong suit.
+Though Ceedling is tailored for unit testing, it can also go right
+ahead and build your final binary release artifact for you as well.
+That said, Ceedling is more powerful as a unit test build environment
+than it is a general purpose release build environment. Complicated
+projects including separate bootloaders or multiple library builds,
+etc. are not necessarily its strong suit (but the
+[`subprojects`](../plugins/subprojects/README.md) plugin can
+accomplish quite a bit here).
+
+It's quite common and entirely workable to host Ceedling and your
+test suite alongside your existing release build setup. That is, you
+can use make, Visual Studio, SCons, Meson, etc. for your release build
+and Ceedling for your test build. Your two build systems will simply
+âpointâ to the same project code.
-Hold on. Back up. Ruby? Rake? YAML? Unity? CMock? CException?
+## Hold on. Back up. Ruby? Rake? YAML? Unity? CMock? CException?
-Seem overwhelming? It's not bad at all, and for the benefits tests
+Seems overwhelming? It's not bad at all. And, for the benefits testing
bring us, it's all worth it.
-[Ruby][] is a handy scripting
-language like Perl or Python. It's a modern, full featured language
-that happens to be quite handy for accomplishing tasks like code
-generation or automating one's workflow while developing in
-a compiled language such as C.
+### Ruby
+
+[Ruby] is a handy scripting language like Perl or Python. It's a modern,
+full featured language that happens to be quite handy for accomplishing
+tasks like code generation or automating one's workflow while developing
+in a compiled language such as C.
[Ruby]: http://www.ruby-lang.org/en/
-[Rake][] is a utility written in Ruby
-for accomplishing dependency tracking and task automation
-common to building software. It's a modern, more flexible replacement
-for [Make][]).
+### Rake
+
+[Rake] is a utility written in Ruby for accomplishing dependency
+tracking and task automation common to building software. It's a modern,
+more flexible replacement for [Make]).
+
Rakefiles are Ruby files, but they contain build targets similar
in nature to that of Makefiles (but you can also run Ruby code in
your Rakefile).
@@ -108,16 +337,29 @@ your Rakefile).
[Rake]: http://rubyrake.org/
[Make]: http://en.wikipedia.org/wiki/Make_(software)
-[YAML][] is a "human friendly data serialization standard for all
-programming languages." It's kinda like a markup language, but don't
-call it that. With a YAML library, you can [serialize][] data structures
+### YAML
+
+[YAML] is a "human friendly data serialization standard for all
+programming languages." It's kinda like a markup language but donât
+call it that. With a YAML library, you can [serialize] data structures
to and from the file system in a textual, human readable form. Ceedling
uses a serialized data structure as its configuration input.
+YAML has some advanced features that can greatly
+[reduce duplication][yaml-anchors-aliases] in a configuration file
+needed in complex projects. YAML anchors and aliases are beyond the scope
+of this document but may be of use to advanced Ceedling users. Note that
+Ceedling does anticipate the use of YAML aliases. It proactively flattens
+YAML lists to remove any list nesting that results from the convenience of
+aliasing one list inside another.
+
[YAML]: http://en.wikipedia.org/wiki/Yaml
[serialize]: http://en.wikipedia.org/wiki/Serialization
+[yaml-anchors-aliases]: https://blog.daemonl.com/2016/02/yaml.html
+
+### Unity
-[Unity] is a [unit test framework][test] for C. It provides facilities
+[Unity] is a [unit test framework][unit-testing] for C. It provides facilities
for test assertions, executing tests, and collecting / reporting test
results. Unity derives its name from its implementation in a single C
source file (plus two C header files) and from the nature of its
@@ -125,16 +367,26 @@ implementation - Unity will build in any C toolchain and is configurable
for even the very minimalist of processors.
[Unity]: http://github.com/ThrowTheSwitch/Unity
-[test]: http://en.wikipedia.org/wiki/Unit_testing
+[unit-testing]: http://en.wikipedia.org/wiki/Unit_testing
-[CMock] is a tool written in Ruby able to generate entire
-[mock functions][mock] in C code from a given C header file. Mock
-functions are invaluable in [interaction-based unit testing][ut].
+### CMock
+
+[CMock]â is a tool written in Ruby able to generate [function mocks & stubs][test-doubles]
+in C code from a given C header file. Mock functions are invaluable in
+[interaction-based unit testing][interaction-based-tests].
CMock's generated C code uses Unity.
+â Through a [plugin][FFF-plugin], Ceedling also supports
+[FFF], _Fake Function Framework_, for [fake functions][test-doubles] as an
+alternative to CMockâs mocks and stubs.
+
[CMock]: http://github.com/ThrowTheSwitch/CMock
-[mock]: http://en.wikipedia.org/wiki/Mock_object
-[ut]: http://martinfowler.com/articles/mocksArentStubs.html
+[test-doubles]: https://blog.pragmatists.com/test-doubles-fakes-mocks-and-stubs-1a7491dfa3da
+[FFF]: https://github.com/meekrosoft/fff
+[FFF-plugin]: ../plugins/fff
+[interaction-based-tests]: http://martinfowler.com/articles/mocksArentStubs.html
+
+### CException
[CException] is a C source and header file that provide a simple
[exception mechanism][exn] for C by way of wrapping up the
@@ -146,2181 +398,5193 @@ up your return call trace.
[exn]: http://en.wikipedia.org/wiki/Exception_handling
[setjmp]: http://en.wikipedia.org/wiki/Setjmp.h
-Notes
------
+## Notes on Ceedling Dependencies and Bundled Tools
-* YAML support is included with Ruby - requires no special installation
- or configuration.
+* By using the preferred installation option of the Ruby Ceedling gem (see
+ later installation section), all other Ceedling dependencies will be
+ installed for you.
-* Unity, CMock, and CException are bundled with Ceedling, and
- Ceedling is designed to glue them all together for your project
- as seamlessly as possible.
+* Regardless of installation method, Unity, CMock, and CException are bundled
+ with Ceedling. Ceedling is designed to glue them all together for your
+ project as seamlessly as possible.
+* YAML support is included with Ruby. It requires no special installation
+ or configuration. If your project file contains properly formatted YAML
+ with the recognized names and options (see later sections), you are good
+ to go.
-Installation & Setup: What Exactly Do I Need to Get Started?
-------------------------------------------------------------
+
-As a [Ruby gem](http://docs.rubygems.org/read/chapter/1):
+# Ceedling, Unity, and CMockâs Testing Abilities
-1. [Download and install Ruby](http://www.ruby-lang.org/en/downloads/)
+The unit testing Ceedling, Unity, and CMock afford works in practically
+any context.
-2. Use Ruby's command line gem package manager to install Ceedling:
- `gem install ceedling`
- (Unity, CMock, and CException come along with Ceedling for free)
+The simplest sort of test suite is one crafted to run on the same host
+system using the same toolchain as the release artifact under development.
-3. Execute Ceedling at command line to create example project
- or an empty Ceedling project in your filesystem (executing
- `ceedling help` first is, well, helpful).
+But, Ceedling, Unity, and CMock were developed for use on a wide variety
+of systems and include features handy for low-level system development work.
+This is especially of interest to embedded systems developers.
-Gem install notes:
+## All your sweet, sweet test suite options
-1. Steps 1-2 are a one time affair for your local environment.
- When steps 1-2 are completed once, only step 3 is needed for
- each new project.
+Ceedling, Unity, and CMock help you create and run test suites using any
+of the following approaches. For more on this topic, please see this
+[handy dandy article][tts-which-build] and/or follow the links for each
+item listed below.
-Getting Started after Ceedling is installed:
+[tts-which-build]: https://throwtheswitch.org/build/which
-1. Once Ceedling is installed, you'll want to start to integrate it with new
- and old projects alike. If you wanted to start to work on a new project
- named `foo`, Ceedling can create the skeleton of the project using `ceedling
- new foo`. Likewise if you already have a project named `bar` and you want to
- integrate Ceedling into it, you would run `ceedling new bar` and Ceedling
- will create any files and directories it needs to run.
-
-2. Now that you have Ceedling integrated with a project, you can start using it.
- A good starting point to get use to Ceedling either in a new project or an
- existing project is creating a new module to get use to Ceedling by issuing
- the command `ceedling module:create[unicorn]`.
-
-General notes:
-
-1. Certain advanced features of Ceedling rely on gcc and cpp
- as preprocessing tools. In most linux systems, these tools
- are already available. For Windows environments, we recommend
- the [mingw project](http://www.mingw.org/) (Minimalist
- GNU for Windows). This represents an optional, additional
- setup / installation step to complement the list above. Upon
- installing mingw ensure your system path is updated or set
- [:environment][:path] in your `project.yml` file (see
- environment section later in this document).
-
-2. To use a project file name other than the default `project.yml`
- or place the project file in a directory other than the one
- in which you'll run Rake, create an environment variable
- `CEEDLING_MAIN_PROJECT_FILE` with your desired project
- file path.
-
-3. To better understand Rake conventions, Rake execution,
- and Rakefiles, consult the [Rake tutorial, examples, and
- user guide](http://rubyrake.org/).
-
-4. When using Ceedling in Windows environments, a test file name may
- not include the sequences âpatchâ or âsetupâ. The Windows Installer
- Detection Technology (part of UAC), requires administrator
- privileges to execute file names with these strings.
-
-Now What? How Do I Make It GO?
-------------------------------
-
-We're getting a little ahead of ourselves here, but it's good
-context on how to drive this bus. Everything is done via the command
-line. We'll cover conventions and how to actually configure
-your project in later sections.
+1. **[Native][tts-build-native].** This option builds and runs code on your
+ host system.
+ 1. In the simplest case this means you are testing code that is intended
+ to run on the same sort of system as the test suite. Your test
+ compiler toolchain is the same as your release compiler toolchain.
+ 1. However, a native build can also mean your test compiler is different
+ than your release compiler. With some thought and effort, code for
+ another platform can be tested on your host system. This is often
+ the best approach for embedded and other specialized development.
+1. **[Emulator][tts-build-cross].** In this option, you build your test code with your target's
+ toolchain, and then run the test suite using an emulator provided for
+ that target. This is a good option for embedded and other specialized
+ development â if an emulator is available.
+1. **[On target][tts-build-cross].** The Ceedling bundle of tools can create test suites that
+ run on a target platform directly. Particularly in embedded development
+ â believe it or not â this is often the option of last resort. That is,
+ you should probably go with the other options in this list.
-To run tests, build your release artifact, etc., you will be interacting
-with Rake on the command line. Ceedling works with Rake to present
-you with named tasks that coordinate the file generation and
-build steps needed to accomplish something useful. You can also
-add your own independent Rake tasks or create plugins to extend
-Ceedling (more on this later).
+[tts-build-cross]: https://throwtheswitch.org/build/cross
+[tts-build-native]: https://throwtheswitch.org/build/native
-* `ceedling [no arguments]`:
+
- Run the default Rake task (conveniently recognized by the name default
- by Rake). Neither Rake nor Ceedling provide a default task. Rake will
- abort if run without arguments when no default task is defined. You can
- conveniently define a default task in the Rakefile discussed in the
- preceding setup & installation section of this document.
+# How Does a Test Case Even Work?
-* `ceedling -T`:
+## Behold assertions
- List all available Rake tasks with descriptions (Rake tasks without
- descriptions are not listed). -T is a command line switch for Rake and
- not the same as tasks that follow.
+In its simplest form, a test case is just a C function with no
+parameters and no return value that packages up logical assertions.
+If no assertions fail, the test case passes. Technically, an empty
+test case function is a passing test since there can be no failing
+assertions.
-* `ceedling --trace`:
+Ceedling relies on the [Unity] project for its unit test framework
+(i.e. the thing that provides assertions and counts up passing
+and failing tests).
- For advanced users troubleshooting a confusing build error, debug
- Ceedling or a plugin, --trace provides a stack trace of dependencies
- walked during task execution and any Ruby failures along the way. Note
- that --trace is a command line switch for Rake and is not the same as
- tasks that follow.
+An assertion is simply a logical comparison of expected and actual
+values. Unity provides a wide variety of different assertions to
+cover just about any scenario you might encounter. Getting
+assertions right is actually a bit tricky. Unity does all that
+hard work for you and has been thoroughly tested itself and battle
+hardened through use by many, many developers.
-* `ceedling environment`:
+### Super simple passing test case
- List all configured environment variable names and string values. This
- task is helpful in verifying the evaluation of any Ruby expressions in
- the [:environment] section of your config file. *: Note: Ceedling may
- set some convenience environment variables by default.*
+```c
+#include "unity.h"
-* `ceedling paths:*`:
+void test_case(void) {
+ TEST_ASSERT_TRUE( (1 == 1) );
+}
+```
- List all paths collected from [:paths] entries in your YAML config
- file where * is the name of any section contained in [:paths]. This
- task is helpful in verifying the expansion of path wildcards / globs
- specified in the [:paths] section of your config file.
+### Super simple failing test case
-* `ceedling files:assembly`
-* `ceedling files:include`
-* `ceedling files:source`
-* `ceedling files:support`
-* `ceedling files:test`
+```c
+#include "unity.h"
- List all files and file counts collected from the relevant search
- paths specified by the [:paths] entries of your YAML config file. The
- files:assembly task will only be available if assembly support is
- enabled in the [:release_build] section of your configuration file.
+void test_a_different_case(void) {
+ TEST_ASSERT_TRUE( (1 == 2) );
+}
+```
-* `ceedling options:*`:
+### Realistic simple test case
- Load and merge configuration settings into the main project
- configuration. Each task is named after a `*.yml` file found in the
- configured options directory. See documentation for the configuration
- setting [:project][:options_paths] and for options files in advanced
- topics.
+In reality, weâre probably not testing the static value of an integer
+against itself. Instead, weâre calling functions in our source code
+and making assertions against return values.
-* `ceedling test:all`:
+```c
+#include "unity.h"
+#include "my_math.h"
- Run all unit tests (rebuilding anything that's changed along the way).
+void test_some_sums(void) {
+ TEST_ASSERT_EQUALS( 5, mySum( 2, 3) );
+ TEST_ASSERT_EQUALS( 6, mySum( 0, 6) );
+ TEST_ASSERT_EQUALS( -12, mySum( 20, -32) );
+}
+```
-* `ceedling test:build_only`:
+If an assertion fails, the test case fails. As soon as an assertion
+fails, execution within that test case stops.
- Build all unit tests, object files and executable but not run them.
+Multiple test cases can live in the same test file. When all the
+test cases are run, their results are tallied into simple pass
+and fail metrics with a bit of metadata for failing test cases such
+as line numbers and names of test cases.
-* `ceedling test:delta`:
+Ceedling and Unity work together to both automatically run your test
+cases and tally up all the results.
- Run only those unit tests for which the source or test files have
- changed (i.e. incremental build). Note: with the
- [:project][:use_test_preprocessor] configuration file option set,
- runner files are always regenerated limiting the total efficiency this
- text execution option can afford.
+### Sample test case output
-* `ceedling test:*`:
+Successful test suite run:
- Execute the named test file or the named source file that has an
- accompanying test. No path. Examples: ceedling test:foo.c or ceedling
- test:test_foo.c
+```
+--------------------
+OVERALL TEST SUMMARY
+--------------------
+TESTED: 49
+PASSED: 49
+FAILED: 0
+IGNORED: 0
+```
-* `ceedling test:pattern[*]`:
+A test suite with a failing test:
- Execute any tests whose name and/or path match the regular expression
- pattern (case sensitive). Example: ceedling "test:pattern[(I|i)nit]" will
- execute all tests named for initialization testing. Note: quotes may
- be necessary around the ceedling parameter to distinguish regex characters
- from command line operators.
+```
+-------------------
+FAILED TEST SUMMARY
+-------------------
+[test/TestModel.c]
+ Test: testInitShouldCallSchedulerAndTemperatureFilterInit
+ At line (21): "Function TaskScheduler_Init() called more times than expected."
+
+--------------------
+OVERALL TEST SUMMARY
+--------------------
+TESTED: 49
+PASSED: 48
+FAILED: 1
+IGNORED: 0
+```
-* `ceedling test:path[*]`:
+### Advanced test cases with mocks
- Execute any tests whose path contains the given string (case
- sensitive). Example: ceedling test:path[foo/bar] will execute all tests
- whose path contains foo/bar. Note: both directory separator characters
- / and \ are valid.
-
-* `ceedling test:* --test_case= `
- Execute test case which match **test_case_name**. Option available only after
- setting up **cmdline_args** to true under **test_runner** in project.yml:
-
- ```
- :test_runner:
- :cmdline_args: true
- ```
+Often you want to test not just what a function returns but how
+it interacts with other functions.
- For instance, if you have file test_gpio.c with defined 3 tests:
+The simple test cases above work well at the "edges" of a
+codebase (libraries, state management, some kinds of I/O, etc.).
+But, in the messy middle of your code, code calls other code.
+One way to handle testing this is with [mock functions][mocks] and
+[interaction-based testing][interaction-based-tests].
- - test_gpio_start
- - test_gpio_configure_proper
- - test_gpio_configure_fail_pin_not_allowed
+Mock functions are functions with the same interface as the real
+code the mocks replace. A mocked function allows you to control
+how it behaves and wrap up assertions within a higher level idea
+of expectations.
- and you want to run only configure tests, you can call:
+What is meant by an expectation? Well⊠We _expect_ a certain
+function is called with certain arguments and that it will return
+certain values. With the appropriate code inside a mocked function
+all of this can be managed and checked.
- ```ceedling test:gpio --test_case=configure```
+You can write your own mocks, of course. But, it's generally better
+to rely on something else to do it for you. Ceedling uses the [CMock]
+framework to perform mocking for you.
- ---
- **Limitation**
+Here's some sample code you might want to test:
- The Unity implementation use test case name as substring which will be search in your test case names. If you pass only **gpio** and your file under test contains **gpio** in the name, it will run all tests from it. This is connected with the logic, how Unity generates test_ files. In such case, it is suggested to use full name of test case.
+```c
+#include "other_code.h"
+
+void doTheThingYo(mode_t input) {
+ mode_t result = processMode(input);
+ if (result == MODE_3) {
+ setOutput(OUTPUT_F);
+ }
+ else {
+ setOutput(OUTPUT_D);
+ }
+}
+```
- ---
+And, here's what test cases using mocks for that code could look
+like:
-* `ceedling test:* --exclude_test_case= `
- Execute test case which does not match **test_case_name**. Option available only after
- setting up **cmdline_args** to true under **test_runner** in project.yml:
-
- ```
- :test_runner:
- :cmdline_args: true
- ```
+```c
+#include "mock_other_code.h"
- For instance, if you have file test_gpio.c with defined 3 tests:
+void test_doTheThingYo_should_enableOutputF(void) {
+ // Mocks
+ processMode_ExpectAndReturn(MODE_1, MODE_3);
+ setOutput_Expect(OUTPUT_F);
- - test_gpio_start
- - test_gpio_configure_proper
- - test_gpio_configure_fail_pin_not_allowed
+ // Function under test
+ doTheThingYo(MODE_1);
+}
- and you want to run only start tests, you can call:
+void test_doTheThingYo_should_enableOutputD(void) {
+ // Mocks
+ processMode_ExpectAndReturn(MODE_2, MODE_4);
+ setOutput_Expect(OUTPUT_D);
- ```ceedling test:gpio --exclude_test_case=configure```
+ // Function under test
+ doTheThingYo(MODE_2);
+}
+```
- ---
- **Limitation**
+Remember, the generated mock code you canât see here has a whole bunch
+of smarts and Unity assertions inside it. CMock scans header files and
+then generates mocks (C code) from the function signatures it finds in
+those header files. It's kinda magical.
- The Unity implementation use test case name as substring which will be search in your test case names. If you pass only **gpio** and your file under test contains **gpio** in the name, it will run all tests from it. This is connected with the logic, how Unity generates test_ files. In such case, it is suggested to use full name of test case.
+### That was the basics, but youâll need more
- ---
+For more on the assertions and mocking shown above, consult the
+documentation for [Unity] and [CMock] or the resources in
+Ceedlingâs [README][/README.md].
+Ceedling, Unity, and CMock rely on a variety of
+[conventions to make your life easier][conventions-and-behaviors].
+Read up on these to understand how to build up test cases
+and test suites.
-* `ceedling release`:
+Also take a look at the very next sections for more examples
+and details on how everything fits together.
- Build all source into a release artifact (if the release build option
- is configured).
+[conventions-and-behaviors]: #important-conventions--behaviors
-* `ceedling release:compile:*`:
+
- Sometimes you just need to compile a single file dagnabit. Example:
- ceedling release:compile:foo.c
+# Commented Sample Test File
-* `ceedling release:assemble:*`:
+**Here is a beautiful test file to help get you startedâŠ**
- Sometimes you just need to assemble a single file doggonit. Example:
- ceedling release:assemble:foo.s
+## Core concepts in code
-* `ceedling module:create[Filename]`:
-* `ceedling module:create[Filename]`:
+After absorbing this sample code, youâll have context for much
+of the documentation that follows.
- It's often helpful to create a file automatically. What's better than
- that? Creating a source file, a header file, and a corresponding test
- file all in one step!
+The sample test file below demonstrates the following:
- There are also patterns which can be specified to automatically generate
- a bunch of files. Try `ceedling module:create[Poodles,mch]` for example!
+1. Making use of the Unity & CMock test frameworks.
+1. Adding the source under test (`foo.c`) to the final test
+ executable by convention (`#include "foo.h"`).
+1. Adding two mocks to the final test executable by convention
+ (`#include "mock_bar.h` and `#include "mock_baz.h`).
+1. Adding a source file with no matching header file to the test
+ executable with a test build directive macro
+ `TEST_SOURCE_FILE("more.c")`.
+1. Creating two test cases with mock expectations and Unity
+ assertions.
- The module generator has several options you can configure.
- F.e. Generating the source/header/test file in a subdirectory (by adding when calling module:create).
- For more info, refer to the [Module Generator](https://github.com/ThrowTheSwitch/Ceedling/blob/master/docs/CeedlingPacket.md#module-generator) section.
+All other conventions and features are documented in the sections
+that follow.
-* `ceedling module:stub[Filename]`:
-* `ceedling module:stub[Filename]`:
+```c
+// test_foo.c -----------------------------------------------
+#include "unity.h" // Compile/link in Unity test framework
+#include "types.h" // Header file with no *.c file -- no compilation/linking
+#include "foo.h" // Corresponding source file, foo.c, under test will be compiled and linked
+#include "mock_bar.h" // bar.h will be found and mocked as mock_bar.c + compiled/linked in;
+#include "mock_baz.h" // baz.h will be found and mocked as mock_baz.c + compiled/linked in
- So what happens if you've created your API in your header (maybe even using
- TDD to do so?) and now you need to start to implement the corresponding C
- module? Why not get a head start by using `ceedilng module:stub[headername]`
- to automatically create a function skeleton for every function declared in
- that header? Better yet, you can call this again whenever you add new functions
- to that header to add just the new functions, leaving the old ones alone!
+TEST_SOURCE_FILE("more.c") // foo.c depends on symbols from more.c, but more.c has no matching more.h
-* `ceedling logging `:
+void setUp(void) {} // Every test file requires this function;
+ // setUp() is called by the generated runner before each test case function
- Enable logging to /logs. Must come before test and release
- tasks to log their steps and output. Log names are a concatenation of
- project, user, and option files loaded. User and option files are
- documented in the advanced topics section of this document.
+void tearDown(void) {} // Every test file requires this function;
+ // tearDown() is called by the generated runner after each test case function
-* `ceedling verbosity[x] `:
+// A test case function
+void test_Foo_Function1_should_Call_Bar_AndGrill(void)
+{
+ Bar_AndGrill_Expect(); // Function from mock_bar.c that instructs our mocking
+ // framework to expect Bar_AndGrill() to be called once
+ TEST_ASSERT_EQUAL(0xFF, Foo_Function1()); // Foo_Function1() is under test (Unity assertion):
+ // (a) Calls Bar_AndGrill() from bar.h
+ // (b) Returns a byte compared to 0xFF
+}
- Change the default verbosity level. [x] ranges from 0 (quiet) to 4
- (obnoxious). Level [3] is the default. The verbosity task must precede
- all tasks in the command line list for which output is desired to be
- seen. Verbosity settings are generally most meaningful in conjunction
- with test and release tasks.
+// Another test case function
+void test_Foo_Function2_should_Call_Baz_Tec(void)
+{
+ Baz_Tec_ExpectAnd_Return(1); // Function from mock_baz.c that instructs our mocking
+ // framework to expect Baz_Tec() to be called once and return 1
+ TEST_ASSERT_TRUE(Foo_Function2()); // Foo_Function2() is under test (Unity assertion)
+ // (a) Calls Baz_Tec() in baz.h
+ // (b) Returns a value that can be compared to boolean true
+}
-* `ceedling summary`:
+// end of test_foo.c ----------------------------------------
+```
- If plugins are enabled, this task will execute the summary method of
- any plugins supporting it. This task is intended to provide a quick
- roundup of build artifact metrics without re-running any part of the
- build.
+## Ceedling actions from the sample test code
-* `ceedling clean`:
+From the test file specified above Ceedling will generate
+`test_foo_runner.c`. This runner file will contain `main()` and will call
+both of the example test case functions.
- Deletes all toolchain binary artifacts (object files, executables),
- test results, and any temporary files. Clean produces no output at the
- command line unless verbosity has been set to an appreciable level.
+The final test executable will be `test_foo.exe` (Windows) or `test_foo.out`
+for Unix-based systems (extensions are configurable. Based on the `#include`
+list and test directive macro above, the test executable will be the output
+of the linker having processed `unity.o`, `foo.o`, `mock_bar.o`, `mock_baz.o`,
+`more.o`, `test_foo.o`, and `test_foo_runner.o`.
-* `ceedling clobber`:
+Ceedling finds the needed code files, generates mocks, generates a runner,
+compiles all the code files, and links everything into the test executable.
+Ceedling will then run the test executable and collect test results from it
+to be reported to the developer at the command line.
- Extends clean task's behavior to also remove generated files: test
- runners, mocks, preprocessor output. Clobber produces no output at the
- command line unless verbosity has been set to an appreciable level.
+## Incidentally, Ceedling comes with example projects
-* `ceedling options:export`:
+Ceedling comes with entire example projects you can extract.
- This allows you to export a snapshot of your current tool configuration
- as a yaml file. You can specify the name of the file in brackets `[blah.yml]`
- or let it default to `tools.yml`. In either case, the produced file can be
- used as the tool configuration for you project if desired, and modified as you
- wish.
+1. Execute `ceedling examples` in your terminal to list available example
+ projects.
+1. Execute `ceedling example [destination]` to extract the
+ named example project.
-To better understand Rake conventions, Rake execution, and
-Rakefiles, consult the [Rake tutorial, examples, and user guide][guide].
+You can inspect the _project.yml_ file and source & test code. Run
+`ceedling help` from the root of the example projects to see what you can
+do, or just go nuts with `ceedling test:all`.
-[guide]: http://rubyrake.org/
+
-At present, none of Ceedling's commands provide persistence.
-That is, they must each be specified at the command line each time
-they are needed. For instance, Ceedling's verbosity command
-only affects output at the time it's run.
+# Anatomy of a Test Suite
-Individual test and release file tasks
-are not listed in `-T` output. Because so many files may be present
-it's unwieldy to list them all.
+A Ceedling test suite is composed of one or more individual test executables.
-Multiple rake tasks can be executed at the command line (order
-is executed as provided). For example, `ceedling
-clobber test:all release` will removed all generated files;
-build and run all tests; and then build all source - in that order.
-If any Rake task fails along the way, execution halts before the
-next task.
+The [Unity] project provides the actual framework for test case assertions
+and unit test sucess/failure accounting. If mocks are enabled, [CMock] builds
+on Unity to generate mock functions from source header files with expectation
+test accounting. Ceedling is the glue that combines these frameworks, your
+projectâs toolchain, and your source code into a collection of test
+executables you can run as a singular suite.
-The `clobber` task removes certain build directories in the
-course of deleting generated files. In general, it's best not
-to add to source control any Ceedling generated directories
-below the root of your top-level build directory. That is, leave
-anything Ceedling & its accompanying tools generate out of source
-control (but go ahead and add the top-level build directory that
-holds all that stuff). Also, since Ceedling is pretty smart about
-what it rebuilds and regenerates, you needn't clobber often.
+## What is a test executable?
-Important Conventions
-=====================
+Put simply, in a Ceedling test suite, each test file becomes a test executable.
+Your test code file becomes a single test executable.
-Directory Structure, Filenames & Extensions
--------------------------------------------
+`test_foo.c` âĄïž `test_foo.out` (or `test_foo.exe` on Windows)
-Much of Ceedling's functionality is driven by collecting files
-matching certain patterns inside the paths it's configured
-to search. See the documentation for the [:extension] section
-of your configuration file (found later in this document) to
-configure the file extensions Ceedling uses to match and collect
-files. Test file naming is covered later in this section.
+A single test executable generally comprises the following. Each item in this
+list is a C file compiled into an object file. The entire list is linked into
+a final test executable.
-Test files and source files must be segregated by directories.
-Any directory structure will do. Tests can be held in subdirectories
-within source directories, or tests and source directories
-can be wholly separated at the top of your project's directory
-tree.
+* One or more release C code files under test (`foo.c`)
+* `unity.c`.
+* A test C code file (`test_foo.c`).
+* A generated test runner C code file (`test_foo_runner.c`). `main()` is located
+ in the runner.
+* If using mocks:
+ * `cmock.c`
+ * One more mock C code files generated from source header files (`mock_bar.c`)
-Search Path Order
------------------
-
-When Ceedling searches for files (e.g. looking for header files
-to mock) or when it provides search paths to any of the default
-gcc toolchain executables, it organizes / prioritizes its search
-paths. The order is always: test paths, support paths, source
-paths, and then include paths. This can be useful, for instance,
-in certain testing scenarios where we desire Ceedling or a compiler
-to find a stand-in header file in our support directory before
-the actual source header file of the same name.
-
-This convention only holds when Ceedling is using its default
-tool configurations and / or when tests are involved. If you define
-your own tools in the configuration file (see the [:tools] section
-documented later in this here document), you have complete control
-over what directories are searched and in what order. Further,
-test and support directories are only searched when appropriate.
-That is, when running a release build, test and support directories
-are not used at all.
-
-Source Files & Binary Release Artifacts
----------------------------------------
+## Why multiple individual test executables in a suite?
-Your binary release artifact results from the compilation and
-linking of all source files Ceedling finds in the specified source
-directories. At present only source files with a single (configurable)
-extension are recognized. That is, `*.c` and `*.cc` files will not
-both be recognized - only one or the other. See the configuration
-options and defaults in the documentation for the [:extension]
-sections of your configuration file (found later in this document).
+For several reasons:
-Test Files & Executable Test Fixtures
--------------------------------------
+* This greatly simplifies the building of your tests.
+* C lacks any concept of namespaces or reflection abilities able to segment and
+ distinguish test cases.
+* This allows the same release code to be built differently under different
+ testing scenarios. Think of how different `#define`s, compiler flags, and
+ linked libraries might come in handy for different tests of the same
+ release C code. One source file can be built and tested in different ways
+ with multiple test files.
-Ceedling builds each individual test file with its accompanying
-source file(s) into a single, monolithic test fixture executable.
-Test files are recognized by a naming convention: a (configurable)
-prefix such as "`test_`" in the file name with the same file extension
-as used by your C source files. See the configuration options
-and defaults in the documentation for the [:project] and [:extension]
-sections of your configuration file (found later in this document).
-Depending on your configuration options, Ceedling can recognize
-a variety of test file naming patterns in your test search paths.
-For example: `test_some_super_functionality.c`, `TestYourSourceFile.cc`,
-or `testing_MyAwesomeCode.C` could each be valid test file
-names. Note, however, that Ceedling can recognize only one test
-file naming convention per project.
+## Ceedlingâs role in your test suite
-Ceedling knows what files to compile and link into each individual
-test executable by way of the #include list contained in each
-test file. Any C source files in the configured search directories
-that correspond to the header files included in a test file will
-be compiled and linked into the resulting test fixture executable.
-From this same #include list, Ceedling knows which files to mock
-and compile and link into the test executable (if you use mocks
-in your tests). That was a lot of clauses and information in a very
-few sentences; the example that follows in a bit will make it clearer.
+A test executable is not all that hard to create by hand, but it can be tedious,
+repetitive, and error-prone.
-By naming your test functions according to convention, Ceedling
-will extract and collect into a runner C file calls to all your
-test case functions. This runner file handles all the execution
-minutiae so that your test file can be quite simple and so that
-you never forget to wire up a test function to be executed. In this
-generated runner lives the `main()` entry point for the resulting
-test executable. There are no configuration options for the
-naming convention of your test case functions. A test case function
-signature must have these three elements: void return, void
-parameter list, and the function name prepended with lowercase
-"`test`". In other words, a test function signature should look
-like this: `void test``[any name you like]``(void)`.
-
-A commented sample test file follows on the next page. Also, see
-the sample project contained in the Ceedling documentation
-bundle.
+What Ceedling provides is an ability to perform the process repeatedly and simply
+at the push of a button, alleviating the tedium and any forgetfulness. Just as
+importantly, Ceedling also does all the work of running each of those test
+executables and tallying all the test results.
-```c
-// test_foo.c -----------------------------------------------
-#include "unity.h" // compile/link in Unity test framework
-#include "types.h" // header file with no *.c file -- no compilation/linking
-#include "foo.h" // source file foo.c under test
-#include "mock_bar.h" // bar.h will be found and mocked as mock_bar.c + compiled/linked in;
- // foo.c includes bar.h and uses functions declared in it
-#include "mock_baz.h" // baz.h will be found and mocked as mock_baz.c + compiled/linked in
- // foo.c includes baz.h and uses functions declared in it
+
+# Ceedling Installation & Set Up
-void setUp(void) {} // every test file requires this function;
- // setUp() is called by the generated runner before each test case function
+**How Exactly Do I Get Started?**
-void tearDown(void) {} // every test file requires this function;
- // tearDown() is called by the generated runner after each test case function
+You have two good options for installing and running Ceedling:
-// a test case function
-void test_Foo_Function1_should_Call_Bar_AndGrill(void)
-{
- Bar_AndGrill_Expect(); // setup function from mock_bar.c that instructs our
- // framework to expect Bar_AndGrill() to be called once
- TEST_ASSERT_EQUAL(0xFF, Foo_Function1()); // assertion provided by Unity
- // Foo_Function1() calls Bar_AndGrill() & returns a byte
-}
+1. The Ceedling Ruby Gem
+1. Prepackaged _MadScienceLab_ Docker images
-// another test case function
-void test_Foo_Function2_should_Call_Baz_Tec(void)
-{
- Baz_Tec_ExpectAnd_Return(1); // setup function provided by mock_baz.c that instructs our
- // framework to expect Baz_Tec() to be called once and return 1
- TEST_ASSERT_TRUE(Foo_Function2()); // assertion provided by Unity
-}
+The simplest way to get started with a local installation is to install
+Ceedling as a Ruby gem. Gems are simply prepackaged Ruby-based software.
+Other options exist, but the Ceedling Gem is the best option for a local
+installation. However, you will also need a compiler toolchain (e.g. GNU
+Compiler Collection) plus any supporting tools used by any plugins you
+enabled.
-// end of test_foo.c ----------------------------------------
-```
+If you are familiar with the virtualization technology Docker, our premade
+Docker images will get you started with Ceedling and all the accompanying
+tools lickety split. Install Docker, pull down one of the _MadScienceLab_
+images and go.
-From the test file specified above Ceedling will generate `test_foo_runner.c`;
-this runner file will contain `main()` and call both of the example
-test case functions.
-
-The final test executable will be `test_foo.exe` (for Windows
-machines or `test_foo.out` for linux systems - depending on default
-or configured file extensions). Based on the #include list above,
-the test executable will be the output of the linker having processed
-`unity.o`, `foo.o`, `mock_bar.o`, `mock_baz.o`, `test_foo.o`,
-and `test_foo_runner.o`. Ceedling finds the files, generates
-mocks, generates a runner, compiles all the files, and links
-everything into the test executable. Ceedling will then run
-the test executable and collect test results from it to be reported
-to the developer at the command line.
-
-For more on the assertions and mocks shown, consult the documentation
-for Unity and CMock.
-
-The Magic of Dependency Tracking
---------------------------------
-
-Ceedling is pretty smart in using Rake to build up your project's
-dependencies. This means that Ceedling automagically rebuilds
-all the appropriate files in your project when necessary: when
-your configuration changes, Ceedling or any of the other tools
-are updated, or your source or test files change. For instance,
-if you modify a header file that is mocked, Ceedling will ensure
-that the mock is regenerated and all tests that use that mock are
-rebuilt and re-run when you initiate a relevant testing task.
-When you see things rebuilding, it's for a good reason. Ceedling
-attempts to regenerate and rebuild only what's needed for a given
-execution of a task. In the case of large projects, assembling
-dependencies and acting upon them can cause some delay in executing
-tasks.
-
-With one exception, the trigger to rebuild or regenerate a file
-is always a disparity in timestamps between a target file and
-its source - if an input file is newer than its target dependency,
-the target is rebuilt or regenerated. For example, if the C source
-file from which an object file is compiled is newer than that object
-file on disk, recompilation will occur (of course, if no object
-file exists on disk, compilation will always occur). The one
-exception to this dependency behavior is specific to your input
-configuration. Only if your logical configuration changes
-will a system-wide rebuild occur. Reorganizing your input configuration
-or otherwise updating its file timestamp without modifying
-the values within the file will not trigger a rebuild. This behavior
-handles the various ways in which your input configuration can
-change (discussed later in this document) without having changed
-your actual project YAML file.
-
-Ceedling needs a bit of help to accomplish its magic with deep
-dependencies. Shallow dependencies are straightforward:
-a mock is dependent on the header file from which it's generated,
-a test file is dependent upon the source files it includes (see
-the preceding conventions section), etc. Ceedling handles
-these "out of the box." Deep dependencies are specifically a
-C-related phenomenon and occur as a consequence of include statements
-within C source files. Say a source file includes a header file
-and that header file in turn includes another header file which
-includes still another header file. A change to the deepest header
-file should trigger a recompilation of the source file, a relinking
-of all the object files comprising a test fixture, and a new execution
-of that test fixture.
-
-Ceedling can handle deep dependencies but only with the help
-of a C preprocessor. Ceedling is quite capable, but a full C preprocessor
-it ain't. Your project can be configured to use a C preprocessor
-or not. Simple projects or large projects constructed so as to
-be quite flat in their include structure generally don't need
-deep dependency preprocessing - and can enjoy the benefits of
-faster execution. Legacy code, on the other hand, will almost
-always want to be tested with deep preprocessing enabled. Set
-up of the C preprocessor is covered in the documentation for the
-[:project] and [:tools] section of the configuration file (later
-in this document). Ceedling contains all the configuration
-necessary to use the gcc preprocessor by default. That is, as
-long as gcc is in your system search path, deep preprocessing
-of deep dependencies is available to you by simply enabling it
-in your project configuration file.
-
-Ceedling's Build Output
------------------------
+## Local Installation As a [Ruby Gem](http://docs.rubygems.org/read/chapter/1):
-Ceedling requires a top-level build directory for all the stuff
-that it, the accompanying test tools, and your toolchain generate.
-That build directory's location is configured in the [:project]
-section of your configuration file (discussed later). There
-can be a ton of generated files. By and large, you can live a full
-and meaningful life knowing absolutely nothing at all about
-the files and directories generated below the root build directory.
+1. [Download and install Ruby][ruby-install]. Ruby 3 is required.
-As noted already, it's good practice to add your top-level build
-directory to source control but nothing generated beneath it.
-You'll spare yourself headache if you let Ceedling delete and
-regenerate files and directories in a non-versioned corner
-of your project's filesystem beneath the top-level build directory.
+1. Use Rubyâs command line gem package manager to install Ceedling:
+ `gem install ceedling`. Unity, CMock, and CException come along with
+ Ceedling at no extra charge.
-The `artifacts` directory is the one and only directory you may
-want to know about beneath the top-level build directory. The
-subdirectories beneath `artifacts` will hold your binary release
-target output (if your project is configured for release builds)
-and will serve as the conventional location for plugin output.
-This directory structure was chosen specifically because it
-tends to work nicely with Continuous Integration setups that
-recognize and list build artifacts for retrieval / download.
+1. Execute Ceedling at command line to create example project
+ or an empty Ceedling project in your filesystem (executing
+ `ceedling help` first is, well, helpful).
-The Almighty Project Configuration File (in Glorious YAML)
-----------------------------------------------------------
+[ruby-install]: http://www.ruby-lang.org/en/downloads/
-Please consult YAML documentation for the finer points of format
-and to understand details of our YAML-based configuration file.
-We recommend [Wikipedia's entry on YAML](http://en.wikipedia.org/wiki/Yaml)
-for this. A few highlights from that reference page:
+### Gem install notes
-* YAML streams are encoded using the set of printable Unicode
- characters, either in UTF-8 or UTF-16
+Steps 1-2 are a one time affair for your local environment. When steps 1-2
+are completed once, only step 3 is needed for each new project.
-* Whitespace indentation is used to denote structure; however
- tab characters are never allowed as indentation
+## _MadScienceLab_ Docker Images
-* Comments begin with the number sign ( # ), can start anywhere
- on a line, and continue until the end of the line unless enclosed
- by quotes
+As an alternative to local installation, fully packaged Docker images containing Ruby, Ceedling, the GCC toolchain, and more are also available. [Docker][docker-overview] is a virtualization technology that provides self-contained software bundles that are a portable, well-managed alternative to local installation of tools like Ceedling.
-* List members are denoted by a leading hyphen ( - ) with one member
- per line, or enclosed in square brackets ( [ ] ) and separated
- by comma space ( , )
+Four Docker image variants containing Ceedling and supporting tools exist. These four images are available for both Intel and ARM host platforms (Docker does the right thing based on your host environment). The latter includes ARM Linux and Appleâs M-series macOS devices.
-* Hashes are represented using the colon space ( : ) in the form
- key: value, either one per line or enclosed in curly braces
- ( { } ) and separated by comma space ( , )
+1. **_[MadScienceLab][docker-image-base]_**. This image contains Ruby, Ceedling, CMock, Unity, CException, the GNU Compiler Collection (gcc), and a handful of essential C libraries and command line utilities.
+1. **_[MadScienceLab Plugins][docker-image-plugins]_**. This image contains all of the above plus the command line tools that Ceedlingâs built-in plugins rely on. Naturally, it is quite a bit larger than option (1) because of the additional tools and dependencies.
+1. **_[MadScienceLab ARM][docker-image-arm]_**. This image mirrors (1) with the compiler toolchain replaced with the GNU `arm-none-eabi` variant.
+1. **_[MadScienceLab ARM + Plugins][docker-image-arm-plugins]_**. This image is (3) with the addition of all the complementary plugin tooling just like (2) provides.
-* Strings (scalars) are ordinarily unquoted, but may be enclosed
- in double-quotes ( " ), or single-quotes ( ' )
+See the Docker Hub pages linked above for more documentation on these images.
-* YAML requires that colons and commas used as list separators
- be followed by a space so that scalar values containing embedded
- punctuation can generally be represented without needing
- to be enclosed in quotes
+Just to be clear here, most users of the _MadScienceLab_ Docker images will probably care about the ability to run unit tests on your own host. If you are one of those users, no matter what host platform you are on â Intel or ARM â youâll want to go with (1) or (2) above. The tools within the image will automatically do the right thing within your environment. Options (3) and (4) are most useful for specialized cross-compilation scenarios.
-* Repeated nodes are initially denoted by an ampersand ( & ) and
- thereafter referenced with an asterisk ( * )
+### _MadScienceLab_ Docker Image usage basics
-Notes on what follows:
+To use a _MadScienceLab_ image from your local terminal:
-* Each of the following sections represent top-level entries
- in the YAML configuration file.
+1. [Install Docker][docker-install]
+1. Determine:
+ 1. The local path of your Ceedling project
+ 1. The variant and revision of the Docker image youâll be using
+1. Run the container with:
+ 1. The Docker `run` command and `-it --rm` command line options
+ 1. A Docker volume mapping from the root of your project to the default project path inside the container (_/home/dev/project_)
-* Unless explicitly specified in the configuration file, default
- values are used by Ceedling.
+See the command line examples in the following two sections.
-* These three settings, at minimum, must be specified:
- * [:project][:build_root]
- * [:paths][:source]
- * [:paths][:test]
+Note that all of these somewhat lengthy command lines lend themselves well to being wrapped up in simple helper scripts specific to your project and directory structure.
-* As much as is possible, Ceedling validates your settings in
- properly formed YAML.
+### Run a _MadScienceLab_ Docker Image as an interactive terminal
-* Improperly formed YAML will cause a Ruby error when the YAML
- is parsed. This is usually accompanied by a complaint with
- line and column number pointing into the project file.
+When the container launches as shown below, it will drop you into a Z-shell command line that has access to all the tools and utilities available within the container. In this usage, the Docker container becomes just another terminal, including ending its execution with `exit`.
-* Certain advanced features rely on gcc and cpp as preprocessing
- tools. In most linux systems, these tools are already available.
- For Windows environments, we recommend the [mingw project](http://www.mingw.org/)
- (Minimalist GNU for Windows).
+```shell
+ > docker run -it --rm -v /my/local/project/path:/home/dev/project throwtheswitch/madsciencelab-plugins:1.0.0
+```
-* Ceedling is primarily meant as a build tool to support automated
- unit testing. All the heavy lifting is involved there. Creating
- a simple binary release build artifact is quite trivial in
- comparison. Consequently, most default options and the construction
- of Ceedling itself is skewed towards supporting testing though
+Once the _MadScienceLab_ containerâs command line is available, to run Ceedling, execute it just as you would after installing Ceedling locally:
+
+```shell
+ ~/project > ceedling help
+```
+
+```shell
+ ~/project > ceedling new ...
+```
+
+```shell
+ ~/project > ceedling test:all
+```
+
+### Run a _MadScienceLab_ Docker Image as a command line utility
+
+Alternatively, you can run Ceedling through the _MadScienceLab_ Docker container directly from the command line as a command line utility. The general pattern is immediately below.
+
+```shell
+ > docker run -it --rm -v /my/local/project/path:/home/dev/project throwtheswitch/madsciencelab-plugins:1.0.0
+```
+
+As a specific example, to run all tests in a suite, the command line would be this:
+
+```shell
+ > docker run -it --rm -v /my/local/project/path:/home/dev/project throwtheswitch/madsciencelab-plugins:1.0.0 ceedling test:all
+```
+
+In this usage, the container starts, executes Ceedling, and then ends.
+
+[docker-overview]: https://www.ibm.com/topics/docker
+[docker-install]: https://www.docker.com/products/docker-desktop/
+
+[docker-image-base]: https://hub.docker.com/repository/docker/throwtheswitch/madsciencelab
+[docker-image-plugins]: https://hub.docker.com/repository/docker/throwtheswitch/madsciencelab-plugins
+[docker-image-arm]: https://hub.docker.com/repository/docker/throwtheswitch/madsciencelab-arm-none-eabi
+[docker-image-arm-plugins]: https://hub.docker.com/repository/docker/throwtheswitch/madsciencelab-arm-none-eabi-plugins
+
+## Getting Started after Ceedling is Installed
+
+1. Once Ceedling is installed, youâll want to start to integrate it with new
+ and old projects alike. If you wanted to start to work on a new project
+ named `foo`, Ceedling can create the skeleton of the project using `ceedling
+ new foo `. Likewise if you already have a project named `bar`
+ and you want to âinjectâ Ceedling into it, you would run `ceedling new bar
+ `, and Ceedling will create any files and directories it needs.
+
+1. Now that you have Ceedling integrated with a project, you can start using it.
+ A good starting point is to enable the [plugin](#ceedling-plugins)
+ `module_generator` in your project configuration file and create a source +
+ test code module to get accustomed to Ceedling by issuing the command
+ `ceedling 'module:create[name]'`.
+
+## Grab Bag of Ceedling Notes
+
+1. Certain advanced features of Ceedling rely on `gcc` and `cpp` as
+ preprocessing tools. In most Linux systems, these tools are already available.
+ For Windows environments, we recommend the
+ [MinGW project](http://www.mingw.org/) (Minimalist GNU for Windows). This
+ represents an optional, additional setup / installation step to complement
+ the list above. Upon installing MinGW ensure your system path is updated or
+ set `:environment` âł `:path` in your project configuration (see `:environment`
+ section).
+
+1. When using Ceedling in Windows environments, a test filename should not
+ include the sequences âpatchâ or âsetupâ. After a test build these test
+ filenames will become test executables. Windows Installer Detection Technology
+ (part of UAC) requires administrator privileges to execute filenames including
+ these strings.
+
+
+
+# Now What? How Do I Make It _GO_? The Command Line.
+
+Weâre getting a little ahead of ourselves here, but it's good
+context on how to drive this bus. Everything is done via the command
+line. We'll cover project conventions and how to actually configure
+your project in later sections.
+
+For now, let's talk about the command line.
+
+To run tests, build your release artifact, etc., you will be using the
+trusty command line. Ceedling is transitioning away from being built
+around Rake. As such, right now, interacting with Ceedling at the
+command line involves two different conventions:
+
+1. **Application Commands.** Application commands tell Ceedling what to
+ to do with your project. These create projects, load project files,
+ begin builds, output version information, etc. These include rich
+ help and operate similarly to popular command line tools like `git`.
+1. **Build & Plugin Tasks.** Build tasks actually execute test suites,
+ run release builds, etc. These tasks are created from your project
+ file. These are generated through Ceedlingâs Rake-based code and
+ conform to its conventions â simplistic help, no option flags, but
+ bracketed arguments.
+
+In the case of running builds, both come into play at the command line.
+
+The two classes of command line arguments are clearly labelled in the
+summary of all commands provided by `ceedling help`.
+
+## Quick command line example to get you started
+
+To exercise the Ceedling command line quickly, follow these steps after
+[installing Ceedling](#ceedling-installation--set-up):
+
+1. Open a terminal and chnage directories to a location suitable for
+ an example project.
+1. Execute `ceedling example temp_sensor` in your terminal. The `example`
+ argument is an application command.
+1. Change directories into the new _temp_sensor/_ directory.
+1. Execute `ceedling test:all` in your terminal. The `test:all` is a
+ build task executed by the default (and omitted) `build` application
+ command.
+1. Take a look at the build and test suite console output as well as
+ the _project.yml_ file in the root of the example project.
+
+## Ceedling application commands
+
+Ceedling provides robust command line help for application commands.
+Execute `ceedling help` for a summary view of all application commands.
+Execute `ceedling help ` for detailed help.
+
+_NOTE:_ Because the built-in command line help is thorough, we will only
+briefly list and explain the available application commands.
+
+* `ceedling [no arguments]`:
+
+ Runs the default build tasks. Unless set in the project file, Ceedling
+ uses a default task of `test:all`. To override this behavior, set your
+ own default tasks in the project file (see later section).
+
+* `ceedling build ` or `ceedling `:
+
+ Runs the named build tasks. `build` is optional (i.e. `ceedling test:all`
+ is equivalent to `ceedling build test:all`). Various option flags
+ exist to control project configuration loading, verbosity levels,
+ logging, test task filters, etc.
+
+ See next section to understand the build & plugin tasks this application
+ command is able to execute. Run `ceedling help build` to understand all
+ the command line flags that work with build & plugin tasks.
+
+* `ceedling dumpconfig`:
+
+ Process project configuration and write final result to a YAML file.
+ Various option flags exist to control project configuration loading,
+ configuration manipulation, and configuration sub-section extraction.
+
+* `ceedling environment`:
+
+ Lists project related environment variables:
+
+ * All environment variable names and string values added to your
+ environment from within Ceedling and through the `:environment`
+ section of your configuration. This is especially helpful in
+ verifying the evaluation of any string replacement expressions in
+ your `:environment` config entries.
+ * All existing Ceedling-related environment variables set before you
+ ran Ceedling from the command line.
+
+* `ceedling example`:
+
+ Extracts an example project from within Ceedling to your local
+ filesystem. The available examples are listed with
+ `ceedling examples`. Various option flags control whether the example
+ contains vendored Ceedling and/or a documentation bundle.
+
+* `ceedling examples`:
+
+ Lists the available examples within Ceedling. To extract an example,
+ use `ceedling example`.
+
+* `ceedling help`:
+
+ Displays summary help for all application commands and detailed help
+ for each command. `ceedling help` also loads your project
+ configuration (if available) and lists all build tasks from it.
+ Various option flags control what project configuration is loaded.
+
+* `ceedling new`:
+
+ Creates a new project structure. Various option flags control whether
+ the new project contains vendored Ceedling, a documentation bundle,
+ and/or a starter project configuration file.
+
+* `ceedling upgrade`:
+
+ Upgrade vendored installation of Ceedling for an existing project
+ along with any locally installed documentation bundles.
+
+* `ceedling version`:
+
+ Displays version information for Ceedling and its components. Version output for Ceedling includes the Git Commit short SHA in Ceedlingâs build identifier and Ceedlingâs path of origin.
+
+ ```
+ đ± Welcome to Ceedling!
+
+ Ceedling => #.#.#-
+ ----------------------
+
+
+ Build Frameworks
+ ----------------------
+ CMock => #.#.#
+ Unity => #.#.#
+ CException => #.#.#
+ ```
+
+ If the short SHA information is unavailable such as in local development, the SHA is omitted. The source for this string is generated and captured in the Gem at the time of Ceedlingâs automated build in CI.
+
+## Ceedling build & plugin tasks
+
+Build task are loaded from your project configuration. Unlike
+application commands that are fixed, build tasks vary depending on your
+project configuration and the files within your project structure.
+
+Ultimately, build & plugin tasks are executed by the `build` application
+command (but the `build` keyword can be omitted â see above).
+
+* `ceedling paths:*`:
+
+ List all paths collected from `:paths` entries in your YAML config
+ file where `*` is the name of any section contained in `:paths`. This
+ task is helpful in verifying the expansion of path wildcards / globs
+ specified in the `:paths` section of your config file.
+
+* `ceedling files:assembly`
+* `ceedling files:header`
+* `ceedling files:source`
+* `ceedling files:support`
+* `ceedling files:test`
+
+ List all files and file counts collected from the relevant search
+ paths specified by the `:paths` entries of your YAML config file. The
+ `files:assembly` task will only be available if assembly support is
+ enabled in the `:release_build` or `:test_build` sections of your
+ configuration file.
+
+* `ceedling test:all`:
+
+ Run all unit tests.
+
+* `ceedling test:*`:
+
+ Execute the named test file or the named source file that has an
+ accompanying test. No path. Examples: `ceedling test:foo`, `ceedling
+ test:foo.c` or `ceedling test:test_foo.c`
+
+* `ceedling test:* --test-case= `
+ Execute individual test cases which match `test_case_name`.
+
+ For instance, if you have a test file _test_gpio.c_ containing the following
+ test cases (test cases are simply `void test_name(void)`:
+
+ - `test_gpio_start`
+ - `test_gpio_configure_proper`
+ - `test_gpio_configure_fail_pin_not_allowed`
+
+ ⊠and you want to run only _configure_ tests, you can call:
+
+ `ceedling test:gpio --test-case=configure`
+
+ **Test case matching notes**
+
+ * Test case matching is on sub-strings. `--test_case=configure` matches on
+ the test cases including the word _configure_, naturally.
+ `--test-case=gpio` would match all three test cases.
+
+* `ceedling test:* --exclude_test_case= `
+ Execute test cases which do not match `test_case_name`.
+
+ For instance, if you have file test_gpio.c with defined 3 tests:
+
+ - `test_gpio_start`
+ - `test_gpio_configure_proper`
+ - `test_gpio_configure_fail_pin_not_allowed`
+
+ ⊠and you want to run only start tests, you can call:
+
+ `ceedling test:gpio --exclude_test_case=configure`
+
+ **Test case exclusion matching notes**
+
+ * Exclude matching follows the same sub-string logic as discussed in the
+ preceding section.
+
+* `ceedling test:pattern[*]`:
+
+ Execute any tests whose name and/or path match the regular expression
+ pattern (case sensitive). Example: `ceedling "test:pattern[(I|i)nit]"`
+ will execute all tests named for initialization testing.
+
+ _NOTE:_ Quotes are likely necessary around the regex characters or
+ entire task to distinguish characters from shell command line operators.
+
+* `ceedling test:path[*]`:
+
+ Execute any tests whose path contains the given string (case
+ sensitive). Example: `ceedling test:path[foo/bar]` will execute all tests
+ whose path contains foo/bar. _Notes:_
+
+ 1. Both directory separator characters `/` and `\` are valid.
+ 1. Quotes may be necessary around the task to distinguish the parameter's
+ characters from shell command line operators.
+
+* `ceedling release`:
+
+ Build all source into a release artifact (if the release build option
+ is configured).
+
+* `ceedling release:compile:*`:
+
+ Sometimes you just need to compile a single file dagnabit. Example:
+ `ceedling release:compile:foo.c`
+
+* `ceedling release:assemble:*`:
+
+ Sometimes you just need to assemble a single file doggonit. Example:
+ `ceedling release:assemble:foo.s`
+
+* `ceedling summary`:
+
+ If plugins are enabled, this task will execute the summary method of
+ any plugins supporting it. This task is intended to provide a quick
+ roundup of build artifact metrics without re-running any part of the
+ build.
+
+* `ceedling clean`:
+
+ Deletes all toolchain binary artifacts (object files, executables),
+ test results, and any temporary files. Clean produces no output at the
+ command line unless verbosity has been set to an appreciable level.
+
+* `ceedling clobber`:
+
+ Extends clean task's behavior to also remove generated files: test
+ runners, mocks, preprocessor output. Clobber produces no output at the
+ command line unless verbosity has been set to an appreciable level.
+
+## Ceedling Command Line Tasks, Extra Credit
+
+### Combining Tasks At the Command Line
+
+Multiple build tasks can be executed at the command line.
+
+For example, `ceedling clobber test:all release` will remove all generated
+files; build and run all tests; and then build all source â in that order. If
+any task fails along the way, execution halts before the next task.
+
+Task order is executed as provided and can be important! Running `clobber` after
+a `test:` or `release:` task will not accomplish much.
+
+### Build Directory and Revision Control
+
+The `clobber` task removes certain build directories in the
+course of deleting generated files. In general, it's best not
+to add to source control any Ceedling generated directories
+below the root of your top-level build directory. That is, leave
+anything Ceedling & its accompanying tools generate out of source
+control (but go ahead and add the top-level build directory that
+holds all that stuff if you want).
+
+### Logging decorators
+
+Ceedling attempts to bring more joy to your console logging. This may include
+fancy Unicode characters, emoji, or color.
+
+Example:
+```
+-----------------------
+â OVERALL TEST SUMMARY
+-----------------------
+TESTED: 6
+PASSED: 5
+FAILED: 1
+IGNORED: 0
+```
+
+By default, Ceedling makes an educated guess as to which platforms can best
+support this. Some platforms (weâre looking at you, Windows) do not typically
+have default font support in their terminals for these features. So, by default
+this feature is disabled on problematic platforms while enabled on others.
+
+An environment variable `CEEDLING_DECORATORS` forces decorators on or off with a
+`true` (`1`) or `false` (`0`) string value.
+
+If you find a monospaced font that provides emojis, etc. and works with Windowsâ
+command prompt, you can (1) Install the font (2) change your command promptâs
+font (3) set `CEEDLING_DECORATORS` to `true`.
+
+
+
+# Important Conventions & Behaviors
+
+**How to get things done and understand whatâs happening during builds**
+
+## Directory Structure, Filenames & Extensions
+
+Much of Ceedlingâs functionality is driven by collecting files
+matching certain patterns inside the paths it's configured
+to search. See the documentation for the `:extension` section
+of your configuration file (found later in this document) to
+configure the file extensions Ceedling uses to match and collect
+files. Test file naming is covered later in this section.
+
+Test files and source files must be segregated by directories.
+Any directory structure will do. Tests can be held in subdirectories
+within source directories, or tests and source directories
+can be wholly separated at the top of your projectâs directory
+tree.
+
+## Search Paths for Test Builds
+
+Test builds in C are fairly complex. Each test file becomes a test
+executable. Each test executable needs generated runner code and
+optionally generated mocks. Slicing and dicing what files are
+compiled and linked and how search paths are assembled is tricky
+business. Thatâs why Ceedling exists in the first place. Because
+of these issues, search paths, in particular, require quite a bit
+of special handling.
+
+Unless your project is relying exclusively on `extern` statements and
+uses no mocks for testing, Ceedling _**must**_ be told where to find
+header files. Without search path knowledge, mocks cannot be generated,
+and test file compilation will fail for lack of symbol definitions
+and function declarations.
+
+Ceedling provides two mechanisms for configuring search paths:
+
+1. The [`:paths` âł `:include`](#paths--include) section within your
+ project file (or mixin files).
+1. The [`TEST_INCLUDE_PATH(...)`](#test_include_path) build directive
+ macro. This is only available within test files.
+
+In testing contexts, you have three options for assembling the core of
+the search path list used by Ceedling for test builds:
+
+1. List all search paths within the `:paths` âł `:include` subsection
+ of your project file. This is the simplest and most common approach.
+1. Create the search paths for each test file using calls to the
+ `TEST_INCLUDE_PATH(...)` build directive macro within each test file.
+1. Blending the preceding options. In this approach the subsection
+ within your project file acts as a common, base list of search
+ paths while the build directive macro allows the list to be
+ expanded upon for each test file. This method is especially helpful
+ for large and/or complex projects in trimming down
+ problematically long compiler command lines.
+
+As for the complete search path list for test builds created by Ceedling,
+it is assembled from a variety of sources. In order:
+
+1. Mock generation build path (if mocking is enabled)
+1. Paths provided via `TEST_INCLUDE_PATH(...)` build directive macro
+1. Any paths within `:paths` âł `:test` list containing header files
+1. `:paths` âł `:support` list from your project configuration
+1. `:paths` âł `:include` list from your project configuration
+1. `:paths` âł `:libraries` list from your project configuration
+1. Internal path for Unityâs unit test framework C code
+1. Internal paths for CMock and CExceptionâs C code (if respective
+ features enabled)
+1. `:paths` âł `:test_toolchain_include` list from your project
+ configuration
+
+The paths lists above are documented in detail in the discussion of
+project configuration.
+
+_**Notes:**_
+
+* The order of your `:paths` entries directly translates to the ordering
+ of search paths.
+* The logic of the ordering above is essentially that:
+ * Everything above (5) should have precedence to allow test-specific
+ symbols, function signatures, etc. to be found before that of your
+ source code under test. This is the necessary pattern for effective
+ testing and test builds.
+ * Everything below (5) is supporting symbols and function signatures
+ for your source code. Your source code should be processed before
+ these for effective builds generally.
+* (3) is a balancing act. It is entirely possible that test developers
+ will choose to create common files of symbols and supporting code
+ necessary for unit tests and choose to organize it alongside their
+ test files. A test build must be able to find these references. At the
+ same time it is highly unlikely every test directory path in a project
+ is necessary for a test build â particularly in large and sophisticated
+ projects. To reduce overall search path length and problematic command
+ lines, this convention tailors the search path. This is low risk
+ tailoring but could cause gotchas in edge cases or when Ceedling is
+ combined with other tools. Any other such tailoring is avoided as it
+ could too easily cause maddening build problems.
+* Remember that the ordering of search paths is impacted by the merge
+ order of any Mixins. Paths specified with Mixins will be added to
+ path lists in your project configuration in the order of merging.
+
+## Search Paths for Release Builds
+
+Unlike test builds, release builds are relatively straightforward. Each
+source file is compiled into an object file. All object files are linked.
+A Ceedling release build may optionally compile and link in CException
+and can handle linking in libraries as well.
+
+Search paths for release builds are configured with `:paths` âł `:include`
+in your project configuration. Thatâs about all there is to it.
+
+## Conventions for Source Files & Binary Release Artifacts
+
+Your binary release artifact results from the compilation and
+linking of all source files Ceedling finds in the specified source
+directories. At present only source files with a single (configurable)
+extension are recognized. That is, `*.c` and `*.cc` files will not
+both be recognized - only one or the other. See the configuration
+options and defaults in the documentation for the `:extension`
+sections of your configuration file (found later in this document).
+
+## Conventions for Test Files & Executable Test Fixtures
+
+Ceedling builds each individual test file with its accompanying
+source file(s) into a single, monolithic test fixture executable.
+
+### Test File Naming Convention
+
+Ceedling recognizes test files by a naming convention â a (configurable)
+prefix such as "`test_`" at the beginning of the file name with the same
+file extension as used by your C source files. See the configuration options
+and defaults in the documentation for the `:project` and `:extension`
+sections of your configuration file (elsewhere in this document).
+
+Depending on your configuration options, Ceedling can recognize
+a variety of test file naming patterns in your test search paths.
+For example, `test_some_super_functionality.c`, `TestYourSourceFile.cc`,
+or `testing_MyAwesomeCode.C` could each be valid test file
+names. Note, however, that Ceedling can recognize only one test
+file naming convention per project.
+
+### Conventions for Source and Mock Files to Be Compiled & Linked
+
+Ceedling knows what files to compile and link into each individual
+test executable by way of the `#include` list contained in each
+test file and optional test directive macros.
+
+The `#include` list directs Ceedling in two ways:
+
+1. Any C source files in the configured project directories
+ corresponding to `#include`d header files will be compiled and
+ linked into the resulting test fixture executable.
+1. If you are using mocks, header files with the appropriate
+ mocking prefix (e.g. `mock_foo.h`) direct Ceedling to find the
+ source header file (e.g. `foo.h`), generate a mock from it, and
+ compile & link that generated code into into the test executable
+ as well.
+
+Sometimes the source file you need to add to your test executable has
+no corresponding header file â e.g. `file_abc.h` contains symbols
+present in `file_xyz.c`. In these cases, you can use the test
+directive macro `TEST_SOURCE_FILE(...)` to tell Ceedling to compile
+and link the desired source file into the test executable (see
+macro documentation elsewhere in this doc).
+
+That was a lot of information and many clauses in a very few
+sentences; the commented example test file code that follows in a
+bit will make it clearer.
+
+### Convention for Test Case Functions + Test Runner Generation
+
+By naming your test functions according to convention, Ceedling
+will extract and collect into a generated test runner C file the
+appropriate calls to all your test case functions. This runner
+file handles all the execution minutiae so that your test file
+can be quite simple. As a bonus, youâll never forget to wire up
+a test function to be executed.
+
+In this generated runner lives the `main()` entry point for the
+resulting test executable. There are no configurable options for
+the naming convention of your test case functions.
+
+A test case function signature must have these elements:
+
+1. `void` return
+1. `void` parameter list
+1. A function name prepended with lowercase "`test`".
+
+In other words, a test function signature should look like this:
+`void test(void)`.
+
+## Ceedling preprocessing behavior for your tests
+
+### Preprocessing feature background and overview
+
+Ceedling and CMock are advanced tools that both perform fairly sophisticated
+parsing.
+
+However, neither of these tools fully understands the entire C language,
+especially Câs preprocessing statements.
+
+If your test files rely on macros and `#ifdef` conditionals used in certain
+ways (see examples below), thereâs a chance that Ceedling will break on trying
+to process your test files, or, alternatively, your test suite will build but
+not execute as expected.
+
+Similarly, generating mocks of header files with macros and `#ifdef`
+conditionals around or in function signatures can get weird. Of course, itâs
+often in sophisticated projects with complex header files that mocking is most
+desired in the first place.
+
+Ceedling includes an optional ability to preprocess the following files before
+then extracting test cases and functions to be mocked with text parsing.
+
+1. Your test files, or
+1. Mockable header files, or
+1. Both of the above
+
+See the [`:project` âł `:use_test_preprocessor`][project-settings] project
+configuration setting.
+
+This Ceedling feature uses `gcc`âs preprocessing mode and the `cpp` preprocessor
+tool to strip down / expand test files and headers to their raw code content
+that can then be parsed as text by Ceedling and CMock. These tools must be in
+your search path if Ceedlingâs preprocessing is enabled.
+
+**Ceedlingâs test preprocessing abilities are directly tied to the features and
+output of `gcc` and `cpp`. The default Ceedling tool definitions for these should
+not be redefined for other toolchains. It is highly unlikely to work for you.
+Future Ceedling improvements will allow for a plugin-style ability to use your
+own tools in this highly specialized capacity.**
+
+[project-settings]: #project-global-project-settings
+
+### Ceedling preprocessing limitations and gotchas
+
+#### Preprocessing limitations cheatsheet
+
+Ceedlingâs preprocessing abilities are generally quite useful â especially in
+projects with multiple build configurations for different feature sets or
+multiple targets, legacy code that cannot be refactored, and complex header
+files provided by vendors.
+
+However, best applying Ceedlingâs preprocessing abilities requires understanding
+how the feature works, when to use it, and its limitations.
+
+At a high level, Ceedlingâs preprocessing is applicable for cases where macros
+or conditional compilation preprocessing statements (e.g. `#ifdef`):
+
+* Generate or hide/reveal your test filesâ `#include` statements.
+* Generate or hide/reveal your test filesâ test case function signatures
+ (e.g. `void test_foo()`.
+* Generate or hide/reveal mockable header filesâ `#include` statements.
+* Generate or hide/reveal header filesâ mockable function signatures.
+
+**_NOTE:_ You do not necessarily need to enable Ceedlingâs preprocessing only
+because you have preprocessing statements in your test files or mockable header
+files. The feature is only truly needed if your project meets the conditions
+above.**
+
+The sections that follow flesh out the details of the bulleted list above.
+
+#### Preprocessing gotchas
+
+**_IMPORTANT:_ As of Ceedling 1.0.0, Ceedlingâs test preprocessing feature
+has a limitation that affects Unity features triggered by the following macros.**
+
+* `TEST_CASE()`
+* `TEST_RANGE()`
+
+`TEST_CASE()` and `TEST_RANGE()` are Unity macros that are positional in a file
+in relation to the test case functions they modify. While Ceedling's test file
+preprocessing can preserve these macro calls, their position cannot be preserved.
+
+That is, Ceedlingâs preprocessing and these Unity features are not presently
+compatible. Note that it _is_ possible to enable preprocessing for mockable
+header files apart from enabling it for test files. See the documentation for
+`:project` âł `:use_test_preprocessing`. This can allow test preprocessing in the
+common cases of sophtisticate mockable headers while Unityâs `TEST_CASE()` and
+`TEST_RANGE()` are utilized in a test file untouched by preprocessing.
+
+**_IMPORTANT:_ The following new build directive macro `TEST_INCLUDE_PATH()`
+available in Ceedling 1.0.0 is incompatible with enclosing conditional
+compilation C preprocessing statements:**
+
+Wrapping `TEST_INCLUDE_PATH()` in conditional compilation statements
+(e.g. `#ifdef`) will not behave as you expect. This macro is used as a marker
+for advanced abilities discovered by Ceedling parsing a test file as plain text.
+Whether or not Ceedling preprocessing is enabled, Ceedling will always discover
+this marker macro in the plain text of a test file.
+
+Why is `TEST_INCLUDE_PATH()` incompatible with `#ifdef`? Well, itâs because of
+a cyclical dependency that cannot be resolved. In order to perform test
+preprocessing, we need a full complement of `#include` search paths. These
+could be provided, in part, by `TEST_INCLUDE_PATH()`. But, if we allow
+`TEST_INCLUDE_PATH()` to be placed within conditional compilation C
+preprocessing statements, our search paths may be different after test
+preprocessing! The only solution is to disallow this and scan a test file as
+plain text looking for this macro at the beginning of a test build.
+
+**_Notes:_**
+
+* `TEST_SOURCE_FILE()` _can_ be placed within conditional compilation
+ C preprocessing statements.
+* `TEST_INCLUDE_PATH()` & `TEST_SOURCE_FILE()` can be âhiddenâ from Ceedlingâs
+ text scanning with traditional C comments.
+
+### Preprocessing of your test files
+
+When preprocessing is enabled for test files, Ceedling will expand preprocessor
+statements in test files before extracting `#include` conventions and test case
+signatures. That is, preprocessing output is used to generate test runners
+and assemble the components of a test executable build.
+
+**_NOTE:_** Conditional directives _inside_ test case functions generally do
+not require Ceedlingâs test preprocessing ability. Assuming your code is correct,
+the C preprocessor within your toolchain will do the right thing for you
+in your test build. Read on for more details and the other cases of interest.
+
+Test file preprocessing by Ceedling is applicable primarily when conditional
+preprocessor directives generate the `#include` statements for your test file
+and/or generate or enclose full test case functions. Ceedling will not be able
+to properly discover your `#include` statements or test case functions unless
+they are plainly available in an expanded, raw code version of your test file.
+Ceedlingâs preprocessing abilities provide that expansion.
+
+#### Examples of when Ceedling preprocessing **_is_** needed for test files
+
+Generally, Ceedling preprocessing is needed when:
+
+1. `#include` statements are generated by macros
+1. `#include` statements are conditionally present due to `#ifdef` statements
+1. Test case function signatures are generated by macros
+1. Test case function signatures are conditionaly present due to `#ifdef` statements
+
+```c
+// #include conventions are not recognized for anything except #include "..." statements
+INCLUDE_STATEMENT_MAGIC("header_file")
+```
+```c
+// Test file scanning will always see this #include statement
+#ifdef BUILD_VARIANT_A
+#include "mock_FooBar.h"
+#endif
+```
+```c
+// Test runner generation scanning will see the test case function signature and think this test case exists in every build variation
+#ifdef MY_SUITE_BUILD
+void test_some_test_case(void) {
+ TEST_ASSERT_EQUALS(...);
+}
+#endif
+```
+```c
+// Test runner generation will not recognize this as a test case when scanning the file
+void TEST_CASE_MAGIC("foo_bar_case") {
+ TEST_ASSERT_EQUALS(...);
+}
+```
+
+#### Examples of when test preprocessing is **_not_** needed for test files
+
+```c
+// Code inside a test case is simply code that your toolchain will expand and build as you desire
+// You can manage your compile time symbols with the :defines section of your project configuration file
+void test_some_test_case(void) {
+#ifdef BUILD_VARIANT_A
+ TEST_ASSERT_EQUALS(...);
+#endif
+
+#ifdef BUILD_VARIANT_B
+ TEST_ASSERT_EQUALS(...);
+#endif
+}
+```
+
+### Preprocessing of mockable header files
+
+When preprocessing is enabled for mocking, Ceedling will expand preprocessor
+statements in header files before generating mocks from them. CMock requires
+a clear look at function definitions and types in order to do its work.
+
+Header files with preprocessor directives and conditional macros can easily
+obscure details from CMockâs limited C parser. Advanced C projects tend
+to rely on preprocessing directives and macros to accomplish everything from
+build variants to OS calls to register access to managing proprietary language
+extensions.
+
+Mocking is often most useful in complicated codebases. As such Ceedlingâs
+preprocessing abilities tend to be quite necessary to properly expand header
+files so CMock can parse them.
+
+#### Examples of when Ceedling preprocessing **_is_** needed for mockable headers
+
+Generally, Ceedling preprocessing is needed when:
+
+1. Function signatures are formed by macros
+1. Function signatures are conditionaly present due to surrounding `#ifdef`
+ statements
+1. Macros expand to become function decorators, return types, or parameters
+
+**_Important Notes:_**
+
+* Sometimes CMockâs parsing features can be configured to handle scenarios
+ that fall within (3) above. CMock can match and remove most text strings,
+ match and replace certain text strings, map custom types to mockable
+ alternatives, and be extended with a Unity helper to handle complex and
+ compound types. See [CMock]âs documentation for more.
+
+* Test preprocessing causes any macros or symbols in a mockable header to
+ âdisappearâ in the generated mock. Itâs quite common to have needed symbols
+ or macros in a header file that do not directly impact the function
+ signatures to be mocked. This can break compilation of your test suite.
+
+ Possible solutions to this problem include:
+
+ 1. Move symbols and macros in your header file that do not impact function
+ signatures to another source header file that will not be filtered
+ by Ceedlingâs header file preprocessing.
+ 1. If (1) is not possible, you may duplicate the needed symbols and macros
+ in a header file that is only available in your test build search paths
+ and include it in your test file.
+
+```c
+// Header file scanning will see this function signature but mistakenly mock the name of the macro
+void FUNCTION_SIGNATURE_MAGIC(...);
+```
+
+```c
+// Header file scanning will always see this function signature
+#ifdef BUILD_VARIANT_A
+unsigned int someFunction(void);
+#endif
+```
+
+```c
+// Header file scanning will either fail for this function signature or extract erroneous type names
+INLINE_MAGIC RETURN_TYPE_MAGIC someFunction(PARAMETER_MAGIC);
+```
+
+## Execution time (duration) reporting in Ceedling operations & test suites
+
+### Ceedlingâs logged run times
+
+Ceedling logs two execution times for every project run.
+
+It first logs the set up time necessary to process your project file, parse code
+files, build an internal representation of your project, etc. This duration does
+not capture the time necessary to load the Ruby runtime itself.
+
+```
+Ceedling set up completed in 223 milliseconds
+```
+
+Secondly, each Ceedling run also logs the time necessary to run all the tasks
+you specify at the command line.
+
+```
+Ceedling operations completed in 1.03 seconds
+```
+
+### Ceedling test suite and Unity test executable run durations
+
+A test suite comprises one or more Unity test executables (see
+[Anatomy of a Test Suite][anatomy-test-suite]). Ceedling times indvidual Unity
+test executable run durations. It also sums these into a total test suite
+execution time. These duration values are typically used in generating test
+reports via plugins.
+
+Not all test report formats utilize duration values. For those that do, some
+effort is usually required to map Ceedling duration values to a relevant test
+suite abstraction within a given test report format.
+
+Because Ceedling can execute builds with multiple threads, care must be taken
+to interpret test suite duration values â particularly in relation to
+Ceedlingâs logged run times.
+
+In a multi-threaded build it's quite common for the logged Ceedling project run
+time to be less than the total suite time in a test report. In multi-threaded
+builds on multi-core machines, test executables are run on different processors
+simultaneously. As such, the total on-processor time in a test report can
+exceed the operation time Ceedling itself logs to the console. Further, because
+multi-threading tends to introduce context switching and processor scheduling
+overhead, the run duration of a test executable may be reported as longer than
+a in a comparable single-threaded build.
+
+[anatomy-test-suite]: #anatomy-of-a-test-suite
+
+### Unity test case run times
+
+Individual test case exection time tracking is specifically a [Unity] feature
+(see its documentation for more details). If enabled and if your platform
+supports the time mechanism Unity relies on, Ceedling will automatically
+collect test case time values â generally made use of by test report plugins.
+
+To enable test case duration measurements, they must be enabled as a Unity
+compilation option. Add `UNITY_INCLUDE_EXEC_TIME` to Unity's compilation
+symbols (`:unity` âł `:defines`) in your Ceedling project file (see example
+below). Unity test case durations as reported by Ceedling default to 0 if the
+compilation option is not set.
+
+```yaml
+:unity:
+ :defines:
+ - UNITY_INCLUDE_EXEC_TIME
+```
+
+_NOTE:_ Most test cases are quite short, and most computers are quite fast. As
+ such, Unity test case execution time is often reported as 0 milliseconds as
+ the CPU execution time for a test case typically remains in the microseconds
+ range. Unity would require special rigging that is inconsistently available
+ across platforms to measure test case durations at a finer resolution.
+
+## The Magic of Dependency Tracking
+
+Previous versions of Ceedling used features of Rake to offer
+various kinds of smart rebuilds--that is, only regenerating files,
+recompiling code files, or relinking executables when changes within
+the project had occurred since the last build. Optional Ceedling
+features discovered âdeep dependenciesâ such that, for example, a
+change in a header file several nested layers deep in `#include`
+statements would cause all the correct test executables to be
+updated and run.
+
+These features have been temporarily disabled and/or removed for
+test suites and remain in limited form for release build while
+Ceedling undergoes a major overhaul.
+
+Please see the [Release Notes](ReleaseNotes.md).
+
+### Notes on (Not So) Smart Rebuids
+
+* New features that are a part of the Ceedling overhaul can
+ significantly speed up test suite execution and release builds
+ despite the present behavior of brute force running all build
+ steps. See the discussion of enabling multi-threaded builds in
+ later sections.
+
+* When smart rebuilds return, they will further speed up builds as
+ will other planned optimizations.
+
+## Ceedlingâs Build Output (Files, That Is)
+
+Ceedling requires a top-level build directory for all the stuff
+that it, the accompanying test tools, and your toolchain generate.
+That build directory's location is configured in the top-level
+`:project` section of your configuration file (discussed later). There
+can be a ton of generated files. By and large, you can live a full
+and meaningful life knowing absolutely nothing at all about
+the files and directories generated below the root build directory.
+
+As noted already, it's good practice to add your top-level build
+directory to source control but nothing generated beneath it.
+youâll spare yourself headache if you let Ceedling delete and
+regenerate files and directories in a non-versioned corner
+of your projectâs filesystem beneath the top-level build directory.
+
+The `artifacts/` directory is the one and only directory you may
+want to know about beneath the top-level build directory. The
+subdirectories beneath `artifacts` will hold your binary release
+target output (if your project is configured for release builds)
+and will serve as the conventional location for plugin output.
+This directory structure was chosen specifically because it
+tends to work nicely with Continuous Integration setups that
+recognize and list build artifacts for retrieval / download.
+
+## Build _Errors_ vs. Test _Failures_. Oh, and Exit Codes.
+
+### Errors vs. Failures
+
+Ceedling will run a specified build until an **_error_**. An error
+refers to a build step encountering an unrecoverable problem. Files
+not found, nonexistent paths, compilation errors, missing symbols,
+plugin exceptions, etc. are all errors that will cause Ceedling
+to immediately end a build.
+
+A **_failure_** refers to a test failure. That is, an assertion of
+an expected versus actual value failed within a unit test case.
+A test failure will not stop a build. Instead, the suite will run
+to completion with test failures collected and reported along with
+all test case statistics.
+
+### Ceedling Exit Codes
+
+In its default configuration, Ceedling terminates with an exit code
+of `1`:
+
+ * On any build error and immediately terminates upon that build
+ error.
+ * On any test case failure but runs the build to completion and
+ shuts down normally.
+
+This behavior can be especially handy in Continuous Integration
+environments where you typically want an automated CI build to break
+upon either build errors or test failures.
+
+If this exit code convention for test failures does not work for you,
+no problem-o. You may be of the mind that running a test suite to
+completion should yield a successful exit code (even if tests failed).
+Add the following to your project file to force Ceedling to finish a
+build with an exit code of 0 even upon test case failures.
+
+```yaml
+# Ceedling terminates with happy `exit(0)` even if test cases fail
+:test_build:
+ :graceful_fail: true
+```
+
+If you use the option for graceful failures in CI, youâll want to
+rig up some kind of logging monitor that scans Ceedlingâs test
+summary report sent to `$stdout` and/or a log file. Otherwise, you
+could have a successful build but failing tests.
+
+### Notes on Unity Test Executable Exit Codes
+
+Ceedling works by collecting multiple Unity test executables together
+into a test suite ([more here](#anatomy-of-a-test-suite).
+
+A Unity test executable's exit code is the number of failed tests. An
+exit code of `0` means all tests passed while anything larger than zero
+is the number of test failures.
+
+Because of platform limitations on how big an exit code number can be
+and because of the logical complexities of distinguishing test failure
+counts from build errors or plugin problems, Ceedling conforms to a
+much simpler exit code convention than Unity: `0` = đ while `1` = âčïž.
+
+
+
+# Using Unity, CMock & CException
+
+If you jumped ahead to this section but do not follow some of the
+lingo here, please jump back to an [earlier section for definitions
+and helpful links][helpful-definitions].
+
+[helpful-definitions]: #hold-on-back-up-ruby-rake-yaml-unity-cmock-cexception
+
+## An overview of how Ceedling supports, well, its supporting frameworks
+
+If you are using Ceedling for unit testing, this means you are using Unity,
+the C testing framework. Unity is fully built-in and enabled for test builds.
+It cannot be disabled.
+
+If you want to use mocks in your test cases, youâll need to enable mocking
+and configure CMock with `:project` âł `:use_mocks` and the `:cmock` section
+of your project configuration respectively. CMock is fully supported by
+Ceedling but generally requires some set up for your projectâs needs.
+
+If you are incorporating CException into your release artifact, youâll need
+to enable exceptions and configure CException with `:project` âł
+`:use_exceptions` and the `:cexception` section of your project
+configuration respectively. Enabling CException makes it available in both
+release builds and test builds.
+
+This section provides a high-level view of how the various tools become
+part of your builds and fit into Ceedlingâs configuration file. Ceedlingâs
+configuration file is discussed in detail in the next section.
+
+See [Unity], [CMock], and [CException]âs project documentation for all
+your configuration options. Ceedling offers facilities for providing these
+frameworks their compilation and configuration settings. Discussing
+these tools and all their options in detail is beyond the scope of Ceedling
+documentation.
+
+## Unity Configuration
+
+Unity is wholly compiled C code. As such, its configuration is entirely
+controlled by a variety of compilation symbols. These can be configured
+in Ceedlingâs `:unity` project settings.
+
+### Example Unity configurations
+
+#### Itty bitty processor & toolchain with limited test execution options
+
+```yaml
+:unity:
+ :defines:
+ - UNITY_INT_WIDTH=16 # 16 bit processor without support for 32 bit instructions
+ - UNITY_EXCLUDE_FLOAT # No floating point unit
+```
+
+#### Great big gorilla processor that grunts and scratches
+
+```yaml
+:unity:
+ :defines:
+ - UNITY_SUPPORT_64 # Big memory, big counters, big registers
+ - UNITY_LINE_TYPE=\"unsigned int\" # Apparently, weâre writing lengthy test files,
+ - UNITY_COUNTER_TYPE=\"unsigned int\" # and we've got a ton of test cases in those test files
+ - UNITY_FLOAT_TYPE=\"double\" # You betcha
+```
+
+#### Example Unity configuration header file
+
+Sometimes, you may want to funnel all Unity configuration options into a
+header file rather than organize a lengthy `:unity` âł `:defines` list. Perhaps your
+symbol definitions include characters needing escape sequences in YAML that are
+driving you bonkers.
+
+```yaml
+:unity:
+ :defines:
+ - UNITY_INCLUDE_CONFIG_H
+```
+
+```c
+// unity_config.h
+#ifndef UNITY_CONFIG_H
+#define UNITY_CONFIG_H
+
+#include "uart_output.h" // Helper library for your custom environment
+
+#define UNITY_INT_WIDTH 16
+#define UNITY_OUTPUT_START() uart_init(F_CPU, BAUD) // Helper function to init UART
+#define UNITY_OUTPUT_CHAR(a) uart_putchar(a) // Helper function to forward char via UART
+#define UNITY_OUTPUT_COMPLETE() uart_complete() // Helper function to inform that test has ended
+
+#endif
+```
+
+### Routing Unityâs report output
+
+Unity defaults to using `putchar()` from C's standard library to
+display test results.
+
+For more exotic environments than a desktop with a terminal â e.g.
+running tests directly on a non-PC target â you have options.
+
+For instance, you could create a routine that transmits a character via
+RS232 or USB. Once you have that routine, you can replace `putchar()`
+calls in Unity by overriding the function-like macro `UNITY_OUTPUT_CHAR`.
+
+Even though this override can also be defined in Ceedling YAML, most
+shell environments do not handle parentheses as command line arguments
+very well. Consult your toolchain and shell documentation.
+
+If redefining the function and macros breaks your command line
+compilation, all necessary options and functionality can be defined in
+`unity_config.h`. Unity will need the `UNITY_INCLUDE_CONFIG_H` symbol in the
+`:unity` âł `:defines` list of your Ceedling project file (see example above).
+
+## CMock Configuration
+
+CMock is enabled in Ceedling by default. However, no part of it enters a
+test build unless mock generation is triggered in your test files.
+Triggering mock generation is done by an `#include` convention. See the
+section on [Ceedling conventions and behaviors][conventions] for more.
+
+You are welcome to disable CMock in the `:project` block of your Ceedling
+configuration file. This is typically only useful in special debugging
+scenarios or for Ceedling development itself.
+
+[conventions]: #important-conventions--behaviors
+
+CMock is a mixture of Ruby and C code. CMock's Ruby components generate
+C code for your unit tests. CMock's base C code is compiled and linked into
+a test executable in the same way that any C file is â including Unity,
+CException, and generated mock C code, for that matter.
+
+CMock's code generation can be configured using YAML similar to Ceedling
+itself. Ceedlingâs project file is something of a container for CMock's
+YAML configuration (Ceedling also uses CMock's configuration, though).
+
+See the documentation for the top-level [`:cmock`][cmock-yaml-config]
+section within Ceedlingâs project file.
+
+[cmock-yaml-config]: #cmock-configure-cmocks-code-generation--compilation
+
+Like Unity and CException, CMock's C components are configured at
+compilation with symbols managed in your Ceedling project file's
+`:cmock` âł `:defines` section.
+
+### Example CMock configurations
+
+```yaml
+:project:
+ # Shown for completeness -- CMock enabled by default in Ceedling
+ :use_mocks: TRUE
+
+:cmock:
+ :when_no_prototypes: :warn
+ :enforce_strict_ordering: TRUE
+ :defines:
+ # Memory alignment (packing) on 16 bit boundaries
+ - CMOCK_MEM_ALIGN=1
+ :plugins:
+ - :ignore
+ :treat_as:
+ uint8: HEX8
+ uint16: HEX16
+ uint32: UINT32
+ int8: INT8
+ bool: UINT8
+```
+
+## CException Configuration
+
+Like Unity, CException is wholly compiled C code. As such, its
+configuration is entirely controlled by a variety of `#define` symbols.
+These can be configured in Ceedlingâs `:cexception` âł `:defines` project
+settings.
+
+Unlike Unity which is always available in test builds and CMock that
+defaults to available in test builds, CException must be enabled
+if you wish to use it in your project.
+
+### Example CException configurations
+
+```yaml
+:project:
+ # Enable CException for both test and release builds
+ :use_exceptions: TRUE
+
+:cexception:
+ :defines:
+ # Possible exception codes of -127 to +127
+ - CEXCEPTION_T='signed char'
+
+```
+
+
+
+# How to Load a Project Configuration. You Have Options, My Friend.
+
+Ceedling needs a project configuration to accomplish anything for you.
+Ceedling's project configuration is a large in-memory data structure.
+That data structure is loaded from a human-readable file format called
+YAML.
+
+The next section details Ceedlingâs project configuration options in
+YAML. This section explains all your options for loading and modifying
+project configuration.
+
+## Overview of Project Configuration Loading & Smooshing
+
+Ceedling has a certain pipeline for loading and manipulating the
+configuration it uses to build your projects. It goes something like
+this:
+
+1. Load the base project configuration from a YAML file.
+1. Merge the base configuration with zero or more Mixins from YAML files.
+1. Load zero or more plugins that provide default configuration values
+ or alter the base project configuration.
+1. Populate the configuration with default values if anything was left
+ unset to ensure all configuration needed to run is present.
+
+Ceedling provides reasonably verbose logging at startup telling you which
+configuration files were used and in what order they were merged.
+
+For nitty-gritty details on plugin configuration behavior, see the
+_[Plugin Development Guide](PluginDevelopmentGuide.md)_
+
+## Options for Loading Your Base Project Configuration
+
+You have three options for telling Ceedling what single base project
+configuration to load. These options are ordered below according to their
+precedence. If an option higher in the list is present, it is used.
+
+1. Command line option flags
+1. Environment variable
+1. Default file in working directory
+
+### `--project` command line flags
+
+Many of Ceedling's [application commands][packet-section-7] include an
+optional `--project` flag. When provided, Ceedling will load as its base
+configuration the YAML filepath provided.
+
+Example: `ceedling --project=my/path/build.yml test:all`
+
+_NOTE:_ Ceedling loads any relative paths within your configuration in
+relation to your working directory. This can cause a disconnect between
+configuration paths, working directory, and the path to your project
+file.
+
+If the filepath does not exist, Ceedling terminates with an error.
+
+### Environment variable `CEEDLING_PROJECT_FILE`
+
+If a `--project` flag is not used at the command line, but the
+environment variable `CEEDLING_PROJECT_FILE` is set, Ceedling will use
+the path it contains to load your project configuration. The path can
+be absolute or relative (to your working directory).
+
+If the filepath does not exist, Ceedling terminates with an error.
+
+### Default _project.yml_ in your working directory
+
+If neither a `--project` command line flag nor the environment variable
+`CEEDLING_PROJECT_FILE` are set, then Ceedling tries to load a file
+named _project.yml_ in your working directory.
+
+If this file does not exist, Ceedling terminates with an error.
+
+## Applying Mixins to Your Base Project Configuration
+
+Once you have a base configuation loaded, you may want to modify it for
+any number of reasons. Some example scenarios:
+
+* A single project actually contains mutiple build variations. You would
+ like to maintain a common configuration that is shared among build
+ variations.
+* Your repository contains the configuration needed by your Continuous
+ Integration server setup, but this is not fun to run locally. You would
+ like to modify the configuration locally with sources external to your
+ repository.
+* Ceedling's default `gcc` tools do not work for your project needs. You
+ would like the complex tooling configurations you most often need to
+ be maintained separately and shared among projects.
+
+Mixins allow you to merge configuration with your project configuration
+just after the base project file is loaded. The merge is so low-level
+and generic that you can, in fact, load an empty base configuration
+and merge in entire project configurations through mixins.
+
+## Mixins Example Plus Merging Rules
+
+Letâs start with an example that also explains how mixins are merged.
+Then, the documentation sections that follow will discuss everything
+in detail.
+
+### Mixins Example: Scenario
+
+In this example, we will load a base project configuration and then
+apply three mixins using each of the available means â command line,
+envionment variable, and `:mixins` section in the base project
+configuration file.
+
+#### Example environment variable
+
+`CEEDLING_MIXIN_1` = `./env.yml`
+
+#### Example command line
+
+`ceedling --project=base.yml --mixin=support/mixins/cmdline.yml `
+
+_NOTE:_ The `--mixin` flag supports more than filepaths and can be used
+multiple times in the same command line for multiple mixins (see later
+documentation section).
+
+The example command line above will produce the following logging output.
+
+```
+đ± Loaded project configuration from command line argument using base.yml
+ + Merged command line mixin using support/mixins/cmdline.yml
+ + Merged CEEDLING_MIXIN_1 mixin using ./env.yml
+ + Merged project configuration mixin using ./enabled.yml
+```
+
+_Notes_
+
+* The logging output above referencing _enabled.yml_ comes from the
+ `:mixins` section within the base project configuration file provided below.
+* The resulting configuration in this example is missing settings required
+ by Ceedling. This will cause a validation build error that is not shown
+ here.
+
+### Mixins Example: Configuration files
+
+#### _base.yml_ â Our base project configuration file
+
+Our base project configuration file:
+
+1. Sets up a configuration file-baesd mixin. Ceedling will look for a mixin
+ named _enabled_ in the specified load paths. In this simple configuration
+ that means Ceedling looks for and merges _support/mixins/enabled.yml_.
+1. Creates a `:project` section in our configuration.
+1. Creates a `:plugins` section in our configuration and enables the standard
+ console test report output plugin.
+
+```yaml
+:mixins: # `:mixins` section only recognized in base project configuration
+ :enabled: # `:enabled` list supports names and filepaths
+ - enabled # Ceedling looks for name as enabled.yml in load paths and merges if found
+ :load_paths:
+ - support/mixins
+
+:project:
+ :build_root: build/
+
+:plugins:
+ :enabled:
+ - report_tests_pretty_stdout
+```
+
+#### _support/mixins/cmdline.yml_ â Mixin via command line filepath flag
+
+This mixin will merge a `:project` section with the existing `:project`
+section from the base project file per the deep merge rules (noted after
+the examples).
+
+```yaml
+:project:
+ :use_test_preprocessor: :all
+ :test_file_prefix: Test
+```
+
+#### _env.yml_ â Mixin via environment variable filepath
+
+This mixin will merge a `:plugins` section with the existing `:plugins`
+section from the base project file per the deep merge rules (noted
+after the examples).
+
+```yaml
+:plugins:
+ :enabled:
+ - compile_commands_json_db
+```
+
+#### _support/mixins/enabled.yml_ â Mixin via base project configuration file `:mixins` section
+
+This mixin listed in the base configuration project file will merge
+`:project` and `:plugins` sections with those that already exist from
+the base configuration plus earlier mixin merges per the deep merge
+rules (noted after the examples).
+
+```yaml
+:project:
+ :use_test_preprocessor: :none
+
+:plugins:
+ :enabled:
+ - gcov
+```
+
+### Mixins Example: Resulting project configuration
+
+Behold the project configuration following mixin merges:
+
+```yaml
+:project:
+ :build_root: build/ # From base.yml
+ :use_test_preprocessor: :all # Value in support/mixins/cmdline.yml overwrote value from support/mixins/enabled.yml
+ :test_file_prefix: Test # Added to :project from support/mixins/cmdline.yml
+
+:plugins:
+ :enabled: # :plugins âł :enabled from two mixins merged with oringal list in base.yml
+ - report_tests_pretty_stdout # From base.yml
+ - compile_commands_json_db # From env.yml
+ - gcov # From support/mixins/enabled.yml
+
+# NOTE: Original :mixins section is filtered out of resulting config
+```
+
+### Mixins deep merge rules
+
+Mixins are merged in a specific order. See the next documentation
+sections for details.
+
+Smooshing of mixin configurations into the base project configuration
+follows a few basic rules:
+
+* If a configuration key/value pair does not already exist at the time
+ of merging, it is added to the configuration.
+* If a simple value â e.g. boolean, string, numeric â already exists
+ at the time of merging, that value is replaced by the value being
+ merged in.
+* If a container â e.g. list or hash â already exists at the time of a
+ merge, the contents are _combined_. In the case of lists, merged
+ values are added to the end of the existing list.
+
+_**Note:**_ That last bullet can have a significant impact on how your
+various project configuration pathsâincluding those used for header
+search pathsâare ordered. In brief, the contents of your `:paths`
+from your base configuration will come first followed by any additions
+from your mixins. See the section [Search Paths for Test Builds][test-search-paths]
+for more.
+
+[test-search-paths]: #search-paths-for-test-builds
+
+## Options for Loading Mixins
+
+You have three options for telling Ceedling what mixins to load. These
+options are ordered below according to their precedence. A Mixin higher
+in the list is merged earlier. In addition, options higher in the list
+force duplicate mixin filepaths to be ignored lower in the list.
+
+Unlike base project file loading that resolves to a single filepath,
+multiple mixins can be specified using any or all of these options.
+
+1. Command line option flags
+1. Environment variables
+1. Base project configuration file entries
+
+### `--mixin` command line flags
+
+As already discussed above, many of Ceedling's application commands
+include an optional `--project` flag. Most of these same commands
+also recognize optional `--mixin` flags. Note that `--mixin` can be
+used multiple times in a single command line.
+
+When provided, Ceedling will load the specified YAML file and merge
+it with the base project configuration.
+
+A Mixin flag can contain one of two types of values:
+
+1. A filename or filepath to a mixin yaml file. A filename contains
+ a file extension. A filepath includes a leading directory path.
+1. A simple name (no file extension and no path). This name is used
+ as a lookup in Ceedling's mixin load paths.
+
+Example: `ceedling --project=build.yml --mixin=foo --mixin=bar/mixin.yaml test:all`
+
+Simple mixin names (#2 above) require mixin load paths to search.
+A default mixin load path is always in the list and points to within
+Ceedling itself (in order to host eventual built-in mixins like
+built-in plugins). User-specified load paths must be added through
+the `:mixins` section of the base configuration project file. See
+the [documentation for the `:mixins` section of your project
+configuration][mixins-config-section] for more details.
+
+Order of precedence is set by the command line mixin order
+left-to-right.
+
+Filepaths may be relative (in relation to the working directory) or
+absolute.
+
+If the `--mixin` filename or filepath does not exist, Ceedling
+terminates with an error. If Ceedling cannot find a mixin name in
+any load paths, it terminates with an error.
+
+[mixins-config-section]: #base-project-configuration-file-mixins-section-entries
+
+### Mixin environment variables
+
+Mixins can also be loaded through environment variables. Ceedling
+recognizes environment variables with a naming scheme of
+`CEEDLING_MIXIN_#`, where `#` is any number greater than 0.
+
+Precedence among the environment variables is a simple ascending
+sort of the trailing numeric value in the environment variable name.
+For example, `CEEDLING_MIXIN_5` will be merged before
+`CEEDLING_MIXIN_99`.
+
+Mixin environment variables only hold filepaths. Filepaths may be
+relative (in relation to the working directory) or absolute.
+
+If the filepath specified by an environment variable does not exist,
+Ceedling terminates with an error.
+
+### Base project configuration file `:mixins` section entries
+
+Ceedling only recognizes a `:mixins` section in your base project
+configuration file. A `:mixins` section in a mixin is ignored. In addition,
+the `:mixins` section of a base project configuration file is filtered
+out of the resulting configuration.
+
+The `:mixins` configuration section can contain up to two subsections.
+Each subsection is optional.
+
+* `:enabled`
+
+ An optional array comprising (A) mixin filenames/filepaths and/or
+ (B) simple mixin names.
+
+ 1. A filename contains a file extension. A filepath includes a
+ directory path. The file content is YAML.
+ 1. A simple name (no file extension and no path) is used
+ as a file lookup among any configured load paths (see next
+ section) and as a lookup name among Ceedlingâs built-in mixins
+ (currently none).
+
+ Enabled entries support [inline Ruby string expansion][inline-ruby-string-expansion].
+
+ **Default**: `[]`
+
+* `:load_paths`
+
+ Paths containing mixin files to be searched via mixin names. A mixin
+ filename in a load path has the form _.yml_ by default. If
+ an alternate filename extension has been specified in your project
+ configuration (`:extension` âł `:yaml`) it will be used for file
+ lookups in the mixin load paths instead of _.yml_.
+
+ Searches start in the path at the top of the list.
+
+ Both mixin names in the `:enabled` list (above) and on the command
+ line via `--mixin` flag use this list of load paths for searches.
+
+ Load paths entries support [inline Ruby string expansion][inline-ruby-string-expansion].
+
+ **Default**: `[]`
+
+Example `:mixins` YAML blurb:
+
+```yaml
+:mixins:
+ :enabled:
+ - foo # Search for foo.yml in proj/mixins & support/ and 'foo' among built-in mixins
+ - path/bar.yaml # Merge this file with base project conig
+ :load_paths:
+ - proj/mixins
+ - support
+```
+
+Relating the above example to command line `--mixin` flag handling:
+
+* A command line flag of `--mixin=foo` is equivalent to the `foo`
+ entry in the `:enabled` mixin configuration.
+* A command line flag of `--mixin=path/bar.yaml` is equivalent to the
+ `path/bar.yaml` entry in the `:enabled` mixin configuration.
+* Note that while command line `--mixin` flags work identically to
+ entries in `:mixins` âł `:enabled`, they are merged first instead of
+ last in the mixin precedence.
+
+
+
+# The Almighty Ceedling Project Configuration File (in Glorious YAML)
+
+See this [commented project file][example-config-file] for a nice
+example of a complete project configuration.
+
+## Some YAML Learninâ
+
+Please consult YAML documentation for the finer points of format
+and to understand details of our YAML-based configuration file.
+
+We recommend [Wikipedia's entry on YAML](http://en.wikipedia.org/wiki/Yaml)
+for this. A few highlights from that reference page:
+
+* YAML streams are encoded using the set of printable Unicode
+ characters, either in UTF-8 or UTF-16.
+
+* White space indentation is used to denote structure; however,
+ tab characters are never allowed as indentation.
+
+* Comments begin with the number sign (`#`), can start anywhere
+ on a line, and continue until the end of the line unless enclosed
+ by quotes.
+
+* List members are denoted by a leading hyphen (`-`) with one member
+ per line, or enclosed in square brackets (`[...]`) and separated
+ by comma space (`, `).
+
+* Hashes are represented using colon space (`: `) in the form
+ `key: value`, either one per line or enclosed in curly braces
+ (`{...}`) and separated by comma space (`, `).
+
+* Strings (scalars) are ordinarily unquoted, but may be enclosed
+ in double-quotes (`"`), or single-quotes (`'`).
+
+* YAML requires that colons and commas used as list separators
+ be followed by a space so that scalar values containing embedded
+ punctuation can generally be represented without needing
+ to be enclosed in quotes.
+
+* Repeated nodes are initially denoted by an ampersand (`&`) and
+ thereafter referenced with an asterisk (`*`). These are known as
+ anchors and aliases in YAML speak.
+
+## Notes on Project File Structure and Documentation That Follows
+
+* Each of the following sections represent top-level entries
+ in the YAML configuration file. Top-level means the named entries
+ are furthest to the left in the hierarchical configuration file
+ (not at the literal top of the file).
+
+* Unless explicitly specified in the configuration file by you,
+ Ceedling uses default values for settings.
+
+* At minimum, these settings must be specified for a test suite:
+ * `:project` âł `:build_root`
+ * `:paths` âł `:source`
+ * `:paths` âł `:test`
+ * `:paths` âł `:include` and/or use of `TEST_INCLUDE_PATH(...)`
+ build directive macro within your test files
+
+* At minimum, these settings must be specified for a release build:
+ * `:project` âł `:build_root`
+ * `:paths` âł `:source`
+
+* As much as is possible, Ceedling validates your settings in
+ properly formed YAML.
+
+* Improperly formed YAML will cause a Ruby error when the YAML
+ is parsed. This is usually accompanied by a complaint with
+ line and column number pointing into the project file.
+
+* Certain advanced features rely on `gcc` and `cpp` as preprocessing
+ tools. In most Linux systems, these tools are already available.
+ For Windows environments, we recommend the [MinGW] project
+ (Minimalist GNU for Windows).
+
+* Ceedling is primarily meant as a build tool to support automated
+ unit testing. All the heavy lifting is involved there. Creating
+ a simple binary release build artifact is quite trivial in
+ comparison. Consequently, most default options and the construction
+ of Ceedling itself is skewed towards supporting testing, though
Ceedling can, of course, build your binary release artifact
- as well. Note that complex binary release artifacts (e.g.
- application + bootloader or multiple libraries) are beyond
- Ceedling's release build ability.
-
-Conventions / features of Ceedling-specific YAML:
-
-* Any second tier setting keys anywhere in YAML whose names end
- in `_path` or `_paths` are automagically processed like all
- Ceedling-specific paths in the YAML to have consistent directory
- separators (i.e. "/") and to take advantage of inline Ruby
- string expansion (see [:environment] setting below for further
- explanation of string expansion).
-
-**Let's Be Careful Out There:** Ceedling performs validation
-on the values you set in your configuration file (this assumes
-your YAML is correct and will not fail format parsing, of course).
+ as well. Note that some complex binary release builds are beyond
+ Ceedlingâs abilities. See the Ceedling plugin [subprojects] for
+ extending release build abilities.
+
+[MinGW]: http://www.mingw.org/
+
+## Ceedling-specific YAML Handling & Conventions
+
+### Inline Ruby string expansion
+
+Ceedling is able to execute inline Ruby string substitution code within the
+entries of certain project file configuration elements.
+
+In some cases, this evaluation may occurs when elements of the project
+configuration are loaded and processed into a data structure for use by the
+Ceedling application (e.g. path handling). In other cases, this evaluation
+occurs each time a project configuration element is referenced (e.g. tools).
+
+_Notes:_
+* One good option for validating and troubleshooting inline Ruby string
+ exapnsion is use of `ceedling dumpconfig` at the command line. This application
+ command causes your project configuration to be processed and written to a
+ YAML file with any inline Ruby string expansions, well, expanded along with
+ defaults set, plugin actions applied, etc.
+* A commonly needed expansion is that of referencing an environment variable.
+ Inline Ruby string expansion supports this. See the example below.
+
+#### Ruby string expansion syntax
+
+To exapnd the string result of Ruby code within a configuration value string,
+wrap the Ruby code in the substitution pattern `#{âŠ}`.
+
+Inline Ruby string expansion may constitute the entirety of a configuration
+value string, may be embedded within a string, or may be used multiple times
+within a string.
+
+Because of the `#` itâs a good idea to wrap any string values in your YAML that
+rely on this feature with quotation marks. Quotation marks for YAML strings are
+optional. However, the `#` can cause a YAML parser to see a comment. As such,
+explicitly indicating a string to the YAML parser with enclosing quotation
+marks alleviates this problem.
+
+#### Ruby string expansion example
+
+```yaml
+:some_config_section:
+ :some_key:
+ - "My env string #{ENV['VAR1']}"
+ - "My utility result string #{`util --arg`.strip()}"
+```
+
+In the example above, the two YAML strings will include the strings returned by
+the Ruby code within `#{âŠ}`:
+
+1. The first string uses Rubyâs environment variable lookup `ENV[âŠ]` to fetch
+the value assigned to variable `VAR1`.
+1. The second string uses Rubyâs backtick shell execution ``âŠ`` to insert the
+string generated by a command line utility.
+
+#### Project file sections that offer inline Ruby string expansion
+
+* `:mixins`
+* `:environment`
+* `:paths` plus any second tier configuration key name ending in `_path` or
+ `_paths`
+* `:flags`
+* `:defines`
+* `:tools`
+* `:release_build` âł `:artifacts`
+
+See each sectionâs documentation for details.
+
+[inline-ruby-string-expansion]: #inline-ruby-string-expansion
+
+### Path handling
+
+Any second tier setting keys anywhere in YAML whose names end in `_path` or
+`_paths` are automagically processed like all Ceedling-specific paths in the
+YAML to have consistent directory separators (i.e. `/`) and to take advantage
+of inline Ruby string expansion (see preceding section for details).
+
+## Letâs Be Careful Out There
+
+Ceedling performs validation of the values you set in your
+configuration file (this assumes your YAML is correct and will
+not fail format parsing, of course).
+
That said, validation is limited to only those settings Ceedling
uses and those that can be reasonably validated. Ceedling does
not limit what can exist within your configuration file. In this
way, you can take full advantage of YAML as well as add sections
and values for use in your own custom plugins (documented later).
+
The consequence of this is simple but important. A misspelled
-configuration section name or value name is unlikely to cause
-Ceedling any trouble. Ceedling will happily process that section
+configuration section or value name is unlikely to cause Ceedling
+any trouble. Ceedling will happily process that section
or value and simply use the properly spelled default maintained
-internally - thus leading to unexpected behavior without warning.
+internally â thus leading to unexpected behavior without warning.
+
+## `:project`: Global project settings
+
+**_NOTE:_** In future versions of Ceedling, test-specific and release-specific
+build settings presently organized beneath `:project` will likely be renamed
+and migrated to the `:test_build` and `:release_build` sections.
+
+* `:build_root`
+
+ Top level directory into which generated path structure and files are
+ placed. NOTE: this is one of the handful of configuration values that
+ must be set. The specified path can be absolute or relative to your
+ working directory.
+
+ **Default**: (none)
+
+* `:default_tasks`
+
+ A list of default build / plugin tasks Ceedling should execute if
+ none are provided at the command line.
+
+ _NOTE:_ These are build & plugin tasks (e.g. `test:all` and `clobber`).
+ These are not application commands (e.g. `dumpconfig`) or command
+ line flags (e.g. `--verbosity`). See the documentation
+ [on using the command line][command-line] to understand the distinction
+ between application commands and build & plugin tasks.
+
+ Example YAML:
+ ```yaml
+ :project:
+ :default_tasks:
+ - clobber
+ - test:all
+ - release
+ ```
+ **Default**: `['test:all']`
+
+ [command-line]: #now-what-how-do-i-make-it-go-the-command-line
+
+* `:use_mocks`
+
+ Configures the build environment to make use of CMock. Note that if
+ you do not use mocks, there's no harm in leaving this setting as its
+ default value.
+
+ **Default**: TRUE
+
+* `:use_test_preprocessor`
+
+ This option allows Ceedling to work with test files that contain
+ tricky conditional compilation statements (e.g. `#ifdef`) as well as mockable
+ header files containing conditional preprocessor directives and/or macros.
+
+ See the [documentation on test preprocessing][test-preprocessing] for more.
+
+ With any preprocessing enabled, the `gcc` & `cpp` tools must exist in an
+ accessible system search path.
+
+ * `:none` disables preprocessing.
+ * `:all` enables preprpocessing for all mockable header files and test C files.
+ * `:mocks` enables only preprocessing of header files that are to be mocked.
+ * `:tests` enables only preprocessing of your test files.
+
+ [test-preprocessing]: #preprocessing-behavior-for-tests
+
+ **Default**: `:none`
+
+* `:test_file_prefix`
+
+ Ceedling collects test files by convention from within the test file
+ search paths. The convention includes a unique name prefix and a file
+ extension matching that of source files.
+
+ Why not simply recognize all files in test directories as test files?
+ By using the given convention, we have greater flexibility in what we
+ do with C files in the test directories.
+
+ **Default**: "test_"
+
+* `:release_build`
+
+ When enabled, a release Rake task is exposed. This configuration
+ option requires a corresponding release compiler and linker to be
+ defined (`gcc` is used as the default).
+
+ Ceedling is primarily concerned with facilitating the complicated
+ mechanics of automating unit tests. The same mechanisms are easily
+ capable of building a final release binary artifact (i.e. non test
+ code â the thing that is your final working software that you execute
+ on target hardware). That said, if you have complicated release
+ builds, you should consider a traditional build tool for these.
+ Ceedling shines at executing test suites.
+
+ More release configuration options are available in the `:release_build`
+ section.
+
+ **Default**: FALSE
+
+* `:compile_threads`
+
+ A value greater than one enables parallelized build steps. Ceedling
+ creates a number of threads up to `:compile_threads` for build steps.
+ These build steps execute batched operations including but not
+ limited to mock generation, code compilation, and running test
+ executables.
+
+ Particularly if your build system includes multiple cores, overall
+ build time will drop considerably as compared to running a build with
+ a single thread.
+
+ Tuning the number of threads for peak performance is an art more
+ than a science. A special value of `:auto` instructs Ceedling to
+ query the host system's number of virtual cores. To this value it
+ adds a constant of 4. This is often a good value sufficient to "max
+ out" available resources without overloading available resources.
+
+ `:compile_threads` is used for all release build steps and all test
+ suite build steps except for running the test executables that make
+ up a test suite. See next section for more.
+
+ **Default**: 1
+
+* `:test_threads`
+
+ The behavior of and values for `:test_threads` are identical to
+ `:compile_threads` with one exception.
+
+ `test_threads:` specifically controls the number of threads used to
+ run the test executables comprising a test suite.
+
+ Why the distinction from `:compile_threads`? Some test suite builds
+ rely not on native executables but simulators running cross-compiled
+ code. Some simulators are limited to running only a single instance at
+ a time. Thus, with this and the previous setting, it becomes possible
+ to parallelize nearly all of a test suite build while still respecting
+ the limits of certain simulators depended upon by test executables.
+
+ **Default**: 1
+
+* `:which_ceedling`
+
+ This is an advanced project option primarily meant for development work
+ on Ceedling itself. This setting tells the code that launches the
+ Ceedling application where to find the code to launch.
+
+ This entry can be either a directory path or `gem`.
+
+ See the section [Which Ceedling](#which_ceedling) for full details.
+
+ **Default**: `gem`
+
+* `:use_backtrace`
+
+ When a test executable encounters a â ïž **Segmentation Fault** or other crash
+ condition, the executable immediately terminates and no further details for
+ test suite reporting are collected.
+
+ But, fear not. You can bring your dead unit tests back to life.
+
+ By default, in the case of a crash, Ceedling reruns the test executable for
+ each test case using a special mode to isolate that test case. In this way
+ Ceedling can iteratively identify which test cases are causing the crash or
+ exercising release code that is causing the crash. Ceedling then assembles
+ the final test reporting results from these individual test case runs.
+
+ You have three options for this setting, `:none`, `:simple` or `:gdb`:
+
+ 1. `:none` will simply cause a test report to list each test case as failed
+ due to a test executable crash.
+
+ Sample Ceedling run output with backtrace `:none`:
+
+ ```
+ đ Executing
+ ------------
+ Running TestUsartModel.out...
+ â ïž ERROR: Test executable `TestUsartModel.out` seems to have crashed
+
+ -------------------
+ FAILED TEST SUMMARY
+ -------------------
+ [test/TestUsartModel.c]
+ Test: testGetBaudRateRegisterSettingShouldReturnAppropriateBaudRateRegisterSetting
+ At line (24): "Test executable crashed"
+
+ Test: testCrash
+ At line (37): "Test executable crashed"
+
+ Test: testGetFormattedTemperatureFormatsTemperatureFromCalculatorAppropriately
+ At line (44): "Test executable crashed"
+
+ Test: testShouldReturnErrorMessageUponInvalidTemperatureValue
+ At line (50): "Test executable crashed"
+
+ Test: testShouldReturnWakeupMessage
+ At line (56): "Test executable crashed"
+
+ -----------------------
+ â OVERALL TEST SUMMARY
+ -----------------------
+ TESTED: 5
+ PASSED: 0
+ FAILED: 5
+ IGNORED: 0
+ ```
+
+ 1. `:simple` causes Ceedling to re-run each test case in the
+ test executable individually to identify and report the problematic
+ test case(s). This is the default option and is described above.
+
+ Sample Ceedling run output with backtrace `:simple`:
+
+ ```
+ đ Executing
+ ------------
+ Running TestUsartModel.out...
+ â ïž ERROR: Test executable `TestUsartModel.out` seems to have crashed
+
+ -------------------
+ FAILED TEST SUMMARY
+ -------------------
+ [test/TestUsartModel.c]
+ Test: testCrash
+ At line (37): "Test case crashed"
+
+ -----------------------
+ â OVERALL TEST SUMMARY
+ -----------------------
+ TESTED: 5
+ PASSED: 4
+ FAILED: 1
+ IGNORED: 0
+ ```
+
+ 1. `:gdb` uses the [`gdb`][gdb] debugger to identify and report the
+ troublesome line of code triggering the crash. If this option is enabled,
+ but `gdb` is not available to Ceedling, project configuration validation
+ will terminate with an error at startup.
+
+ Sample Ceedling run output with backtrace `:gdb`:
+
+ ```
+ đ Executing
+ ------------
+ Running TestUsartModel.out...
+ â ïž ERROR: Test executable `TestUsartModel.out` seems to have crashed
+
+ -------------------
+ FAILED TEST SUMMARY
+ -------------------
+ [test/TestUsartModel.c]
+ Test: testCrash
+ At line (40): "Test case crashed >> Program received signal SIGSEGV, Segmentation fault.
+ 0x00005618066ea1fb in testCrash () at test/TestUsartModel.c:40
+ 40 uint32_t i = *nullptr;"
+
+ -----------------------
+ â OVERALL TEST SUMMARY
+ -----------------------
+ TESTED: 5
+ PASSED: 4
+ FAILED: 1
+ IGNORED: 0
+ ```
+
+ **_Notes:_**
+
+ 1. The default of `:simple` only works in an environment capable of
+ using command line arguments (passed to the test executable). If you are
+ targeting a simulator with your test executable binaries, `:simple` is
+ unlikely to work for you. In the simplest case, you may simply fall back
+ to `:none`. With some work and using Ceedlingâs various features, much
+ more sophisticated options are possible.
+ 1. The `:gdb` option currently only supports the native build platform.
+ That is, the `:gdb` backtrace option cannot handle backtrace for
+ cross-compiled code or any sort of simulator-based test fixture.
+
+ **Default**: `:simple`
+
+ [gdb]: https://www.sourceware.org/gdb/
+
+### Example `:project` YAML blurb
+
+```yaml
+:project:
+ :build_root: project_awesome/build
+ :use_exceptions: FALSE
+ :use_test_preprocessor: :all
+ :options_paths:
+ - project/options
+ - external/shared/options
+ :release_build: TRUE
+ :compile_threads: :auto
+```
+
+## `:mixins` Configuring mixins to merge
+
+This section of a project configuration file is documented in the
+[discussion of project files and mixins][mixins-config-section].
+
+**_Notes:_**
+
+* A `:mixins` section is only recognized within a base project configuration
+ file. Any `:mixins` sections within mixin files are ignored.
+* A `:mixins` section in a Ceedling configuration is entirely filtered out of
+ the resulting configuration. That is, it is unavailable for use by plugins
+ and will not be present in any output from `ceedling dumpconfig`.
+* A `:mixins` section supports [inline Ruby string expansion][inline-ruby-string-expansion].
+ See the full documetation on Mixins for details.
+
+## `:test_build` Configuring a test build
+
+**_NOTE:_** In future versions of Ceedling, test-related settings presently
+organized beneath `:project` will be renamed and migrated to this section.
+
+* `:use_assembly`
+
+ This option causes Ceedling to enable an assembler tool and collect a
+ list of assembly file sources for use in a test suite build.
+
+ The default assembler is the GNU tool `as`; like all other tools, it
+ may be overridden in the `:tools` section.
+
+ After enabliing this feature, two conditions must be true in order to
+ inject assembly code into the build of a test executable:
+
+ 1. The assembly files must be visible to Ceedling by way of `:paths` and
+ `:extension` settings for assembly files. Here, assembly files would be
+ equivalent to C code files handled in the same ways.
+ 1. Ceedling must be told into which test executable build to insert a
+ given assembly file. The easiest way to do so is with the
+ `TEST_SOURCE_FILE()` build directive macro (documented in a later section).
+
+ **Default**: FALSE
+
+### Example `:test_build` YAML blurb
+
+```yaml
+:test_build:
+ :use_assembly: TRUE
+```
+
+## `:release_build` Configuring a release build
+
+**_NOTE:_** In future versions of Ceedling, release build-related settings
+presently organized beneath `:sproject` will be renamed and migrated to
+this section.
+
+* `:output`
+
+ The name of your release build binary artifact to be found in /artifacts/release. Ceedling sets the default artifact file
+ extension to that as is explicitly specified in the `:extension`
+ section or as is system specific otherwise.
+
+ **Default**: `project.exe` or `project.out`
+
+* `:use_assembly`
+
+ This option causes Ceedling to enable an assembler tool and add any
+ assembly code present in the project to the release artifact's build.
+
+ The default assembler is the GNU tool `as`; it may be overridden
+ in the `:tools` section.
+
+ The assembly files must be visible to Ceedling by way of `:paths` and
+ `:extension` settings for assembly files.
+
+ **Default**: FALSE
+
+* `:artifacts`
+
+ By default, Ceedling copies to the _/artifacts/release_
+ directory the output of the release linker and (optionally) a map
+ file. Many toolchains produce other important output files as well.
+ Adding a file path to this list will cause Ceedling to copy that file
+ to the artifacts directory.
+
+ The artifacts directory is helpful for organizing important build
+ output files and provides a central place for tools such as Continuous
+ Integration servers to point to build output. Selectively copying
+ files prevents incidental build cruft from needlessly appearing in the
+ artifacts directory.
+
+ Note that [inline Ruby string expansion][inline-ruby-string-expansion]
+ is available in artifact paths.
+
+ **Default**: `[]` (empty)
+
+### Example `:release_build` YAML blurb
+
+```yaml
+:release_build:
+ :output: top_secret.bin
+ :use_assembly: TRUE
+ :artifacts:
+ - build/release/out/c/top_secret.s19
+```
+
+## Project `:paths` configuration
+
+**Paths for build tools and building file collections**
+
+Ceedling relies on various path and file collections to do its work. File
+collections are automagically assembled from paths, matching globs / wildcards,
+and file extensions (see project configuration `:extension`).
+
+Entries in `:paths` help create directory-based bulk file collections. The
+`:files` configuration section is available for filepath-oriented tailoring of
+these buk file collections.
+
+Entries in `:paths` âł `:include` also specify search paths for header files.
+
+All of the configuration subsections that follow default to empty lists. In
+YAML, list items can be comma separated within brackets or organized per line
+with a dash. An empty list can only be denoted as `[]`. Typically, you will see
+Ceedling project files use lists broken up per line.
+
+```yaml
+:paths:
+ :support: [] # Empty list (internal default)
+ :source:
+ - files/code # Typical list format
+
+```
+
+Examples that illustrate the many `:paths` entry features follow all
+the various path-related documentation sections.
+
+_**Note:**_ If you use Mixins to build up path lists in your project
+configuration, the merge order of those Mixins will dictate the ordering of
+your path lists. Particularly given that the search path list built with
+`:paths` âł `:include` you will want to pay attention to ordering issues
+involved in specifying path lists in Mixins.
+
+* :paths
âł :test
+
+ All C files containing unit test code. NOTE: this is one of the
+ handful of configuration values that must be set for a test suite.
+
+ **Default**: `[]` (empty)
+
+* :paths
âł :source
+
+ All C files containing release code (code to be tested)
+
+ NOTE: this is one of the handful of configuration values that must
+ be set for either a release build or test suite.
+
+ **Default**: `[]` (empty)
+
+* :paths
âł :support
+
+ Any C files you might need to aid your unit testing. For example, on
+ occasion, you may need to create a header file containing a subset of
+ function signatures matching those elsewhere in your code (e.g. a
+ subset of your OS functions, a portion of a library API, etc.). Why?
+ To provide finer grained control over mock function substitution or
+ limiting the size of the generated mocks.
+
+ **Default**: `[]` (empty)
+
+* :paths
âł :include
+
+ See these two important discussions to fully understand your options
+ for header file search paths:
+
+ * [Configuring Your Header File Search Paths][header-file-search-paths]
+ * [`TEST_INCLUDE_PATH(...)` build directive macro][test-include-path-macro]
+
+ [header-file-search-paths]: #configuring-your-header-file-search-paths
+ [test-include-path-macro]: #test_include_path
+
+ This set of paths specifies the locations of your header files. If
+ your header files are intermixed with source files, you must duplicate
+ some or all of your `:paths` âł `:source` entries here.
+
+ In its simplest use, your include paths list can be exhaustive.
+ That is, you list all path locations where your projectâs header files
+ reside in this configuration list.
+
+ However, if you have a complex project or many, many include paths that
+ create problematically long search paths at the compilation command
+ line, you may treat your `:paths` âł `:include` list as a base, common
+ list. Having established that base list, you can then extend it on a
+ test-by-test basis with use of the `TEST_INCLUDE_PATH(...)` build
+ directive macro in your test files.
+
+ **Default**: `[]` (empty)
+
+* :paths
âł :test_toolchain_include
+
+ System header files needed by the test toolchain - should your
+ compiler be unable to find them, finds the wrong system include search
+ path, or you need a creative solution to a tricky technical problem.
+
+ Note that if you configure your own toolchain in the `:tools` section,
+ this search path is largely meaningless to you. However, this is a
+ convenient way to control the system include path should you rely on
+ the default [GCC] tools.
+
+ **Default**: `[]` (empty)
+
+* :paths
âł :release_toolchain_include
+
+ Same as preceding albeit related to the release toolchain.
+
+ **Default**: `[]` (empty)
+
+* :paths
âł :libraries
+
+ Library search paths. [See `:libraries` section][libraries].
+
+ **Default**: `[]` (empty)
+
+ [libraries]: #libraries
+
+* :paths
âł :<custom>
+
+ Any paths you specify for custom list. List is available to tool
+ configurations and/or plugins. Note a distinction â the preceding names
+ are recognized internally to Ceedling and the path lists are used to
+ build collections of files contained in those paths. A custom list is
+ just that - a custom list of paths.
+
+### `:paths` configuration options & notes
+
+1. A path can be absolute (fully qualified) or relative.
+1. A path can include a glob matcher (more on this below).
+1. A path can use [inline Ruby string expansion][inline-ruby-string-expansion].
+1. Subtractive paths are possible and useful. See the documentation below.
+1. Path order beneath a subsection (e.g. `:paths` âł `:include`) is preserved
+ when the list is iterated internally or passed to a tool.
+
+### `:paths` Globs
+
+Globs are effectively fancy wildcards. They are not as capable as full regular
+expressions but are easier to use. Various OSs and programming languages
+implement them differently.
+
+For a quick overview, see this [tutorial][globs-tutorial].
+
+Ceedling supports globs so you can specify patterns of directories without the
+need to list each and every required path.
+
+Ceedling `:paths` globs operate similarlry to [Ruby globs][ruby-globs] except
+that they are limited to matching directories within `:paths` entries and not
+also files. In addition, Ceedling adds a useful convention with certain uses of
+the `*` and `**` operators.
+
+Glob operators include the following: `*`, `**`, `?`, `[-]`, `{,}`.
+
+* `*`
+ * When used within a character string, `*` is simply a standard wildcard.
+ * When used after a path separator, `/*` matches all subdirectories of depth 1
+ below the parent path, not including the parent path.
+* `**`: All subdirectories recursively discovered below the parent path, not
+ including the parent path. This pattern only makes sense after a path
+ separator `/**`.
+* `?`: Single alphanumeric character wildcard.
+* `[x-y]`: Single alphanumeric character as found in the specified range.
+* `{x, y, ...}`: Matching any of the comma-separated patterns. Two or more
+ patterns may be listed within the brackets. Patterns may be specific
+ character sequences or other glob operators.
+
+Special conventions:
+
+* If a globified path ends with `/*` or `/**`, the resulting list of directories
+ also includes the parent directory.
+
+See the example `:paths` YAML blurb section.
+
+[globs-tutotrial]: http://ruby.about.com/od/beginningruby/a/dir2.htm
+[ruby-globs]: https://ruby-doc.org/core-3.0.0/Dir.html#method-c-glob
+
+### Subtractive `:paths` entries
+
+Globs are super duper helpful when you have many paths to list. But, what if a
+single glob gets you 20 nested paths, but you actually want to exclude 2 of
+those paths?
+
+Must you revert to listing all 18 paths individually? No, my friend, we've got
+you. Behold, subtractive paths.
+
+Put simply, with an optional preceding decorator `-:`, you can instruct Ceedling
+to remove certain directory paths from a collection after it builds that
+collection.
+
+By default, paths are additive. For pretty alignment in your YAML, you may also
+use `+:`, but strictly speaking, it's not necessary.
+
+Subtractive paths may be simple paths or globs just like any other path entry.
+
+See examples below.
+
+_**Note:**_ The resolution of subtractive paths happens after your full paths
+lists are assembled. So, if you use `:paths` entries in Mixins to build up your
+project configuration, subtractive paths will only be processed after the final
+mixin is merged. That is, you can merge in additive and subtractive paths with
+Mixins to your heartâs content. The subtractive paths are not removed until all
+Mixins have been merged.
+
+### Example `:paths` YAML blurbs
+
+_NOTE:_ Ceedling standardizes paths for you. Internally, all paths use forward
+ slash `/` path separators (including on Windows), and Ceedling cleans up
+ trailing path separators to be consistent internally.
+
+#### Simple `:paths` entries
+
+```yaml
+:paths:
+ # All /*. => test/release compilation input
+ :source:
+ - project/src/ # Resulting source list has just two relative directory paths
+ - project/aux # (Traversal goes no deeper than these simple paths)
+
+ # All => compilation search paths + mock search paths
+ :include: # All => compilation input
+ - project/src/inc # Include paths are subdirectory of src/
+ - /usr/local/include/foo # Header files for a prebuilt library at fully qualified path
+
+ # All /*. => test compilation input + test suite executables
+ :test:
+ - ../tests # Tests have parent directory above working directory
+```
+
+#### Common `:paths` globs with subtractive path entries
+
+```yaml
+:paths:
+ :source:
+ - +:project/src/** # Recursive glob yields all subdirectories of any depth plus src/
+ - -:project/src/exp # Exclude experimental code in exp/ from release or test builds
+ # `+:` is decoration for pretty alignment; only `-:` changes a list
+
+ :include:
+ - +:project/src/**/inc # Include every subdirectory inc/ beneath src/
+ - -:project/src/exp/inc # Remove header files subdirectory for experimental code
+```
+
+#### Advanced `:paths` entries with globs and string expansion
+
+```yaml
+:paths:
+ :test:
+ - test/**/f??? # Every 4 character âf-series" subdirectory beneath test/
+
+ :my_things: # Custom path list
+ - "#{PROJECT_ROOT}/other" # Inline Ruby string expansion using Ceedling global constant
+```
+
+```yaml
+:paths:
+ :test:
+ - test/{foo,b*,xyz} # Path list will include test/foo/, test/xyz/, and any subdirectories
+ # beneath test/ beginning with 'b', including just test/b/
+```
+
+Globs and inline Ruby string expansion can require trial and error to arrive at
+your intended results. Ceedling provides as much validation of paths as is
+practical.
+
+Use the `ceedling paths:*` and `ceedling files:*` command line tasks â
+documented in a preceding section â to verify your settings. (Here `*` is
+shorthand for `test`, `source`, `include`, etc. Confusing? Sorry.)
+
+The command line option `ceedling dumpconfig` can also help your troubleshoot
+your configuration file. This application command causes Ceedling to process
+your configuration file and write the result to another YAML file for your
+inspection.
+
+## `:files` Modify file collections
+
+**File listings for tailoring file collections**
+
+Ceedling relies on file collections to do its work. These file collections are
+automagically assembled from paths, matching globs / wildcards, and file
+extensions (see project configuration `:extension`).
+
+Entries in `:files` accomplish filepath-oriented tailoring of the bulk file
+collections created from `:paths` directory listings and filename pattern
+matching.
+
+On occasion you may need to remove from or add individual files to Ceedlingâs
+file collections.
+
+The path grammar documented in the `:paths` configuration section largely
+applies to `:files` path entries - albeit with regard to filepaths and not
+directory paths. The `:files` grammar and YAML examples are documented below.
+
+* :files
âł :test
+
+ Modify the collection of unit test C files.
+
+ **Default**: `[]` (empty)
+
+* :files
âł :source
+
+ Modify the collection of all source files used in unit test builds and release builds.
+
+ **Default**: `[]` (empty)
+
+* :files
âł :assembly
+
+ Modify the (optional) collection of assembly files used in release builds.
+
+ **Default**: `[]` (empty)
+
+* :files
âł :include
+
+ Modify the collection of all source header files used in unit test builds (e.g. for mocking) and release builds.
+
+ **Default**: `[]` (empty)
+
+* :files
âł :support
+
+ Modify the collection of supporting C files available to unit tests builds.
+
+ **Default**: `[]` (empty)
+
+* :files
âł :libraries
+
+ Add a collection of library paths to be included when linking.
+
+ **Default**: `[]` (empty)
+
+### `:files` configuration options & notes
+
+1. A path can be absolute (fully qualified) or relative.
+1. A path can include a glob matcher (more on this below).
+1. A path can use [inline Ruby string expansion][inline-ruby-string-expansion].
+1. Subtractive paths prepended with a `-:` decorator are possible and useful.
+ See the documentation below.
+
+### `:files` Globs
+
+Globs are effectively fancy wildcards. They are not as capable as full regular
+expressions but are easier to use. Various OSs and programming languages
+implement them differently.
+
+For a quick overview, see this [tutorial][globs-tutorial].
+
+Ceedling supports globs so you can specify patterns of files as well as simple,
+ordinary filepaths.
+
+Ceedling `:files` globs operate identically to [Ruby globs][ruby-globs] except
+that they ignore directory paths. Only filepaths are recognized.
+
+Glob operators include the following: `*`, `**`, `?`, `[-]`, `{,}`.
+
+* `*`
+ * When used within a character string, `*` is simply a standard wildcard.
+ * When used after a path separator, `/*` matches all subdirectories of depth
+ 1 below the parent path, not including the parent path.
+* `**`: All subdirectories recursively discovered below the parent path, not
+ including the parent path. This pattern only makes sense after a path
+ separator `/**`.
+* `?`: Single alphanumeric character wildcard.
+* `[x-y]`: Single alphanumeric character as found in the specified range.
+* `{x, y, ...}`: Matching any of the comma-separated patterns. Two or more
+ patterns may be listed within the brackets. Patterns may be specific
+ character sequences or other glob operators.
+
+### Subtractive `:files` entries
+
+Tailoring a file collection includes adding to it but also subtracting from it.
+
+Put simply, with an optional preceding decorator `-:`, you can instruct Ceedling
+to remove certain file paths from a collection after it builds that
+collection.
+
+By default, paths are additive. For pretty alignment in your YAML, you may also
+use `+:`, but strictly speaking, it's not necessary.
+
+Subtractive paths may be simple paths or globs just like any other path entry.
+
+See examples below.
+
+### Example `:files` YAML blurbs
+
+#### Simple `:files` tailoring
+
+```yaml
+:paths:
+ # All /*. => test/release compilation input
+ :source:
+ - src/**
+
+:files:
+ :source:
+ - +:callbacks/serial_comm.c # Add source code outside src/
+ - -:src/board/atm134.c # Remove board code
+```
+
+#### Advanced `:files` tailoring
+
+```yaml
+:paths:
+ # All /*. => test compilation input + test suite executables
+ :test:
+ - test/**
+
+:files:
+ :test:
+ # Remove every test file anywhere beneath test/ whose name ends with 'Model'.
+ # String replacement inserts a global constant that is the file extension for
+ # a C file. This is an anchor for the end of the filename and automaticlly
+ # uses file extension settings.
+ - "-:test/**/*Model#{EXTENSION_SOURCE}"
+
+ # Remove test files at depth 1 beneath test/ with 'analog' anywhere in their names.
+ - -:test/*{A,a}nalog*
+
+ # Remove test files at depth 1 beneath test/ that are of an âF seriesâ
+ # test collection FAxxxx, FBxxxx, and FCxxxx where 'x' is any character.
+ - -:test/F[A-C]????
+```
+
+## `:environment:` Insert environment variables into shells running tools
+
+Ceedling creates environment variables from any key / value pairs in the
+environment section. Keys become an environment variable name in uppercase. The
+values are strings assigned to those environment variables. These value strings
+are either simple string values in YAML or the concatenation of a YAML array
+of strings.
+
+`:environment` is a list of single key / value pair entries processed in the
+configured list order.
+
+`:environment` variable value strings can include
+[inline Ruby string expansion][inline-ruby-string-expansion]. Thus, later
+entries can reference earlier entries.
+
+### Special case: `PATH` handling
+
+In the specific case of specifying an environment key named `:path`, an array
+of string values will be concatenated with the appropriate platform-specific
+path separation character (i.e. `:` on Unix-variants, `;` on Windows).
+
+All other instances of environment keys assigned a value of a YAML array use
+simple concatenation.
+
+### Example `:environment` YAML blurb
+
+Note that `:environment` is a list of key / value pairs. Only one key per entry
+is allowed, and that key must be a `:`__.
+
+```yaml
+:environment:
+ - :license_server: gizmo.intranet # LICENSE_SERVER set with value "gizmo.intranet"
+ - :license: "#{`license.exe`}" # LICENSE set to string generated from shelling out to
+ # execute license.exe; note use of enclosing quotes to
+ # prevent a YAML comment.
+
+ - :logfile: system/logs/thingamabob.log # LOGFILE set with path for a log file
+
+ - :path: # Concatenated with path separator (see special case above)
+ - Tools/gizmo/bin # Prepend existing PATH with gizmo path
+ - "#{ENV['PATH']}" # Pattern #{âŠ} triggers ruby evaluation string expansion
+ # NOTE: value string must be quoted because of '#' to
+ # prevent a YAML comment.
+```
+
+## `:extension` Filename extensions used to collect lists of files searched in `:paths`
+
+Ceedling uses path lists and wildcard matching against filename extensions to collect file lists.
+
+* `:header`:
+
+ C header files
-project: global project settings
+ **Default**: .h
-* `build_root`:
+* `:source`:
- Top level directory into which generated path structure and files are
- placed. Note: this is one of the handful of configuration values that
- must be set. The specified path can be absolute or relative to your
- working directory.
+ C code files (whether source or test files)
- **Default**: (none)
+ **Default**: .c
-* `use_exceptions`:
+* `:assembly`:
- Configures the build environment to make use of CException. Note that
- if you do not use exceptions, there's no harm in leaving this as its
- default value.
+ Assembly files (contents wholly assembler instructions)
- **Default**: TRUE
+ **Default**: .s
-* `use_mocks`:
+* `:object`:
- Configures the build environment to make use of CMock. Note that if
- you do not use mocks, there's no harm in leaving this setting as its
- default value.
+ Resulting binary output of C code compiler (and assembler)
- **Default**: TRUE
+ **Default**: .o
-* `use_test_preprocessor`:
+* `:executable`:
- This option allows Ceedling to work with test files that contain
- conditional compilation statements (e.g. #ifdef) and header files you
- wish to mock that contain conditional preprocessor statements and/or
- macros.
+ Binary executable to be loaded and executed upon target hardware
- Ceedling and CMock are advanced tools with sophisticated parsers.
- However, they do not include entire C language preprocessors.
- Consequently, with this option enabled, Ceedling will use gcc's
- preprocessing mode and the cpp preprocessor tool to strip down /
- expand test files and headers to their applicable content which can
- then be processed by Ceedling and CMock.
+ **Default**: .exe or .out (Win or Linux)
- With this option enabled, the gcc & cpp tools must exist in an
- accessible system search path and test runner files are always
- regenerated.
+* `:testpass`:
- **Default**: FALSE
+ Test results file (not likely to ever need a redefined value)
-* `use_preprocessor_directives`:
+ **Default**: .pass
- After standard preprocessing when `use_test_preprocessor` is used
- macros are fully expanded to C code. Some features, for example
- TEST_CASE() or TEST_RANGE() from Unity require not-fully preprocessed
- file to be detected by Ceedling. To do this gcc directives-only
- option is used to expand only conditional compilation statements,
- handle directives, but do not expand macros preprocessor and leave
- the other content of file untouched.
+* `:testfail`:
- With this option enabled, `use_test_preprocessor` must be also enabled
- and gcc must exist in an accessible system search path. For other
- compilers behavior can be changed by `test_file_preprocessor_directives`
- compiler tool.
+ Test results file (not likely to ever need a redefined value)
- **Default**: FALSE
+ **Default**: .fail
-* `use_deep_dependencies`:
+* `:dependencies`:
- The base rules and tasks that Ceedling creates using Rake capture most
- of the dependencies within a standard project (e.g. when the source
- file accompanying a test file changes, the corresponding test fixture
- executable will be rebuilt when tests are re-run). However, deep
- dependencies cannot be captured this way. If a typedef or macro
- changes in a header file three levels of #include statements deep,
- this option allows the appropriate incremental build actions to occur
- for both test execution and release builds.
+ File containing make-style dependency rules created by the `gcc` preprocessor
- This is accomplished by using the dependencies discovery mode of gcc.
- With this option enabled, gcc must exist in an accessible system
- search path.
+ **Default**: .d
- **Default**: FALSE
+### Example `:extension` YAML blurb
-* `generate_deep_dependencies`:
+```yaml
+:extension:
+ :source: .cc
+ :executable: .bin
+```
- When `use_deep_dependencies` is set to TRUE, Ceedling will run a separate
- build step to generate the deep dependencies. If you are using gcc as your
- primary compiler, or another compiler that can generate makefile rules as
- a side effect of compilation, then you can set this to FALSE to avoid the
- extra build step but still use the deep dependencies data when deciding
- which source files to rebuild.
+## `:defines` Command line symbols used in compilation
- **Default**: TRUE
+Ceedlingâs internal, default compiler tool configurations (see later `:tools` section)
+execute compilation of test and source C files.
-* `test_file_prefix`:
+These default tool configurations are a one-size-fits-all approach. If you need to add to
+the command line symbols for individual tests or a release build, the `:defines` section
+allows you to easily do so.
- Ceedling collects test files by convention from within the test file
- search paths. The convention includes a unique name prefix and a file
- extension matching that of source files.
+Particularly in testing, symbol definitions in the compilation command line are often needed:
- Why not simply recognize all files in test directories as test files?
- By using the given convention, we have greater flexibility in what we
- do with C files in the test directories.
+1. You may wish to control aspects of your test suite. Conditional compilation statements
+ can control which test cases execute in which circumstances. (Preprocessing must be
+ enabled, `:project` âł `:use_test_preprocessor`.)
- **Default**: "test_"
+1. Testing means isolating the source code under test. This can leave certain symbols
+ unset when source files are compiled in isolation. Adding symbol definitions in your
+ Ceedling project file for such cases is one way to meet this need.
+
+Entries in `:defines` modify the command lines for compilers used at build time. In the
+default case, symbols listed beneath `:defines` become `-D` arguments.
+
+### `:defines` verification (Ceedling does none)
+
+Ceedling does no verification of your configured `:define` symbols.
+
+Unity, CMock, and CException conditional compilation statements, your toolchain's
+preprocessor, and/or your toolchain's compiler will complain appropriately if your
+specified symbols are incorrect, incomplete, or incompatible.
+
+Ceedling _does_ validate your `:defines` block in your project configuration.
+
+### `:defines` organization: Contexts and Matchers
+
+The basic layout of `:defines` involves the concept of contexts.
+
+General case:
+```yaml
+:defines:
+ :: # :test, :release, etc.
+ - # Simple list of symbols added to all compilation
+ - ...
+```
+
+Advanced matching for **_test_** or **_preprocess_** build handling only:
+```yaml
+:defines:
+ :test:
+ : # Matches a subset of test executables
+ - # List of symbols added to that subset's compilation
+ - ...
+ :preprocess: # Only applicable if :project âł :use_test_preprocessor enabled
+ : # Matches a subset of test executables
+ - # List of symbols added to that subset's compilation
+ - ...
+```
-* `options_paths`:
+A context is the build context you want to modify â `:release`, `:preprocess`, or `:test`.
+Plugins can also hook into `:defines` with their own context.
- Just as you may have various build configurations for your source
- codebase, you may need variations of your project configuration.
+You specify the symbols you want to add to a build step beneath a `:`. In many
+cases this is a simple YAML list of strings that will become symbols defined in a
+compiler's command line.
- By specifying options paths, Ceedling will search for other project
- YAML files, make command line tasks available (ceedling options:variation
- for a variation.yml file), and merge the project configuration of
- these option files in with the main project file at runtime. See
- advanced topics.
+Specifically in the `:test` and `:preprocess` contexts you also have the option to
+create test file matchers that create symbol definitions for some subset of your build.
- Note these Rake tasks at the command line - like verbosity or logging
- control - must come before the test or release task they are meant to
- modify.
+* :defines
âł :release
+ This project configuration entry adds the items of a simple YAML list as symbols to
+ the compilation of every C file in a release build.
+
**Default**: `[]` (empty)
-* `release_build`:
+* :defines
âł :test
- When enabled, a release Rake task is exposed. This configuration
- option requires a corresponding release compiler and linker to be
- defined (gcc is used as the default).
+ This project configuration entry adds the specified items as symbols to compilation of C
+ components in a test executableâs build.
+
+ Symbols may be represented in a simple YAML list or with a more sophisticated file matcher
+ YAML key plus symbol list. Both are documented below.
- More release configuration options are available in the release_build
- section.
+ Every C file that comprises a test executable build will be compiled with the symbols
+ configured that match the test filename itself.
+
+ **Default**: `[]` (empty)
- **Default**: FALSE
+* :defines
âł :preprocess
+
+ This project configuration entry adds the specified items as symbols to any needed
+ preprocessing of components in a test executableâs build. Preprocessing must be enabled
+ for this matching to have any effect. (See `:project` âł `:use_test_preprocessor`.)
+
+ Preprocessing here refers to handling macros, conditional includes, etc. in header files
+ that are mocked and in complex test files before runners are generated from them.
+ (See more about the [Ceedling preprocessing](#ceedling-preprocessing-behavior-for-your-tests)
+ feature.)
+
+ Like the `:test` context, compilation symbols may be represented in a simple YAML list
+ or with a more sophisticated file matcher YAML key plus symbol list. Both are documented
+ below.
+
+ _NOTE:_ Left unspecified, `:preprocess` symbols default to be identical to `:test`
+ symbols. Override this behavior by adding `:defines` âł `:preprocess` symbols. If you want
+ no additional symbols for preprocessing regardless of `test` symbols, specify an
+ empty list `[]` in your `:preprocess` matcher.
+
+ **Default**: Identical to `:test` context unless specified
+
+* :defines
âł :<plugin context>
+
+ Some advanced plugins make use of build contexts as well. For instance, the Ceedling
+ Gcov plugin uses a context of `:gcov`, surprisingly enough. For any plugins with tools
+ that take advantage of Ceedlingâs internal mechanisms, you can add to those tools'
+ compilation symbols in the same manner as the built-in contexts.
+
+### `:defines` options
+
+* `:use_test_definition`:
+
+ If enabled, add a symbol to test compilation derived from the test file name. The
+ resulting symbol is a sanitized, uppercase, ASCII version of the test file name.
+ Any non ASCII characters (e.g. Unicode) are replaced by underscores as are any
+ non-alphanumeric characters. Underscores and dashes are preserved. The symbol name
+ is wrapped in underscores unless they already exist in the leading and trailing
+ positions. Example: _test_123abc-xyzđ”.c_ âĄïž `_TEST_123ABC-XYZ_`.
+
+ **Default**: False
+
+### Simple `:defines` configuration
+
+A simple and common need is configuring conditionally compiled features in a code base.
+The following example illustrates using simple YAML lists for symbol definitions at
+compile time.
+
+```yaml
+:defines:
+ :test: # All compilation of all C files for all test executables
+ - FEATURE_X=ON
+ - PRODUCT_CONFIG_C
+ :release: # All compilation of all C files in a release artifact
+ - FEATURE_X=ON
+ - PRODUCT_CONFIG_C
+```
+
+Given the YAML blurb above, the two symbols will be defined in the compilation command
+lines for all C files in all test executables within a test suite build and for all C
+files in a release build.
+
+### Advanced `:defines` per-test matchers
+Ceedling treats each test executable as a mini project. As a reminder, each test file,
+together with all C sources and frameworks, becomes an individual test executable of
+the same name.
-Example `[:project]` YAML blurb
+**_In the `:test` and `:preprocess` contexts only_**, symbols may be defined for only
+those test executable builds that match filename criteria. Matchers match on test
+filenames only, and the specified symbols are added to the build step for all files
+that are components of matched test executables.
+
+In short, for instance, this means your compilation of _TestA_ can have different
+symbols than compilation of _TestB_. Those symbols will be applied to every C file
+that is compiled as part those individual test executable builds. Thus, in fact, with
+separate test files unit testing the same source C file, you may exercise different
+conditional compilations of the same source. See the example in the section below.
+
+#### `:defines` per-test matcher examples with YAML
+
+Before detailing matcher capabilities and limits, here are examples to illustrate the
+basic ideas of test file name matching.
+
+This first example builds on the previous simple symbol list example. The imagined scenario
+is that of unit testing the same single source C file with different product features
+enabled. The per-test matchers shown here use test filename substring matchers.
```yaml
-:project:
- :build_root: project_awesome/build
- :use_exceptions: FALSE
- :use_test_preprocessor: TRUE
- :use_deep_dependencies: TRUE
- :options_paths:
- - project/options
- - external/shared/options
- :release_build: TRUE
+# Imagine three test files all testing aspects of a single source file Comms.c with
+# different features enabled via conditional compilation.
+:defines:
+ :test:
+ # Tests for FeatureX configuration
+ :CommsFeatureX: # Matches a test executable name including 'CommsFeatureX'
+ - FEATURE_X=ON
+ - FEATURE_Z=OFF
+ - PRODUCT_CONFIG_C
+ # Tests for FeatureZ configuration
+ :CommsFeatureZ: # Matches a test executable name including 'CommsFeatureZ'
+ - FEATURE_X=OFF
+ - FEATURE_Z=ON
+ - PRODUCT_CONFIG_C
+ # Tests of base functionality
+ :CommsBase: # Matches a test executable name including 'CommsBase'
+ - FEATURE_X=OFF
+ - FEATURE_Z=OFF
+ - PRODUCT_BASE
```
-Ceedling is primarily concerned with facilitating the somewhat
-complicated mechanics of automating unit tests. The same mechanisms
-are easily capable of building a final release binary artifact
-(i.e. non test code; the thing that is your final working software
-that you execute on target hardware).
+This example illustrates each of the test file name matcher types.
-* `use_backtrace_gdb_reporter`:
- Set this value to true if you project use gcc compiler and you want to collect
- backtrace from test runners which fail with **Segmentation fault** error.
- The .fail files will contain testsuite with information, which test failed.
- Backtrace is fully integrated with **junit_tests_report** plugin.
+```yaml
+:defines:
+ :test:
+ :*: # Wildcard: Add '-DA' for compilation all files for all test executables
+ - A
+ :Model: # Substring: Add '-DCHOO' for compilation of all files of any test executable with 'Model' in its name
+ - CHOO
+ :/M(ain|odel)/: # Regex: Add '-DBLESS_YOU' for all files of any test executable with 'Main' or 'Model' in its name
+ - BLESS_YOU
+ :Comms*Model: # Wildcard: Add '-DTHANKS' for all files of any test executables that have zero or more characters
+ - THANKS # between 'Comms' and 'Model'
+```
- **Default**: FALSE
+#### Using `:defines` per-test matchers
-* `output`:
+These matchers are available:
- The name of your release build binary artifact to be found in /artifacts/release. Ceedling sets the default artifact file
- extension to that as is explicitly specified in the [:extension]
- section or as is system specific otherwise.
+1. Wildcard (`*`)
+ 1. If specified in isolation, matches all tests.
+ 1. If specified within a string, matches any test filename with that
+ wildcard expansion.
+1. Substring â Matches on part of a test filename (up to all of it, including
+ full path).
+1. Regex (`/.../`) â Matches test file names against a regular expression.
- **Default**: `project.exe` or `project.out`
+Notes:
+* Substring filename matching is case sensitive.
+* Wildcard matching is effectively a simplified form of regex. That is, multiple
+ approaches to matching can match the same filename.
-* `use_assembly`:
+Symbols by matcher are cumulative. This means the symbols from multiple
+matchers can be applied to all compilation for any single test executable.
- If assembly code is present in the source tree, this option causes
- Ceedling to create appropriate build directories and use an assembler
- tool (default is the GNU tool as - override available in the [:tools]
- section.
+Referencing the example above, here are the extra compilation symbols for a
+handful of test executables:
- **Default**: FALSE
+* _test_Something_: `-DA`
+* _test_Main_: `-DA -DBLESS_YOU`
+* _test_Model_: `-DA -DCHOO -DBLESS_YOU`
+* _test_CommsSerialModel_: `-DA -DCHOO -DBLESS_YOU -DTHANKS`
-* `artifacts`:
+The simple `:defines` list format remains available for the `:test` and `:preprocess`
+contexts. Of course, this format is limited in that it applies symbols to the
+compilation of all C files for all test executables.
- By default, Ceedling copies to the /artifacts/release
- directory the output of the release linker and (optionally) a map
- file. Many toolchains produce other important output files as well.
- Adding a file path to this list will cause Ceedling to copy that file
- to the artifacts directory. The artifacts directory is helpful for
- organizing important build output files and provides a central place
- for tools such as Continuous Integration servers to point to build
- output. Selectively copying files prevents incidental build cruft from
- needlessly appearing in the artifacts directory. Note that inline Ruby
- string replacement is available in the artifacts paths (see discussion
- in the [:environment] section).
+This simple list format for `:test` and `:preprocess` contextsâŠ
- **Default**: `[]` (empty)
+```yaml
+:defines:
+ :test:
+ - A
+```
-Example `[:release_build]` YAML blurb
+âŠis equivalent to this matcher version:
```yaml
-:release_build:
- :output: top_secret.bin
- :use_assembly: TRUE
- :artifacts:
- - build/release/out/c/top_secret.s19
+:defines:
+ :test:
+ :*:
+ - A
```
-**paths**: options controlling search paths for source and header
-(and assembly) files
+#### Distinguishing similar or identical filenames with `:defines` per-test matchers
-* `test`:
+You may find yourself needing to distinguish test files with the same name or test
+files with names whose base naming is identical.
- All C files containing unit test code. Note: this is one of the
- handful of configuration values that must be set.
+Of course, identical test filenames have a natural distinguishing feature in their
+containing directory paths. Files of the same name can only exist in different
+directories. As such, your matching must include the path.
- **Default**: `[]` (empty)
+```yaml
+:defines:
+ :test:
+ :hardware/test_startup: # Match any test names beginning with 'test_startup' in hardware/ directory
+ - A
+ :network/test_startup: # Match any test names beginning with 'test_startup' in network/ directory
+ - B
+```
-* `source`:
+It's common in C file naming to use the same base name for multiple files. Given the
+following example list, care must be given to matcher construction to single out
+test_comm_startup.c.
- All C files containing release code (code to be tested). Note: this is
- one of the handful of configuration values that must be set.
+* tests/test_comm_hw.c
+* tests/test_comm_startup.c
+* tests/test_comm_startup_timers.c
- **Default**: `[]` (empty)
+```yaml
+:defines:
+ :test:
+ :test_comm_startup.c: # Full filename with extension distinguishes this file test_comm_startup_timers.c
+ - FOO
+```
-* `support`:
+The preceding examples use substring matching, but, regular expression matching
+could also be appropriate.
- Any C files you might need to aid your unit testing. For example, on
- occasion, you may need to create a header file containing a subset of
- function signatures matching those elsewhere in your code (e.g. a
- subset of your OS functions, a portion of a library API, etc.). Why?
- To provide finer grained control over mock function substitution or
- limiting the size of the generated mocks.
+#### Using YAML anchors & aliases for complex testing scenarios with `:defines`
- **Default**: `[]` (empty)
+See the short but helpful article on [YAML anchors & aliases][yaml-anchors-aliases] to
+understand these features of YAML.
+
+Particularly in testing complex projects, per-test file matching may only get you so
+far in meeting your symbol definition needs. For instance, you may need to use the
+same symbols across many test files, but no convenient name matching scheme works.
+Advanced YAML features can help you copy the same symbols into multiple `:defines`
+test file matchers.
+
+The following advanced example illustrates how to create a set of compilation symbols
+for test preprocessing that are identical to test compilation with one addition.
+
+In brief, this example uses YAML features to copy the `:test` matcher configuration
+that matches all test executables into the `:preprocess` context and then add an
+additional compilation symbol to the list.
+
+```yaml
+:defines:
+ :test: &config-test-defines # YAML anchor
+ :*: &match-all-tests # YAML anchor
+ - PRODUCT_FEATURE_X
+ - ASSERT_LEVEL=2
+ - USES_RTOS=1
+ :test_foo:
+ - DRIVER_FOO=1u
+ :test_bar:
+ - DRIVER_BAR=5u
+ :preprocess:
+ <<: *config-test-defines # Insert all :test defines file matchers via YAML alias
+ :*: # Override wildcard matching key in copy of *config-test-defines
+ - *match-all-tests # Copy test defines for all files via YAML alias
+ - RTOS_SPECIAL_THING # Add single additional symbol to all test executable preprocessing
+ # test_foo, test_bar, and any other matchers are present because of <<: above
+```
-* `include`:
+## `:libraries`
- Any header files not already in the source search path. Note there's
- no practical distinction between this search path and the source
- search path; it's merely to provide options or to support any
- peculiar source tree organization.
+Ceedling allows you to pull in specific libraries for release and test builds with a
+few levels of support.
+* :libraries
âł :test
+
+ Libraries that should be injected into your test builds when linking occurs.
+
+ These can be specified as naked library names or with relative paths if search paths
+ are specified with `:paths` âł `:libraries`. Otherwise, absolute paths may be used
+ here.
+
+ These library files **must** exist when tests build.
+
**Default**: `[]` (empty)
-* `test_toolchain_include`:
+* :libraries
âł :release
+
+ Libraries that should be injected into your release build when linking occurs.
+
+ These can be specified as naked library names or with relative paths if search paths
+ are specified with `:paths` âł `:libraries`. Otherwise, absolute paths may be used
+ here.
+
+ These library files **must** exist when the release build occurs **unless** you
+ are using the _subprojects_ plugin. In that case, the plugin will attempt to build
+ the needed library for you as a dependency.
+
+ **Default**: `[]` (empty)
- System header files needed by the test toolchain - should your
- compiler be unable to find them, finds the wrong system include search
- path, or you need a creative solution to a tricky technical problem.
- Note that if you configure your own toolchain in the [:tools] section,
- this search path is largely meaningless to you. However, this is a
- convenient way to control the system include path should you rely on
- the default gcc tools.
+* :libraries
âł :system
+
+ Libraries listed here will be injected into releases and tests.
+
+ These libraries are assumed to be findable by the configured linker tool, should need
+ no path help, and can be specified by common linker shorthand for libraries.
+
+ For example, specifying `m` will include the math library per the GCC convention. The
+ file itself on a Unix-like system will be `libm` and the `gcc` command line argument
+ will be `-lm`.
+
+ **Default**: `[]` (empty)
+
+### `:libraries` options
+
+* `:flag`:
+
+ Command line argument format for specifying a library.
+
+ **Default**: `-l${1}` (GCC format)
+
+* `:path_flag`:
+
+ Command line argument format for adding a library search path.
+
+ Library search paths may be added to your project with `:paths` âł `:libraries`.
+
+ **Default**: `-L "${1}â` (GCC format)
+
+### `:libraries` example with YAML blurb
+
+```yaml
+:paths:
+ :libraries:
+ - proj/libs # Linker library search paths
+
+:libraries:
+ :test:
+ - test/commsstub.lib # Imagined communication library that logs to console without traffic
+ :release:
+ - release/comms.lib # Imagined production communication library
+ :system:
+ - math # Add system math library to test & release builds
+ :flag: -Lib=${1} # This linker does not follow the gcc convention
+```
+
+### `:libraries` notes
+
+* If you've specified your own link step, you are going to want to add `${4}` to your
+ argument list in the position where library files should be added to the command line.
+ For `gcc`, this is often at the very end. Other tools may vary. See the `:tools`
+ section for more.
+
+## `:flags` Configure preprocessing, compilation & linking command line flags
+
+Ceedlingâs internal, default tool configurations execute compilation and linking of test
+and source files among a variety of other tooling needs. (See later `:tools` section.)
+
+These default tool configurations are a one-size-fits-all approach. If you need to add
+flags to the command line for individual tests or a release build, the `:flags` section
+allows you to easily do so.
+
+Entries in `:flags` modify the command lines for tools used at build time.
+
+### Flags organization: Contexts, Operations, and Matchers
+
+The basic layout of `:flags` involves the concepts of contexts and operations.
+General case:
+```yaml
+:flags:
+ :: # :test or :release
+ :: # :preprocess, :compile, :assemble, or :link
+ -
+ - ...
+```
+
+Advanced matching for **_test_** build handling only:
+```yaml
+:flags:
+ :test:
+ :: # :preprocess, :compile, :assemble, or :link
+ :: # Matches a subset of test executables
+ - # List of flags added to that subset's build operation command line
+ - ...
+```
+
+A context is the build context you want to modify â `:test` or `:release`. Plugins can
+also hook into `:flags` with their own context.
+
+An operation is the build step you wish to modify â `:preprocess`, `:compile`, `:assemble`,
+or `:link`.
+
+* The `:preprocess` operation is only used from within the `:test` context.
+* The `:assemble` operation is only of use within the `:test` or `:release` contexts if
+ assembly support has been enabled in `:test_build` or `:release_build`, respectively, and
+ assembly files are a part of the project.
+
+You specify the flags you want to add to a build step beneath `:` âł `:`.
+In many cases this is a simple YAML list of strings that will become flags in a tool's
+command line.
+
+**_Specifically and only in the `:test` context_** you also have the option to create test
+file matchers that apply flags to some subset of your test build. Note that file matchers
+and the simpler flags list format cannot be mixed for `:flags` âł `:test`.
+
+* :flags
âł :release
âł :compile
+
+ This project configuration entry adds the items of a simple YAML list as flags to
+ compilation of every C file in a release build.
+
**Default**: `[]` (empty)
-* `release_toolchain_include`:
+* :flags
âł :release
âł :link
- Same as preceding albeit related to the release toolchain.
+ This project configuration entry adds the items of a simple YAML list as flags to
+ the link step of a release build artifact.
+
+ **Default**: `[]` (empty)
+
+* :flags
âł :test
âł :compile
+ This project configuration entry adds the specified items as flags to compilation of C
+ components in a test executable's build.
+
+ Flags may be represented in a simple YAML list or with a more sophisticated file matcher
+ YAML key plus flag list. Both are documented below.
+
**Default**: `[]` (empty)
-* ``
+* :flags
âł :test
âł :preprocess
+
+ This project configuration entry adds the specified items as flags to any needed
+ preprocessing of components in a test executableâs build. Preprocessing must be enabled
+ for this matching to have any effect. (See `:project` âł `:use_test_preprocessor`.)
+
+ Preprocessing here refers to handling macros, conditional includes, etc. in header files
+ that are mocked and in complex test files before runners are generated from them.
+ (See more about the [Ceedling preprocessing](#ceedling-preprocessing-behavior-for-your-tests)
+ feature.)
+
+ Flags may be represented in a simple YAML list or with a more sophisticated file matcher
+ YAML key plus flag list. Both are documented below.
+
+ _NOTE:_ Left unspecified, `:preprocess` flags default to behaving identically to `:compile`
+ flags. Override this behavior by adding `:test` âł `:preprocess` flags. If you want no
+ additional flags for preprocessing regardless of test compilation flags, simply specify
+ an empty list `[]`.
+
+ **Default**: Same flags as specified for test compilation
+
+* :flags
âł :test
âł :link
+
+ This project configuration entry adds the specified items as flags to the link step of
+ test executables.
+
+ Flags may be represented in a simple YAML list or with a more sophisticated file matcher
+ YAML key plus flag list. Both are documented below.
+
+ **Default**: `[]` (empty)
- Any paths you specify for custom list. List is available to tool
- configurations and/or plugins. Note a distinction. The preceding names
- are recognized internally to Ceedling and the path lists are used to
- build collections of files contained in those paths. A custom list is
- just that - a custom list of paths.
+* :flags
âł :<plugin context>
+
+ Some advanced plugins make use of build contexts as well. For instance, the Ceedling
+ Gcov plugin uses a context of `:gcov`, surprisingly enough. For any plugins with tools
+ that take advantage of Ceedlingâs internal mechanisms, you can add to those tools'
+ flags in the same manner as the built-in contexts and operations.
+
+### Simple `:flags` configuration
+
+A simple and common need is enforcing a particular C standard. The following example
+illustrates simple YAML lists for flags.
+
+```yaml
+:flags:
+ :release:
+ :compile:
+ - -std=c99 # Add `-std=c99` to compilation of all C files in the release build
+ :test:
+ :compile:
+ - -std=c99 # Add `-std=c99` to the compilation of all C files in all test executables
+```
-Notes on path grammar within the [:paths] section:
+Given the YAML blurb above, when test or release compilation occurs, the flag specifying
+the C standard will be in the command line for compilation of all C files.
-* Order of search paths listed in [:paths] is preserved when used by an
- entry in the [:tools] section
+### Advanced `:flags` per-test matchers
-* Wherever multiple path lists are combined for use Ceedling prioritizes
- path groups as follows:
- test paths, support paths, source paths, include paths.
+Ceedling treats each test executable as a mini project. As a reminder, each test file,
+together with all C sources and frameworks, becomes an individual test executable of
+the same name.
- This can be useful, for instance, in certain testing scenarios where
- we desire Ceedling or the compiler to find a stand-in header file before
- the actual source header file of the same name.
+_In the `:test` context only_, flags can be applied to build step operations â
+preprocessing, compilation, and linking â for only those test executables that match
+file name criteria. Matchers match on test filenames only, and the specified flags
+are added to the build step for all files that are components of matched test
+executables.
-* Paths:
+In short, for instance, this means your compilation of _TestA_ can have different flags
+than compilation of _TestB_. And, in fact, those flags will be applied to every C file
+that is compiled as part those individual test executable builds.
- 1. can be absolute or relative
+#### `:flags` per-test matcher examples with YAML
- 2. can be singly explicit - a single fully specified path
+Before detailing matcher capabilities and limits, here are examples to illustrate the
+basic ideas of test file name matching.
- 3. can include a glob operator (more on this below)
+```yaml
+:flags:
+ :test:
+ :compile:
+ :*: # Wildcard: Add '-foo' for all files compiled for all test executables
+ - -foo
+ :Model: # Substring: Add '-Wall' for all files compiled for any test executable with 'Model' in its filename
+ - -Wall
+ :/M(ain|odel)/: # Regex: Add đŽââ ïž flag for all files compiled for any test executable with 'Main' or 'Model' in its filename
+ - -đŽââ ïž
+ :Comms*Model:
+ - --freak # Wildcard: Add your `--freak` flag for all files compiled for any test executable with zero or more
+ # characters between 'Comms' and 'Model'
+ :link:
+ :tests/comm/TestUsart.c: # Substring: Add '--bar --baz' to the link step of the TestUsart executable
+ - --bar
+ - --baz
+```
- 4. can use inline Ruby string replacement (see [:environment]
- section for more)
+#### Using `:flags` per-test matchers
- 5. default as an addition to a specific search list (more on this
- in the examples)
+These matchers are available:
- 6. can act to subtract from a glob included in the path list (more
- on this in the examples)
+1. Wildcard (`*`)
+ 1. If specified in isolation, matches all tests.
+ 1. If specified within a string, matches any test filename with that
+ wildcard expansion.
+1. Substring â Matches on part of a test filename (up to all of it, including
+ full path).
+1. Regex (`/.../`) â Matches test file names against a regular expression.
-[Globs](http://ruby.about.com/od/beginningruby/a/dir2.htm)
-as used by Ceedling are wildcards for specifying directories
-without the need to list each and every required search path.
-Ceedling globs operate just as Ruby globs except that they are
-limited to matching directories and not files. Glob operators
-include the following * ** ? [-] {,} (note: this list is space separated
-and not comma separated as commas are used within the bracket
-operators).
+Notes:
+* Substring filename matching is case sensitive.
+* Wildcard matching is effectively a simplified form of regex. That is,
+ multiple approaches to matching can match the same filename.
-* `*`:
+Flags by matcher are cumulative. This means the flags from multiple matchers can be
+applied to all files processed by the named build operation for any single test executable.
- All subdirectories of depth 1 below the parent path and including the
- parent path
+Referencing the example above, here are the extra compilation flags for a handful of
+test executables:
-* `**`:
+* _test_Something_: `-foo`
+* _test_Main_: `-foo -đŽââ ïž`
+* _test_Model_: `-foo -Wall -đŽââ ïž`
+* _test_CommsSerialModel_: `-foo -Wall -đŽââ ïž --freak`
- All subdirectories recursively discovered below the parent path and
- including the parent path
+The simple `:flags` list format remains available for the `:test` context. Of course,
+this format is limited in that it applies flags to all C files processed by the named
+build operation for all test executables.
-* `?`:
+This simple list format for the `:test` contextâŠ
- Single alphanumeric character wildcard
+```yaml
+:flags:
+ :test:
+ :compile:
+ - -foo
+```
-* `[x-y]`:
+âŠis equivalent to this matcher version:
- Single alphanumeric character as found in the specified range
+```yaml
+:flags:
+ :test:
+ :compile:
+ :*:
+ - -foo
+```
-* `{x,y}`:
+#### Distinguishing similar or identical filenames with `:flags` per-test matchers
- Single alphanumeric character from the specified list
+You may find yourself needing to distinguish test files with the same name or test
+files with names whose base naming is identical.
-Example [:paths] YAML blurbs
+Of course, identical test filenames have a natural distinguishing feature in their
+containing directory paths. Files of the same name can only exist in different
+directories. As such, your matching must include the path.
```yaml
-:paths:
- :source: #together the following comprise all source search paths
- - project/source/* #expansion yields all subdirectories of depth 1 plus parent directory
- - project/lib #single path
- :test: #all test search paths
- - project/**/test? #expansion yields any subdirectory found anywhere in the project that
- #begins with "test" and contains 5 characters
+:flags:
+ :test:
+ :compile:
+ :hardware/test_startup: # Match any test names beginning with 'test_startup' in hardware/ directory
+ - A
+ :network/test_startup: # Match any test names beginning with 'test_startup' in network/ directory
+ - B
+```
-:paths:
- :source: #all source search paths
- - +:project/source/** #all subdirectories recursively discovered plus parent directory
- - -:project/source/os/generated #subtract os/generated directory from expansion of above glob
- #note that '+:' notation is merely aesthetic; default is to add
+It's common in C file naming to use the same base name for multiple files. Given the
+following example list, care must be given to matcher construction to single out
+test_comm_startup.c.
- :test: #all test search paths
- - project/test/bootloader #explicit, single search paths (searched in the order specified)
- - project/test/application
- - project/test/utilities
+* tests/test_comm_hw.c
+* tests/test_comm_startup.c
+* tests/test_comm_startup_timers.c
- :custom: #custom path list
- - "#{PROJECT_ROOT}/other" #inline Ruby string expansion
+```yaml
+:flags:
+ :test:
+ :compile:
+ :test_comm_startup.c: # Full filename with extension distinguishes this file test_comm_startup_timers.c
+ - FOO
```
-Globs and inline Ruby string expansion can require trial and
-error to arrive at your intended results. Use the `ceedling paths:*`
-command line options (documented in preceding section) to verify
-your settings.
+The preceding examples use substring matching, but, regular expression matching
+could also be appropriate.
+
+#### Using YAML anchors & aliases for complex testing scenarios with `:flags`
+
+See the short but helpful article on [YAML anchors & aliases][yaml-anchors-aliases] to
+understand these features of YAML.
+
+Particularly in testing complex projects, per-test file matching may only get you so
+far in meeting your build step flag needs. For instance, you may need to set various
+flags for operations across many test files, but no convenient name matching scheme
+works. Advanced YAML features can help you copy the same flags into multiple `:flags`
+test file matchers.
+
+Please see the discussion in `:defines` for a complete example.
+
+## `:cexception` Configure CExceptionâs features
+
+* `:defines`:
+
+ List of symbols used to configure CException's features in its source and header files
+ at compile time.
+
+ See [Using Unity, CMock & CException](#using-unity-cmock--cexception) for much more on
+ configuring and making use of these frameworks in your build.
+
+ To manage overall command line length, these symbols are only added to compilation when
+ a CException C source file is compiled.
+
+ No symbols must be set unless CException's defaults are inappropriate for your
+ environment and needs.
+
+ Note CException must be enabled for it to be added to a release or test build and for
+ these symbols to be added to a build of CException (see link referenced earlier for more).
+
+ **Default**: `[]` (empty)
-Ceedling relies on file collections automagically assembled
-from paths, globs, and file extensions. File collections greatly
-simplify project set up. However, sometimes you need to remove
-from or add individual files to those collections.
+## `:cmock` Configure CMockâs code generation & compilation
+Ceedling sets values for a subset of CMock settings. All CMock options are
+available to be set, but only those options set by Ceedling in an automated
+fashion are documented below. See CMock documentation.
-* `test`:
+Ceedling sets values for a subset of CMock settings. All CMock options are
+available to be set, but only those options set by Ceedling in an automated
+fashion are documented below. See [CMock] documentation.
- Modify the collection of unit test C files.
+* `:enforce_strict_ordering`:
- **Default**: `[]` (empty)
+ Tests fail if expected call order is not same as source order
+
+ **Default**: TRUE
-* `source`:
+* `:verbosity`:
- Modify the collection of all source files used in unit test builds and release builds.
+ If not set, defaults to Ceedlingâs verbosity level
+* `:defines`:
+
+ Adds list of symbols used to configure CMockâs C code features in its source and header
+ files at compile time.
+
+ See [Using Unity, CMock & CException](#using-unity-cmock--cexception) for much more on
+ configuring and making use of these frameworks in your build.
+
+ To manage overall command line length, these symbols are only added to compilation when
+ a CMock C source file is compiled.
+
+ No symbols must be set unless CMockâs defaults are inappropriate for your environment
+ and needs.
+
**Default**: `[]` (empty)
-* `assembly`:
+* `:plugins`:
- Modify the (optional) collection of assembly files used in release builds.
+ To enable CMockâs optional and advanced features available via CMock plugin, simply add
+ `:cmock` âł `:plugins` to your configuration and specify your desired additional CMock
+ plugins as a simple list of the plugin names.
+
+ See [CMock's documentation][cmock-docs] to understand plugin options.
+
+ [cmock-docs]: https://github.com/ThrowTheSwitch/CMock/blob/master/docs/CMock_Summary.md
**Default**: `[]` (empty)
-* `include`:
+* `:unity_helper_path`:
+
+ A Unity helper is a simple header file used by convention to support your specialized
+ test case needs. For example, perhaps you want a Unity assertion macro for the
+ contents of a struct used throughout your project. Write the macro you need in a Unity
+ helper header file and `#include` that header file in your test file.
- Modify the collection of all source header files used in unit test builds (e.g. for mocking) and release builds.
+ When a Unity helper is provided to CMock, it takes on more significance, and more
+ magic happens. CMock parses Unity helper header files and uses macros of a certain
+ naming convention to extend CMockâs handling of mocked parameters.
+
+ See the [Unity] and [CMock] documentation for more details.
+
+ `:unity_helper_path` may be a single string or a list. Each value must be a relative
+ path from your Ceedling working directory to a Unity helper header file (these are
+ typically organized within containing Ceedling `:paths` âł `:support` directories).
**Default**: `[]` (empty)
-* `support`:
+* `:includes`:
- Modify the collection of supporting C files available to unit tests builds.
+ In certain advanced testing scenarios, you may need to inject additional header files
+ into generated mocks. The filenames in this list will be transformed into `#include`
+ directives created at the top of every generated mock.
+
+ If `:unity_helper_path` is in use (see preceding), the filenames at the end of any
+ Unity helper file paths will be automatically injected into this list provided to
+ CMock.
**Default**: `[]` (empty)
-* `libraries`:
+### Notes on Ceedlingâs nudges for CMock strict ordering
- Add a collection of library paths to be included when linking.
+The preceding settings are tied to other Ceedling settings; hence, why they are
+documented here.
+
+The first setting above, `:enforce_strict_ordering`, defaults to `FALSE` within
+CMock. However, it is set to `TRUE` by default in Ceedling as our way of
+encouraging you to use strict ordering.
+
+Strict ordering is teeny bit more expensive in terms of code generated, test
+execution time, and complication in deciphering test failures. However, itâs
+good practice. And, of course, you can always disable it by overriding the
+value in the Ceedling project configuration file.
+## `:unity` Configure Unityâs features
+
+* `:defines`:
+
+ Adds list of symbols used to configure Unity's features in its source and header files
+ at compile time.
+
+ See [Using Unity, CMock & CException](#using-unity-cmock--cexception) for much more on
+ configuring and making use of these frameworks in your build.
+
+ To manage overall command line length, these symbols are only added to compilation when
+ a Unity C source file is compiled.
+
+ **_Note_**: No symbols must be set unless Unity's defaults are inappropriate for your
+ environment and needs.
+
**Default**: `[]` (empty)
+* `:use_param_tests`:
+
+ Configures Unity test runner generation and `#define`s for test compilation to support
+ Unityâs parameterized test cases.
+
+ Example parameterized test case:
+
+ ```C
+ TEST_RANGE([5, 100, 5])
+ void test_should_handle_divisible_by_5_for_parameterized_test_range(int num) {
+ TEST_ASSERT_EQUAL(0, (num % 5));
+ }
+ ```
+
+ See [Unity] documentation for more on parameterized test cases.
+
+ **Default**: false
+
+## `:test_runner` Configure test runner generation
+
+The format of Ceedling test files â the C files that contain unit test cases â
+is intentionally simple. Itâs pure code and all legit, simple C with `#include`
+statements, test case functions, and optional `setUp()` and `tearDown()`
+functions.
+
+To create test executables, we need a `main()` and a variety of calls to the
+Unity framework to âhook upâ all your test cases into a test suite. You can do
+this by hand, of course, but it's tedious and needed updates as code evolves
+are easily forgotten.
+
+So, Unity provides a script able to generate a test runner in C for you. It
+relies on [ceedling-conventions] used in your test files. Ceedling takes this
+a step further by calling this script for you with all the needed parameters.
+
+Test runner generation is configurable. The `:test_runner` section of your
+Ceedling project file allows you to pass options to Unityâs runner generation
+script. Based on other Ceedling options, Ceedling also sets certain test runner
+generation configuration values for you.
+
+[Test runner configuration options are documented in the Unity project][unity-runner-options].
+
+**_Notes:_**
-Note: All path grammar documented in [:paths] section applies
-to [:files] path entries - albeit at the file path level and not
-the directory level.
+* **Unless you have advanced or unique needs, Unity test runner generation
+ configuration in Ceedling is generally not needed.**
+* In previous versions of Ceedling, the test runner option
+ `:cmdline_args` was needed for certain advanced test suite features. This
+ option is still needed, but Ceedling automatically sets it for you in the
+ scenarios requiring it. Be aware that this option works well in desktop,
+ native testing but is generally unsupported by emulators running test
+ executables (the idea of command line arguments passed to an executable is
+ generally only possible with desktop command line terminals.)
-Example [:files] YAML blurb
+Example configuration:
```yaml
-:files:
- :source:
- - callbacks/comm.c # entry defaults to file addition
- - +:callbacks/comm*.c # add all comm files matching glob pattern
- - -:source/board/atm134.c # not our board
- :test:
- - -:test/io/test_output_manager.c # remove unit tests from test build
+:test_runner:
+ # Insert additional #include statements in a generated runner
+ :includes:
+ - Foo.h
+ - Bar.h
```
-**environment:** inserts environment variables into the shell
-instance executing configured tools
-
-Ceedling creates environment variables from any key / value
-pairs in the environment section. Keys become an environment
-variable name in uppercase. The values are strings assigned
-to those environment variables. These value strings are either
-simple string values in YAML or the concatenation of a YAML array.
+[ceedling-conventions]: #important-conventions--behaviors
+[unity-runner-options]: https://github.com/ThrowTheSwitch/Unity/blob/master/docs/UnityHelperScriptsGuide.md#options-accepted-by-generate_test_runnerrb
-Ceedling is able to execute inline Ruby string substitution
-code to set environment variables. This evaluation occurs when
-the project file is first processed for any environment pair's
-value string including the Ruby string substitution pattern
-`#{âŠ}`. Note that environment value strings that _begin_ with
-this pattern should always be enclosed in quotes. YAML defaults
-to processing unquoted text as a string; quoting text is optional.
-If an environment pair's value string begins with the Ruby string
-substitution pattern, YAML will interpret the string as a Ruby
-comment (because of the `#`). Enclosing each environment value
-string in quotes is a safe practice.
+## `:tools` Configuring command line tools used for build steps
-[:environment] entries are processed in the configured order
-(later entries can reference earlier entries).
+Ceedling requires a variety of tools to work its magic. By default, the GNU
+toolchain (`gcc`, `cpp`, `as` â and `gcov` via plugin) are configured and ready
+for use with no additions to your project configuration YAML file.
-Special case: PATH handling
+A few items before we dive in:
-In the specific case of specifying an environment key named _path_,
-an array of string values will be concatenated with the appropriate
-platform-specific path separation character (e.g. ':' on linux,
-';' on Windows). All other instances of environment keys assigned
-YAML arrays use simple concatenation.
+1. Sometimes Ceedlingâs built-in tools are _nearly_ what you need but not
+ quite. If you only need to add some arguments to all uses of tool's command
+ line, Ceedling offers a shortcut to do so. See the
+ [final section of the `:tools`][tool-definition-shortcuts] documentation for
+ details.
+1. If you need fine-grained control of the arguments Ceedling uses in the build
+ steps for test executables, see the documentation for [`:flags`][flags].
+ Ceedling allows you to control the command line arguments for each test
+ executable build â with a variety of pattern matching options.
+1. If you need to link libraries â your own or standard options â please see
+ the [top-level `:libraries` section][libraries] available for your
+ configuration file. Ceedling supports a number of useful options for working
+ with pre-compiled libraries. If your library linking needs are super simple,
+ the shortcut in (1) might be the simplest option.
-Example [:environment] YAML blurb
+[flags]: #flags-configure-preprocessing-compilation--linking-command-line-flags
+[tool-definition-shortcuts]: #ceedling-tool-modification-shortcuts
-```yaml
-:environment:
- - :license_server: gizmo.intranet #LICENSE_SERVER set with value "gizmo.intranet"
- - :license: "#{`license.exe`}" #LICENSE set to string generated from shelling out to
- #execute license.exe; note use of enclosing quotes
+### Ceedling tools for test suite builds
- - :path: #concatenated with path separator (see special case above)
- - Tools/gizmo/bin #prepend existing PATH with gizmo path
- - "#{ENV['PATH']}" #pattern #{âŠ} triggers ruby evaluation string substitution
- #note: value string must be quoted because of '#'
-
- - :logfile: system/logs/thingamabob.log #LOGFILE set with path for a log file
-```
+Our recommended approach to writing and executing test suites relies on the GNU
+toolchain. _*Yes, even for embedded system work on platforms with their own,
+proprietary C toolchain.*_ Please see
+[this section of documentation][sweet-suite] to understand this recommendation
+among all your options.
-**extension**: configure file name extensions used to collect lists of files searched in [:paths]
+You can and sometimes must run a Ceedling test suite in an emulator or on
+target, and Ceedling allows you to do this through tool definitions documented
+here. Generally, youâll likely want to rely on the default definitions.
-* `header`:
+[sweet-suite]: #all-your-sweet-sweet-test-suite-options
- C header files
+### Ceedling tools for release builds
- **Default**: .h
+More often than not, release builds require custom tool definitions. The GNU
+toolchain is configured for Ceeding release builds by default just as with test
+builds. youâll likely need your own definitions for `:release_compiler`,
+`:release_linker`, and possibly `:release_assembler`.
-* `source`:
+### Ceedling plugin tools
- C code files (whether source or test files)
+Ceedling plugins are free to define their own tools that are loaded into your
+project configuration at startup. Plugin tools are defined using the same
+mechanisns as Ceedlingâs built-in tools and are called the same way. That is,
+all features available to you for working with tools as an end users are
+generally available for working with plugin-based tools. This presumes a
+plugin author followed guidance and convention in creating any command line
+actions.
- **Default**: .c
+### Ceedling tool definitions
-* `assembly`:
+Contained in this section are details on Ceedlingâs default tool definitions.
+For sake of space, the entirety of a given definition is not shown. If you need
+to get in the weeds or want a full example, see the file `defaults.rb` in
+Ceedlingâs lib/ directory.
- Assembly files (contents wholly assembly instructions)
+#### Tool definition overview
- **Default**: .s
+Listed below are the built-in tool names, corresponding to build steps along
+with the numbered parameters that Ceedling uses to fill out a full command line
+for the named tool. The full list of fundamental elements for a tool definition
+are documented in the sections that follow along with examples.
-* `object`:
+Not every numbered parameter listed immediately below must be referenced in a
+Ceedling tool definition. If `${4}` isnât referenced by your custom tool,
+Ceedling simply skips it while expanding a tool definition into a command line.
- Resulting binary output of C code compiler (and assembler)
+The numbered parameters below are references that expand / are replaced with
+actual values when the corresponding command line is constructed. If the values
+behind these parameters are lists, Ceedling expands the containing reference
+multiple times with the contents of the value. A conceptual example is
+instructiveâŠ
- **Default**: .o
+#### Simplified tool definition / expansion example
-* `executable`:
+A partial tool definition:
- Binary executable to be loaded and executed upon target hardware
+```yaml
+:tools:
+ :power_drill:
+ :executable: dewalt.exe
+ :arguments:
+ - "--X${3}"
+```
- **Default**: .exe or .out (Win or linux)
+Let's say that `${3}` is a list inside Ceedling, `[2, 3, 7]`. The expanded tool
+command line for `:tools` âł `:power_drill` would look like this:
-* `testpass`:
+```shell
+ > dewalt.exe --X2 --X3 --X7
+```
- Test results file (not likely to ever need a new value)
+#### Ceedlingâs default build step tool definitions
- **Default**: .pass
+**_NOTE:_** Ceedlingâs tool definitions for its preprocessing and backtrace
+features are not documented here. Ceedlingâs use of tools for these features
+are tightly coupled to the options and output of those tools. Drop-in
+replacements using other tools are not practically possible. Eventually, an
+improved plugin system will provide options for integrating alternative tools.
-* `testfail`:
+* `:test_compiler`:
- Test results file (not likely to ever need a new value)
+ Compiler for test & source-under-test code
- **Default**: .fail
+ - `${1}`: Input source
+ - `${2}`: Output object
+ - `${3}`: Optional output list
+ - `${4}`: Optional output dependencies file
+ - `${5}`: Header file search paths
+ - `${6}`: Command line #defines
-* `dependencies`:
+ **Default**: `gcc`
- File containing make-style dependency rules created by gcc preprocessor
+* `:test_assembler`:
- **Default**: .d
+ Assembler for test assembly code
+ - `${1}`: input assembly source file
+ - `${2}`: output object file
+ - `${3}`: search paths
+ - `${4}`: #define symbols (accepted but ignored by GNU assembler)
-Example [:extension] YAML blurb
+ **Default**: `as`
- :extension:
- :source: .cc
- :executable: .bin
+* `:test_linker`:
-**defines**: command line defines used in test and release compilation by configured tools
+ Linker to generate test fixture executables
-* `test`:
+ - `${1}`: input objects
+ - `${2}`: output binary
+ - `${3}`: optional output map
+ - `${4}`: optional library list
+ - `${5}`: optional library path list
- Defines needed for testing. Useful for:
+ **Default**: `gcc`
- 1. test files containing conditional compilation statements (i.e.
- tests active in only certain contexts)
+* `:test_fixture`:
- 2. testing legacy source wherein the isolation of source under test
- afforded by Ceedling and its complementary tools leaves certain
- symbols unset when source files are compiled in isolation
+ Executable test fixture
- **Default**: `[]` (empty)
+ - `${1}`: simulator as executable with`${1}` as input binary file argument or native test executable
-* `test_preprocess`:
+ **Default**: `${1}`
- If [:project][:use_test_preprocessor] or
- [:project][:use_deep_dependencies] is set and code is structured in a
- certain way, the gcc preprocessor may need symbol definitions to
- properly preprocess files to extract function signatures for mocking
- and extract deep dependencies for incremental builds.
+* `:release_compiler`:
- **Default**: `[]` (empty)
+ Compiler for release source code
-* ``:
+ - `${1}`: input source
+ - `${2}`: output object
+ - `${3}`: optional output list
+ - `${4}`: optional output dependencies file
- Replace standard `test` definitions for specified ``definitions. For example:
-```yaml
- :defines:
- :test:
- - FOO_STANDARD_CONFIG
- :test_foo_config:
- - FOO_SPECIFIC_CONFIG
-```
- `ceedling test:foo_config` will now have `FOO_SPECIFIC_CONFIG` defined instead of
- `FOO_STANDARD_CONFIG`. None of the other tests will have `FOO_SPECIFIC_SPECIFIC`.
+ **Default**: `gcc`
- **Default**: `[]` (empty)
+* `:release_assembler`:
-* `release`:
+ Assembler for release assembly code
- Defines needed for the release build binary artifact.
+ - `${1}`: input assembly source file
+ - `${2}`: output object file
+ - `${3}`: search paths
+ - `${4}`: #define symbols (accepted but ignored by GNU assembler)
- **Default**: `[]` (empty)
+ **Default**: `as`
-* `release_preprocess`:
+* `:release_linker`:
- If [:project][:use_deep_dependencies] is set and code is structured in
- a certain way, the gcc preprocessor may need symbol definitions to
- properly preprocess files for incremental release builds due to deep
- dependencies.
+ Linker for release source code
- **Default**: `[]` (empty)
+ - `${1}`: input objects
+ - `${2}`: output binary
+ - `${3}`: optional output map
+ - `${4}`: optional library list
+ - `${5}`: optional library path list
-* `use_test_definition`:
+ **Default**: `gcc`
- When this option is used the `-D` flag is added to the build option.
+#### Tool defintion configurable elements
- **Default**: FALSE
+1. `:executable` - Command line executable (required).
-Example [:defines] YAML blurb
+ NOTE: If an executable contains a space (e.g. `Code Cruncher`), and the
+ shell executing the command line generated from the tool definition needs
+ the name quoted, add escaped quotes in the YAML:
-```yaml
-:defines:
- :test:
- - UNIT_TESTING #for select cases in source to allow testing with a changed behavior or interface
- - OFF=0
- - ON=1
- - FEATURE_X=ON
- :source:
- - FEATURE_X=ON
-```
+ ```yaml
+ :tools:
+ :test_compiler:
+ :executable: \"Code Cruncher\"
+ ```
+1. `:arguments` - List (array of strings) of command line arguments and
+ substitutions (required).
-**libraries**: command line defines used in test and release compilation by configured tools
+1. `:name` - Simple name (i.e. "nickname") of tool beyond its
+ executable name. This is optional. If not explicitly set
+ then Ceedling will form a name from the tool's YAML entry key.
-Ceedling allows you to pull in specific libraries for the purpose of release and test builds.
-It has a few levels of support for this. Start by adding a :libraries main section in your
-configuration. In this section, you can optionally have the following subsections:
+1. `:stderr_redirect` - Control of capturing `$stderr` messages
+ {`:none`, `:auto`, `:win`, `:unix`, `:tcsh`}.
+ Defaults to `:none` if unspecified. You may create a custom entry by
+ specifying a simple string instead of any of the recognized
+ symbols. As an example, the `:unix` symbol maps to the string `2>&1`
+ that is automatically inserted at the end of a command line.
-* `test`:
+ This option is rarely necessary. `$stderr` redirection was originally
+ often needed in early versions of Ceedling. Shell output stream handling
+ is now automatically handled. This option is preserved for possible edge
+ cases.
- Library files that should be injected into your tests when linking occurs.
- These can be specified as either relative or absolute paths. These files MUST
- exist when the test attempts to build.
+1. `:optional` - By default a tool you define is required for operation. This
+ means a build will be aborted if Ceedling cannot find your toolâs executable
+ in your environment. However, setting `:optional` to `true` causes this
+ check to be skipped. This is most often needed in plugin scenarios where a
+ tool is only needed if an accompanying configuration option requires it. In
+ such cases, a programmatic option available in plugin Ruby code using the
+ Ceedling class `ToolValidator` exists to process tool definitions as needed.
-* `release`:
+#### Tool element runtime substitution
- Library files that should be injected into your release when linking occurs. These
- can be specified as either relative or absolute paths. These files MUST exist when
- the release attempts to build UNLESS you are using the subprojects plugin. In that
- case, it will attempt to build that library for you as a dynamic dependency.
+To accomplish useful work on multiple files, a configured tool will most often
+require that some number of its arguments or even the executable itself change
+for each run. Consequently, every toolâs argument list and executable field
+possess two means for substitution at runtime.
-* `system`:
+Ceedling provides inline Ruby string expansion and a notation for populating
+tool elements with dynamically gathered values within the build environment.
- These libraries are assumed to be in the tool path somewhere and shouldn't need to be
- specified. The libraries added here will be injected into releases and tests. For example
- if you specify `-lm` you can include the math library. The `-l` portion is only necessary
- if the `:flag` prefix below doesn't specify it already for you other libraries.
+##### Tool element runtime substitution: Inline Ruby string expansion
-* `flag`:
+`"#{...}"`: This notation is that of the beloved
+[inline Ruby string expansion][inline-ruby-string-expansion] available in a
+variety of configuration file sections. This string expansion occurs each
+time a tool configuration is executed during a build.
- This is the method of adding an argument for each library. For example, gcc really likes
- it when you specify â-l${1}â
+##### Tool element runtime substitution: Notational substitution
-* `path_flag`:
+A Ceedling tool's other form of dynamic substitution relies on a `$` notation.
+These `$` operators can exist anywhere in a string and can be decorated in any
+way needed. To use a literal `$`, escape it as `\\$`.
- This is the method of adding an path argument for each library path. For example, gcc really
- likes it when you specify â-L \"${1}\"â
+* `$`: Simple substitution for value(s) globally available within the runtime
+ (most often a string or an array).
-Notes:
+* `${#}`: When a Ceedling tool's command line is expanded from its configured
+ representation, runs of that tool will be made with a parameter list of
+ substitution values. Each numbered substitution corresponds to a position in
+ a parameter list.
-* If you've specified your own link step, you are going to want to add ${4} to your argument
-list in the place where library files should be added to the command call. For gcc, this is
-often the very end. Other tools may vary.
+ * In the case of a compiler `${1}` will be a C code file path, and `$
+ {2}` will be the file path of the resulting object file.
+ * For a linker `${1}` will be an array of object files to link, and `$
+ {2}` will be the resulting binary executable.
-**flags**: configure per-file compilation and linking flags
+ * For an executable test fixture `${1}` is either the binary executable
+ itself (when using a local toolchain such as GCC) or a binary input file
+ given to a simulator in its arguments.
-Ceedling tools (see later [:tools] section) are used to configure
-compilation and linking of test and source files. These tool
-configurations are a one-size-fits-all approach. Should individual files
-require special compilation or linking flags, the settings in the
-[:flags] section work in conjunction with tool definitions by way of
-argument substitution to achieve this.
+### Example `:tools` YAML blurb
-* `release`:
+```yaml
+:tools:
+ :test_compiler:
+ :executable: compiler # Exists in system search path
+ :name: 'acme test compiler'
+ :arguments:
+ - -I"${5}" # Expands to -I search paths from `:paths` section + build directive path macros
+ - -D"${6}" # Expands to all -D defined symbols from `:defines` section
+ - --network-license # Simple command line argument
+ - -optimize-level 4 # Simple command line argument
+ - "#{`args.exe -m acme.prj`}" # In-line Ruby call to shell out & build string of arguments
+ - -c ${1} # Source code input file
+ - -o ${2} # Object file output
+
+ :test_linker:
+ :executable: /programs/acme/bin/linker.exe # Full file path
+ :name: 'acme test linker'
+ :arguments:
+ - ${1} # List of object files to link
+ - -l$-lib: # In-line YAML array substitution to link in foo-lib and bar-lib
+ - foo
+ - bar
+ - -o ${2} # Binary output artifact
+
+ :test_fixture:
+ :executable: tools/bin/acme_simulator.exe # Relative file path to command line simulator
+ :name: 'acme test fixture'
+ :stderr_redirect: :win # Inform Ceedling what model of $stderr capture to use
+ :arguments:
+ - -mem large # Simple command line argument
+ - -f "${1}" # Binary executable input file for simulator
+```
- [:compile] or [:link] flags for release build
+#### `:tools` example blurb notes
-* `test`:
+* `${#}` is a replacement operator expanded by Ceedling with various
+ strings, lists, etc. assembled internally. The meaning of each
+ number is specific to each predefined default tool (see
+ documentation above).
- [:compile] or [:link] flags for test build
+* See [search path order][##-search-path-order] to understand how
+ the `-I"${5}"` term is expanded.
-Notes:
+* At present, `$stderr` redirection is primarily used to capture
+ errors from test fixtures so that they can be displayed at the
+ conclusion of a test run. For instance, if a simulator detects
+ a memory access violation or a divide by zero error, this notice
+ might go unseen in all the output scrolling past in a terminal.
-* Ceedling works with the [:release] and [:test] build contexts
- as-is; plugins can add additional contexts
+* The built-in preprocessing tools _can_ be overridden with
+ non-GCC equivalents. However, this is highly impractical to do
+ as preprocessing features are quite dependent on the
+ idiosyncrasies and features of the GCC toolchain.
-* Only [:compile] and [:link] are recognized operations beneath
- a context
+#### Example Test Compiler Tooling
-* File specifiers do not include a path or file extension
+Resulting compiler command line construction from preceding example
+`:tools` YAML blurbâŠ
-* File specifiers are case sensitive (must match original file
- name)
+```shell
+> compiler -I"/usr/includeâ -Iâproject/testsâ
+ -I"project/tests/supportâ -Iâproject/sourceâ -Iâproject/includeâ
+ -DTEST -DLONG_NAMES -network-license -optimize-level 4 arg-foo
+ arg-bar arg-baz -c project/source/source.c -o
+ build/tests/out/source.o
+```
-* File specifiers do support regular expressions if encased in quotes
+Notes on compiler tooling example:
-* '`*`' is a special (optional) file specifier to provide flags
- to all files not otherwise specified
+- `arg-foo arg-bar arg-baz` is a fabricated example string collected from
+ `$stdout` as a result of shell execution of `args.exe`.
+- The `-c` and `-o` arguments are fabricated examples simulating a single
+ compilation step for a test; `${1}` & `${2}` are single files.
+#### Example Test Linker Tooling
-Example [:flags] YAML blurb
+Resulting linker command line construction from preceding example
+`:tools` YAML blurbâŠ
-```yaml
-:flags:
- :release:
- :compile:
- :main: # add '-Wall' to compilation of main.c
- - -Wall
- :fan: # add '--O2' to compilation of fan.c
- - --O2
- :'test_.+': # add '-pedantic' to all test-files
- - -pedantic
- :*: # add '-foo' to compilation of all files not main.c or fan.c
- - -foo
- :test:
- :compile:
- :main: # add '--O1' to compilation of main.c as part of test builds including main.c
- - --O1
- :link:
- :test_main: # add '--bar --baz' to linking of test_main.exe
- - --bar
- - --baz
+```shell
+> \programs\acme\bin\linker.exe thing.o unity.o
+ test_thing_runner.o test_thing.o mock_foo.o mock_bar.o -lfoo-lib
+ -lbar-lib -o build\tests\out\test_thing.exe
```
-**import**: Load additional config files
-
-In some cases it is nice to have config files (project.yml, options files) which can
-load other config files, for commonly re-used definitions (target processor,
-common code modules, etc).
+Notes on linker tooling example:
-These can be recursively nested, the included files can include other files.
+- In this scenario `${1}` is an array of all the object files needed to
+ link a test fixture executable.
-To import config files, either provide an array of files to import, or use hashes to set imports. The former is useful if you do not anticipate needing to replace a given file for different configurations (project: or options:). If you need to replace/remove imports based on different configuration files, use the hashed version. The two methods cannot be mixed in the same .yml.
+#### Example Test Fixture Tooling
-Example [:import] YAML blurb using array
+Resulting test fixture command line construction from preceding example
+`:tools` YAML blurbâŠ
-```yaml
-:import:
- - path/to/config.yml
- - path/to/another/config.yml
+```shell
+> tools\bin\acme_simulator.exe -mem large -f "build\tests\out\test_thing.bin 2>&1â
```
-Example [:import] YAML blurb using hashes
-```yaml
-:import:
- :configA: path/to/config.yml
- :configB: path/to/another/config.yml
-```
+Notes on test fixture tooling example:
+1. `:executable` could have simply been `${1}` if we were compiling
+ and running native executables instead of cross compiling. That is,
+ if the output of the linker runs on the host system, then the test
+ fixture _is_ `${1}`.
+1. Weâre using `$stderr` redirection to allow us to capture simulator error
+ messages to `$stdout` for display at the run's conclusion.
-Ceedling sets values for a subset of CMock settings. All CMock
-options are available to be set, but only those options set by
-Ceedling in an automated fashion are documented below. See CMock
-documentation.
+### Ceedling tool modification shortcuts
-**cmock**: configure CMock's code generation options and set symbols used to modify CMock's compiled features
-Ceedling sets values for a subset of CMock settings. All CMock options are available to be set, but only those options set by Ceedling in an automated fashion are documented below. See CMock documentation.
+Sometimes Ceedlingâs default tool defininitions are _this close_ to being just
+what you need. But, darn, you need one extra argument on the command line, or
+you just need to hack the tool executable. Youâd love to get away without
+overriding an entire tool definition just in order to tweak it.
-* `enforce_strict_ordering`:
+We got you.
- Tests fail if expected call order is not same as source order
+#### Ceedling tool executable replacement
- **Default**: TRUE
+Sometimes you need to do some sneaky stuff. We get it. This feature lets you
+replace the executable of a tool definition â including an internal default â
+with your own.
-* `mock_path`:
+To use this shortcut, simply add a configuration section to your project file at
+the top-level, `:tools_` âł `:executable`. Of course, you can
+combine this with the following modification option in a single block for the
+tool. Executable replacement can make use of
+[inline Ruby string expansion][inline-ruby-string-expansion].
- Path for generated mocks
+See the list of tool names at the beginning of the `:tools` documentation to
+identify the named options. Plugins can also include their own tool definitions
+that can be modified with this same option.
- **Default**: /tests/mocks
+This example YAML...
-* `defines`:
+```yaml
+:tools_test_compiler:
+ :executable: foo
+```
- List of conditional compilation symbols used to configure CMock's
- compiled features. See CMock documentation to understand available
- options. No symbols must be set unless defaults are inappropriate for
- your specific environment. All symbols are used only by Ceedling to
- compile CMock C code; contents of [:defines] are ignored by CMock's
- Ruby code when instantiated.
+... will produce the following:
- **Default**: `[]` (empty)
+```shell
+ > foo
+```
-* `verbosity`:
+#### Ceedling tool arguments addition shortcut
- If not set, defaults to Ceedling's verbosity level
+Now, this little feature only allows you to add arguments to the end of a tool
+command line. Not the beginning. And, you canât remove arguments with this
+option.
-* `plugins`:
+Further, this little feature is a blanket application across all uses of a tool.
+If you need fine-grained control of command line flags in build steps per test
+executable, please see the [`:flags` configuration documentation][flags].
- If [:project][:use_exceptions] is enabled, the internal plugins list is pre-populated with 'cexception'.
+To use this shortcut, simply add a configuration section to your project file at
+the top-level, `:tools_` âł `:arguments`. Of course, you can
+combine this with the preceding modification option in a single block for the
+tool.
- Whether or not you have included [:cmock][:plugins] in your
- configuration file, Ceedling automatically adds 'cexception' to the
- plugin list if exceptions are enabled. To add to the list Ceedling
- provides CMock, simply add [:cmock][:plugins] to your configuration
- and specify your desired additional plugins.
+See the list of tool names at the beginning of the `:tools` documentation to
+identify the named options. Plugins can also include their own tool definitions
+that can be modified with this same hack.
- Each of the plugins have their own additional documentation.
+This example YAML...
+```yaml
+:tools_test_compiler:
+ :arguments:
+ - --flag # Add `--flag` to the end of all test C file compilation
+```
-* `includes`:
+... will produce the following (for the default executable):
+
+```shell
+ > gcc --flag
+```
- If [:cmock][:unity_helper] set, pre-populated with unity_helper file
- name (no path).
+## `:plugins` Ceedling extensions
- The [:cmock][:includes] list works identically to the plugins list
- above with regard to adding additional files to be inserted within
- mocks as #include statements.
+See the section below dedicated to plugins for more information. This section
+pertains to enabling plugins in your project configuration.
+Ceedling includes a number of built-in plugins. See the collection within
+the project at [plugins/][ceedling-plugins] or the [documentation section below](#ceedling-plugins)
+dedicated to Ceedlingâs plugins. Each built-in plugin subdirectory includes
+thorough documentation covering its capabilities and configuration options.
-The last four settings above are directly tied to other Ceedling
-settings; hence, why they are listed and explained here. The
-first setting above, [:enforce_strict_ordering], defaults
-to FALSE within CMock. It is set to TRUE by default in Ceedling
-as our way of encouraging you to use strict ordering. It's a teeny
-bit more expensive in terms of code generated, test execution
-time, and complication in deciphering test failures. However,
-it's good practice. And, of course, you can always disable it
-by overriding the value in the Ceedling YAML configuration file.
+_Note_: Many users find that the handy-dandy [Command Hooks plugin][command-hooks]
+is often enough to meet their needs. This plugin allows you to connect your own
+scripts and command line tools to Ceedling build steps.
+[custom-plugins]: PluginDevelopmentGuide.md
+[ceedling-plugins]: ../plugins/
+[command-hooks]: ../plugins/command_hooks/
-**cexception**: configure symbols used to modify CException's compiled features
+* `:load_paths`:
-* `defines`:
+ Base paths to search for plugin subdirectories or extra Ruby functionality.
- List of conditional compilation symbols used to configure CException's
- features in its source and header files. See CException documentation
- to understand available options. No symbols must be set unless the
- defaults are inappropriate for your specific environment.
+ Ceedling maintains the Ruby load path for its built-in plugins. This list of
+ paths allows you to add your own directories for custom plugins or simpler
+ Ruby files referenced by your Ceedling configuration options elsewhere.
**Default**: `[]` (empty)
+* `:enabled`:
-**unity**: configure symbols used to modify Unity's compiled features
+ List of plugins to be used - a plugin's name is identical to the
+ subdirectory that contains it.
-* `defines`:
+ **Default**: `[]` (empty)
- List of conditional compilation symbols used to configure Unity's
- features in its source and header files. See Unity documentation to
- understand available options. No symbols must be set unless the
- defaults are inappropriate for your specific environment. Most Unity
- defines can be easily configured through the YAML file.
+Plugins can provide a variety of added functionality to Ceedling. In
+general use, it's assumed that at least one reporting plugin will be
+used to format test results (usually `report_tests_pretty_stdout`).
- **Default**: `[]` (empty)
+If no reporting plugins are specified, Ceedling will print to `$stdout` the
+(quite readable) raw test results from all test fixtures executed.
-Example [:unity] YAML blurbs
-```yaml
-:unity: #itty bitty processor & toolchain with limited test execution options
- :defines:
- - UNITY_INT_WIDTH=16 #16 bit processor without support for 32 bit instructions
- - UNITY_EXCLUDE_FLOAT #no floating point unit
+### Example `:plugins` YAML blurb
-:unity: #great big gorilla processor that grunts and scratches
- :defines:
- - UNITY_SUPPORT_64 #big memory, big counters, big registers
- - UNITY_LINE_TYPE=\"unsigned int\" #apparently we're using really long test files,
- - UNITY_COUNTER_TYPE=\"unsigned int\" #and we've got a ton of test cases in those test files
- - UNITY_FLOAT_TYPE=\"double\" #you betcha
-```
-
-
-Notes on Unity configuration:
-
-* **Verification** - Ceedling does no verification of your configuration
- values. In a properly configured setup, your Unity configuration
- values are processed, collected together with any test define symbols
- you specify elsewhere, and then passed to your toolchain during test
- compilation. Unity's conditional compilation statements, your
- toolchain's preprocessor, and/or your toolchain's compiler will
- complain appropriately if your specified configuration values are
- incorrect, incomplete, or incompatible.
-
-* **Routing $stdout** - Unity defaults to using `putchar()` in C's
- standard library to display test results. For more exotic environments
- than a desktop with a terminal (e.g. running tests directly on a
- non-PC target), you have options. For example, you could create a
- routine that transmits a character via RS232 or USB. Once you have
- that routine, you can replace `putchar()` calls in Unity by overriding
- the function-like macro `UNITY_OUTPUT_CHAR`. Consult your toolchain
- and shell documentation. Eventhough this can also be defined in the YAML file
- most shell environments do not handle parentheses as command line arguments
- very well. To still be able to add this functionality all necessary
- options can be defined in the `unity_config.h`. Unity needs to be told to look for
- the `unity_config.h` in the YAML file, though.
-
-Example [:unity] YAML blurbs
```yaml
-:unity:
- :defines:
- - UNITY_INCLUDE_CONFIG_H
-```
+:plugins:
+ :load_paths:
+ - project/tools/ceedling/plugins # Home to your collection of plugin directories.
+ - project/support # Home to some ruby code your custom plugins share.
+ :enabled:
+ - report_tests_pretty_stdout # Nice test results at your command line.
+ - our_custom_code_metrics_report # You created a plugin to scan all code to collect
+ # line counts and complexity metrics. Its name is a
+ # subdirectory beneath the first `:load_path` entry.
-Example unity_config.h
```
-#ifndef UNITY_CONFIG_H
-#define UNITY_CONFIG_H
-#include "uart_output.h" //Helper library for your custom environment
+
-#define UNITY_INT_WIDTH 16
-#define UNITY_OUTPUT_START() uart_init(F_CPU, BAUD) //Helperfunction to init UART
-#define UNITY_OUTPUT_CHAR(a) uart_putchar(a) //Helperfunction to forward char via UART
-#define UNITY_OUTPUT_COMPLETE() uart_complete() //Helperfunction to inform that test has ended
+# Which Ceedling
-#endif
-```
+In certain scenarios you may need to run a different version of Ceedling.
+Typically, Ceedling developers need this ability. But, it could come in
+handy in certain advanced Continuous Integration build scenarios or some
+sort of version behavior comparison.
+Itâs not uncommon in Ceedling development work to have the last production
+gem installed while modifying the application code in a locally cloned
+repository. Or, you may be bouncing between local versions of Ceedling to
+troubleshoot changes.
-**tools**: a means for representing command line tools for use under
-Ceedling's automation framework
+Which Ceedling handling gives you options on what gets run.
-Ceedling requires a variety of tools to work its magic. By default,
-the GNU toolchain (`gcc`, `cpp`, `as`) are configured and ready for
-use with no additions to the project configuration YAML file.
-However, as most work will require a project-specific toolchain,
-Ceedling provides a generic means for specifying / overriding
-tools.
+## Which Ceedling background
-* `test_compiler`:
+Ceedling is usually packaged and installed as a Ruby Gem. This gem ends
+up installed in an appropriate place by the `gem` package installer.
+Inside the gem installation is the entire Ceedling project. The `ceedling`
+command line launcher lives in `bin/` while the Ceedling application lives
+in `lib/`. The code in `/bin` manages lots of startup details and base
+configuration. Ultimately, it then launches the main application code from
+`lib/`.
- Compiler for test & source-under-test code
+The features and conventions controlling _which ceedling_ dictate which
+application code the `ceedling` command line handler launches.
- - `${1}`: input source
- - `${2}`: output object
- - `${3}`: optional output list
- - `${4}`: optional output dependencies file
+_NOTE:_ If you are a developer working on the code in Ceedlingâs `bin/`
+and want to run it while a gem is installed, you must take the additional
+step of specifying the path to the `ceedling` launcher in your file system.
- **Default**: `gcc`
+In Unix-like systems, this will look like:
+`> my/ceedling/changes/bin/ceedling `.
-* `test_linker`:
+On Windows systems, you may need to run:
+`> ruby my\ceedling\changes\bin\ceedling `.
- Linker to generate test fixture executables
+## Which Ceedling options and precedence
- - `${1}`: input objects
- - `${2}`: output binary
- - `${3}`: optional output map
- - `${4}`: optional library list
- - `${5}`: optional library path list
+When Ceedling starts up, it evaluates a handful of conditions to determine
+which Ceedling location to launch.
- **Default**: `gcc`
+The following are evaluated in order:
-* `test_fixture`:
+1. Environment variable `WHICH_CEEDLING`. If this environment variable is
+ set, its value is used.
+1. Configuration entry `:project` âł `:which_ceedling`. If this is set,
+ its value is used.
+1. The path `vendor/ceedling`. If this path exists in your working
+ directory â typically because of a `--local` vendored installation at
+ project creation â its contents are used to launch Ceedling.
+1. If none of the above exist, the `ceedling` launcher defaults to using
+ the `lib/` directory next to the `bin/` directory from which the
+ `ceedling` launcher is running. In the typical case this is the default
+ gem installation.
- Executable test fixture
+_NOTE:_ Configuration entry (2) does not make sense in some scenarios.
+When running `ceedling new`, `ceedling examples`, or `ceedling example`
+there is no project file to read. Similarly, `ceedling upgrade` does not
+load a project file; it merely works with the directory structure and
+contets of a project. In these cases, the environment variable is your
+only option to set which Ceedling to launch.
- - `${1}`: simulator as executable with`${1}` as input binary file argument or native test executable
+## Which Ceedling settings
- **Default**: `${1}`
+The environment variable and configuration entry for _Which Ceedling_ can
+contain two values:
-* `test_includes_preprocessor`:
+1. The value `gem` indicates that the command line `ceedling` launcher
+ should run the application packaged alongside it in `lib/` (these
+ paths are typically found in the gem installation location).
+1. A relative or absolute path in your file system. Such a path should
+ point to the top-level directory that contains Ceedlingâs `bin/` and
+ `lib/` sub-directories.
- Extractor of #include statements
+
- - `${1}`: input source file
+# Build Directive Macros
- **Default**: `cpp`
+## Overview of Build Directive Macros
-* `test_file_preprocessor`:
+Ceedling supports a small number of build directive macros. At present,
+these macros are only for use in test files.
- Preprocessor of test files (macros, conditional compilation statements)
- - `${1}`: input source file
- - `${2}`: preprocessed output source file
+By placing these macros in your test files, you may control aspects of an
+individual test executable's build from within the test file itself.
- **Default**: `gcc`
+These macros are actually defined in Unity, but they evaluate to empty
+strings. That is, the macros do nothing and only serve as text markers for
+Ceedling to parse. But, by placing them in your test files they
+communicate instructions to Ceedling when scanned at the beginning of a
+test build.
-* `test_file_preprocessor_directives`:
+**_Notes:_**
- Preprocessor of test files to expand only conditional compilation statements,
- handle directives, but do not expand macros
+- Since these macros are defined in _unity.h_, itâs essential to
+ `#include "unity.h"` before making use of them in your test file.
+ Typically, _unity.h_ is referenced at or near the top of a test file
+ anyhow, but this is an important detail to call out.
+- **`TEST_SOURCE_FILE()` and `TEST_INCLUDE_PATH()`, new in Ceedling
+ 1.0.0, are incompatible with enclosing conditional compilation C
+ preprocessing statements.** See
+ [Ceedlingâs preprocessing documentation](#preprocessing-gotchas)
+ for more details.
- - `${1}`: input source file
- - `${2}`: not-fully preprocessed output source file
+## `TEST_SOURCE_FILE()`
- **Default**: `gcc`
+### `TEST_SOURCE_FILE()` Purpose
-* `test_dependencies_generator`:
+The `TEST_SOURCE_FILE()` build directive allows the simple injection of
+a specific source file into a test executableâs build.
- Discovers deep dependencies of source & test (for incremental builds)
+The Ceedling [convention][ceedling-conventions] of compiling and linking
+any C file that corresponds in name to an `#include`d header file does
+not always work. A given source file may not have a header file that
+corresponds directly to its name. In some specialized cases, a source
+file may not rely on a header file at all.
- - `${1}`: input source file
- - `${2}`: compiled object filepath
- - `${3}`: output dependencies file
+Attempting to `#include` a needed C source file directly is both ugly and
+can cause various build problems with duplicated symbols, etc.
- **Default**: `gcc`
+`TEST_SOURCE_FILE()` is the way to cleanly and simply add a given C file
+to the executable built from a test file. `TEST_SOURCE_FILE()` is also one
+of the best methods for adding an assembly file to the build of a given
+test executableâif assembly support is enabled for test builds.
-* `release_compiler`:
+### `TEST_SOURCE_FILE()` Usage
- Compiler for release source code
+The argument for the `TEST_SOURCE_FILE()` build directive macro is a
+single filename or filepath as a string enclosed in quotation marks. Use
+forward slashes for path separators. The filename or filepath must be
+present within Ceedlingâs source file collection.
- - `${1}`: input source
- - `${2}`: output object
- - `${3}`: optional output list
- - `${4}`: optional output dependencies file
+To understand your source file collection:
- **Default**: `gcc`
+- See the documentation for project file configuration section
+ [`:paths`](#project-paths-configuration).
+- Dump a listing your projectâs source files with the command line task
+ `ceedling files:source`.
-* `release_assembler`:
+Multiple uses of `TEST_SOURCE_FILE()` are perfectly fine. Youâll likely
+want one per line within your test file.
- Assembler for release assembly code
+### `TEST_SOURCE_FILE()` Example
- - `${1}`: input assembly source file
- - `${2}`: output object file
+```c
+/*
+ * Test file test_mycode.c to exercise functions in mycode.c.
+ */
+
+#include "unity.h" // Contains TEST_SOURCE_FILE() definition
+#include "support.h" // Needed symbols and macros
+//#include "mycode.h" // Header file corresponding to mycode.c by convention does not exist
- **Default**: `as`
+// Tell Ceedling to compile and link mycode.c as part of the test_mycode executable
+TEST_SOURCE_FILE("foo/bar/mycode.c")
-* `release_linker`:
+// --- Unit test framework calls ---
- Linker for release source code
+void setUp(void) {
+ ...
+}
- - `${1}`: input objects
- - `${2}`: output binary
- - `${3}`: optional output map
- - `${4}`: optional library list
- - `${5}`: optional library path list
+void test_MyCode_FooBar(void) {
+ ...
+}
+```
- **Default**: `gcc`
+## `TEST_INCLUDE_PATH()`
-* `release_dependencies_generator`:
+### `TEST_INCLUDE_PATH()` Purpose
- Discovers deep dependencies of source files (for incremental builds)
+The `TEST_INCLUDE_PATH()` build directive allows a header search path to
+be injected into the build of an individual test executable.
- - `${1}`: input source file
- - `${2}`: compiled object filepath
- - `${3}`: output dependencies file
+Unless you have a pretty funky C project, generally at least one search path entry
+is necessary for every test executable build. That path can come from a `:paths`
+âł `:include` entry in your project configuration or by using `TEST_INCLUDE_PATH()`
+in a test file.
- **Default**: `gcc`
+Please see [Configuring Your Header File Search Paths][header-file-search-paths]
+for an overview of Ceedlingâs options and conventions for header file search paths.
+### `TEST_INCLUDE_PATH()` Usage
-A Ceedling tool has a handful of configurable elements:
+`TEST_INCLUDE_PATH()` entries in your test file are only an additive customization.
+The path will be added to the base / common path list specified by
+`:paths` âł `:include` in the project file. If no list is specified in your project
+configuration, `TEST_INCLUDE_PATH()` entries will comprise the entire header search
+path list.
-1. [:executable] - Command line executable (required)
+The argument for the `TEST_INCLUDE_PATH()` build directive macro is a single
+filepath as a string enclosed in quotation marks. Use forward slashes for
+path separators.
-2. [:arguments] - List of command line arguments
- and substitutions (required)
+**_Note_**: At present, a limitation of the `TEST_INCLUDE_PATH()` build directive
+macro is that paths are relative to the working directory from which you are
+executing `ceedling`. A change to your working directory could require updates to
+the path arguments of dall instances of `TEST_INCLUDE_PATH()`.
-3. [:name] - Simple name (e.g. "nickname") of tool beyond its
- executable name (if not explicitly set then Ceedling will
- form a name from the tool's YAML entry name)
+Multiple uses of `TEST_INCLUDE_PATH()` are perfectly fine. Youâll likely want one
+per line within your test file.
-4. [:stderr_redirect] - Control of capturing $stderr messages
- {:none, :auto, :win, :unix, :tcsh}.
- Defaults to :none if unspecified; create a custom entry by
- specifying a simple string instead of any of the available
- symbols.
+[header-file-search-paths]: #configuring-your-header-file-search-paths
-5. [:background_exec] - Control execution as background process
- {:none, :auto, :win, :unix}.
- Defaults to :none if unspecified.
+### `TEST_INCLUDE_PATH()` Example
-6. [:optional] - By default a tool is required for operation, which
- means tests will be aborted if the tool is not present. However,
- you can set this to `TRUE` if it's not needed for testing.
+```c
+/*
+ * Test file test_mycode.c to exercise functions in mycode.c.
+ */
+#include "unity.h" // Contains TEST_INCLUDE_PATH() definition
+#include "somefile.h" // Needed symbols and macros
-Tool Element Runtime Substitution
----------------------------------
+// Add the following to the compiler's -I search paths used to
+// compile all components comprising the test_mycode executable.
+TEST_INCLUDE_PATH("foo/bar/")
+TEST_INCLUDE_PATH("/usr/local/include/baz/")
-To accomplish useful work on multiple files, a configured tool will most
-often require that some number of its arguments or even the executable
-itself change for each run. Consequently, every tool's argument list and
-executable field possess two means for substitution at runtime. Ceedling
-provides two kinds of inline Ruby execution and a notation for
-populating elements with dynamically gathered values within the build
-environment.
+// --- Unit test framework calls ---
-Tool Element Runtime Substitution: Inline Ruby Execution
---------------------------------------------------------
+void setUp(void) {
+ ...
+}
-In-line Ruby execution works similarly to that demonstrated for the
-[:environment] section except that substitution occurs as the tool is
-executed and not at the time the configuration file is first scanned.
+void test_MyCode_FooBar(void) {
+ ...
+}
+```
-* `#{...}`:
+
- Ruby string substitution pattern wherein the containing string is
- expanded to include the string generated by Ruby code between the
- braces. Multiple instances of this expansion can occur within a single
- tool element entry string. Note that if this string substitution
- pattern occurs at the very beginning of a string in the YAML
- configuration the entire string should be enclosed in quotes (see the
- [:environment] section for further explanation on this point).
+# Ceedling Plugins
-* `{...} `:
+Ceedling includes a number of plugins. See the collection of built-in [plugins/][ceedling-plugins]
+or consult the list with summaries and links to documentation in the subsection
+that follows. Each plugin subdirectory includes full documentation of its
+capabilities and configuration options.
- If an entire tool element string is enclosed with braces, it signifies
- that Ceedling should execute the Ruby code contained within those
- braces. Say you have a collection of paths on disk and some of those
- paths include spaces. Further suppose that a single tool that must use
- those paths requires those spaces to be escaped, but all other uses of
- those paths requires the paths to remain unchanged. You could use this
- Ceedling feature to insert Ruby code that iterates those paths and
- escapes those spaces in the array as used by the tool of this example.
+To enable built-in plugins or your own custom plugins, see the documentation for
+the `:plugins` section in Ceedling project configuation options.
-Tool Element Runtime Substitution: Notational Substitution
-----------------------------------------------------------
+Many users find that the handy-dandy [Command Hooks plugin][command-hooks]
+is often enough to meet their needs. This plugin allows you to connect your own
+scripts and tools to Ceedling build steps.
-A Ceedling tool's other form of dynamic substitution relies on a '$'
-notation. These '$' operators can exist anywhere in a string and can be
-decorated in any way needed. To use a literal '$', escape it as '\\$'.
+As mentioned, you can create your own plugins. See the [guide][custom-plugins]
+for how to create custom plugins.
-* `$`:
+[//]: # (Links in this section already defined above)
- Simple substitution for value(s) globally available within the runtime
- (most often a string or an array).
+## Ceedlingâs built-in plugins, a directory
-* `${#}`:
+### Ceedling plugin `report_tests_pretty_stdout`
- When a Ceedling tool's command line is expanded from its configured
- representation and used within Ceedling Ruby code, certain calls to
- that tool will be made with a parameter list of substitution values.
- Each numbered substitution corresponds to a position in a parameter
- list. Ceedling Ruby code expects that configured compiler and linker
- tools will contain ${1} and ${2} replacement arguments. In the case of
- a compiler ${1} will be a C code file path, and ${2} will be the file
- path of the resulting object file. For a linker ${1} will be an array
- of object files to link, and ${2} will be the resulting binary
- executable. For an executable test fixture ${1} is either the binary
- executable itself (when using a local toolchain such as gcc) or a
- binary input file given to a simulator in its arguments.
+[This plugin][report_tests_pretty_stdout] is meant to tbe the default for
+printing test results to the console. Without it, readable test results are
+still produced but are not nicely formatted and summarized.
+Plugin output includes a well-formatted list of summary statistics, ignored and
+failed tests, and any extraneous output (e.g. `printf()` statements or
+simulator memory errors) collected from executing the test fixtures.
-Example [:tools] YAML blurbs
+Alternatives to this plugin are:
+
+ * `report_tests_ide_stdout`
+ * `report_tests_gtestlike_stdout`
-```yaml
-:tools:
- :test_compiler:
- :executable: compiler #exists in system search path
- :name: 'acme test compiler'
- :arguments:
- - -I"$": COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE #expands to -I search paths
- - -I"$": COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR #expands to -I search paths
- - -D$: COLLECTION_DEFINES_TEST_AND_VENDOR #expands to all -D defined symbols
- - --network-license #simple command line argument
- - -optimize-level 4 #simple command line argument
- - "#{`args.exe -m acme.prj`}" #in-line ruby sub to shell out & build string of arguments
- - -c ${1} #source code input file (Ruby method call param list sub)
- - -o ${2} #object file output (Ruby method call param list sub)
- :test_linker:
- :executable: /programs/acme/bin/linker.exe #absolute file path
- :name: 'acme test linker'
- :arguments:
- - ${1} #list of object files to link (Ruby method call param list sub)
- - -l$-lib: #inline yaml array substitution to link in foo-lib and bar-lib
- - foo
- - bar
- - -o ${2} #executable file output (Ruby method call param list sub)
- :test_fixture:
- :executable: tools/bin/acme_simulator.exe #relative file path to command line simulator
- :name: 'acme test fixture'
- :stderr_redirect: :win #inform Ceedling what model of $stderr capture to use
- :arguments:
- - -mem large #simple command line argument
- - -f "${1}" #binary executable input file to simulator (Ruby method call param list sub)
-```
+Both of the above write to the console test results with a format that is useful
+to IDEs generally in the case of the former, and GTest-aware reporting tools in
+the case of the latter.
-Resulting command line constructions from preceding example [:tools] YAML blurbs
+[report_tests_pretty_stdout]: ../plugins/report_tests_pretty_stdout
- > compiler -I"/usr/includeâ -Iâproject/testsâ
- -I"project/tests/supportâ -Iâproject/sourceâ -Iâproject/includeâ
- -DTEST -DLONG_NAMES -network-license -optimize-level 4 arg-foo
- arg-bar arg-baz -c project/source/source.c -o
- build/tests/out/source.o
+### Ceedling plugin `report_tests_ide_stdout`
-[notes: (1.) "arg-foo arg-bar arg-baz" is a fabricated example
-string collected from $stdout as a result of shell execution
-of args.exe
-(2.) the -c and -o arguments are
-fabricated examples simulating a single compilation step for
-a test; ${1} & ${2} are single files]
+[This plugin][report_tests_ide_stdout] prints to the console test results
+formatted similarly to `report_tests_pretty_stdout` with one key difference.
+This plugin's output is formatted such that an IDE executing Ceedling tasks can
+recognize file paths and line numbers in test failures, etc.
- > \programs\acme\bin\linker.exe thing.o unity.o
- test_thing_runner.o test_thing.o mock_foo.o mock_bar.o -lfoo-lib
- -lbar-lib -o build\tests\out\test_thing.exe
+This plugin's formatting is often recognized in an IDE's build window and
+automatically linked for file navigation. With such output, you can select a
+test result in your IDE's execution window and jump to the failure (or ignored
+test) in your test file (more on using [IDEs] with Ceedling, Unity, and
+CMock).
-[note: in this scenario ${1} is an array of all the object files
-needed to link a test fixture executable]
+If enabled, this plugin should be used in place of
+`report_tests_pretty_stdout`.
- > tools\bin\acme_simulator.exe -mem large -f "build\tests\out\test_thing.bin 2>&1â
+[report_tests_ide_stdout]: ../plugins/report_tests_ide_stdout
-[note: (1.) :executable could have simply been ${1} - if we were compiling
-and running native executables instead of cross compiling (2.) we're using
-$stderr redirection to allow us to capture simulator error messages to
-$stdout for display at the run's conclusion]
+[IDEs]: https://www.throwtheswitch.org/ide
+### Ceedling plugin `report_tests_teamcity_stdout`
-Notes:
+[TeamCity] is one of the original Continuous Integration server products.
-* The upper case names are Ruby global constants that Ceedling
- builds
+[This plugin][report_tests_teamcity_stdout] processes test results into TeamCity
+service messages printed to the console. TeamCity's service messages are unique
+to the product and allow the CI server to extract build steps, test results,
+and more from software builds if present.
-* "COLLECTION_" indicates that Ceedling did some work to assemble
- the list. For instance, expanding path globs, combining multiple
- path globs into a convenient summation, etc.
+The output of this plugin is useful in actual CI builds but is unhelpful in
+local developer builds. See the plugin's documentation for options to enable
+this plugin only in CI builds and not in local builds.
-* At present, $stderr redirection is primarily used to capture
- errors from test fixtures so that they can be displayed at the
- conclusion of a test run. For instance, if a simulator detects
- a memory access violation or a divide by zero error, this notice
- might go unseen in all the output scrolling past in a terminal.
+[TeamCity]: https://jetbrains.com/teamcity
+[report_tests_teamcity_stdout]: ../plugins/report_tests_teamcity_stdout
-* The preprocessing tools can each be overridden with non-gcc
- equivalents. However, this is an advanced feature not yet
- documented and requires that the replacement toolchain conform
- to the same conventions used by gcc.
+### Ceedling plugin `report_tests_gtestlike_stdout`
-**Ceedling Collection Used in Compilation**:
+[This plugin][report_tests_gtestlike_stdout] collects test results and prints
+them to the console in a format that mimics [Google Test's output][gtest-sample-output].
+Google Test output is both human readable and recognized
+by a variety of reporting tools, IDEs, and Continuous Integration servers.
-* `COLLECTION_PATHS_TEST`:
+If enabled, this plugin should be used in place of
+`report_tests_pretty_stdout`.
- All test paths
+[gtest-sample-output]:
+https://subscription.packtpub.com/book/programming/9781800208988/11/ch11lvl1sec31/controlling-output-with-google-test
+[report_tests_gtestlike_stdout]: ../plugins/report_tests_gtestlike_stdout
-* `COLLECTION_PATHS_SOURCE`:
+### Ceedling plugin `command_hooks`
- All source paths
+[This plugin][command-hooks] provides a simple means for connecting Ceedlingâs build events to
+Ceedling tool entries you define in your project configuration (see `:tools`
+documentation). In this way you can easily connect your own scripts or command
+line utilities to build steps without creating an entire custom plugin.
-* `COLLECTION_PATHS_INCLUDE`:
+[//]: # (Links defined in a previous section)
- All include paths
+### Ceedling plugin `module_generator`
-* `COLLECTION_PATHS_SUPPORT`:
+A pattern emerges in day-to-day unit testing, especially in the practice of
+Test- Driven Development. Again and again, one needs a triplet of a source
+file, header file, and test file â scaffolded in such a way that they refer to
+one another.
- All test support paths
+[This plugin][module_generator] allows you to save precious minutes by creating
+these templated files for you with convenient command line tasks.
-* `COLLECTION_PATHS_SOURCE_AND_INCLUDE`:
+[module_generator]: ../plugins/module_generator
- All source and include paths
+### Ceedling plugin `fff`
-* `COLLECTION_PATHS_SOURCE_INCLUDE_VENDOR`:
+The Fake Function Framework, [FFF], is an alternative approach to [test doubles][test-doubles]
+than that used by CMock.
- All source and include paths + applicable vendor paths (e.g.
- CException's source path if exceptions enabled)
+[This plugin][FFF-plugin] replaces Ceedling generation of CMock-based mocks and
+stubs in your tests with FFF-generated fake functions instead.
-* `COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE`:
+[//]: # (FFF links are defined up in an introductory section explaining CMock)
- All test toolchain include paths
+### Ceedling plugin `beep`
-* `COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE`:
+[This plugin][beep] provides a simple audio notice when a test build completes suite
+execution or fails due to a build error. It is intended to support developers
+running time-consuming test suites locally (i.e. in the background).
- All test, source, and include paths
+The plugin provides a variety of options for emitting audio notificiations on
+various desktop platforms.
-* `COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR`:
+[beep]: ../plugins/beep
- All test, source, include, and applicable vendor paths (e.g. Unity's
- source path plus CMock and CException's source paths if mocks and
- exceptions are enabled)
+### Ceedling plugin `bullseye`
-* `COLLECTION_PATHS_RELEASE_TOOLCHAIN_INCLUDE`:
+[This plugin][bullseye-plugin] adds additional Ceedling tasks to execute tests
+with code coverage instrumentation provided by the commercial code coverage
+tool provided by [Bullseye]. The Bullseye tool provides visualization and report
+generation from the coverage results produced by an instrumented test suite.
- All release toolchain include paths
+[bullseye]: http://www.bullseye.com
+[bullseye-plugin]: ../plugins/bullseye
-* `COLLECTION_DEFINES_TEST_AND_VENDOR`:
+### Ceedling plugin `gcov`
- All symbols specified in [:defines][:test] + symbols defined for
- enabled vendor tools - e.g. [:unity][:defines], [:cmock][:defines],
- and [:cexception][:defines]
+[This plugin][gcov-plugin] adds additional Ceedling tasks to execute tests with GNU code
+coverage instrumentation. Coverage reports of various sorts can be generated
+from the coverage results produced by an instrumented test suite.
-* `COLLECTION_DEFINES_RELEASE_AND_VENDOR`:
+This plugin manages the use of up to three coverage reporting tools. The GNU
+[gcov] tool provides simple coverage statitics to the console as well as to the
+other supported reporting tools. Optional Python-based [GCovr] and .Net-based
+[ReportGenerator] produce fancy coverage reports in XML, JSON, HTML, etc.
+formats.
- All symbols specified in [:defines][:release] plus symbols defined by
-[:cexception][:defines] if exceptions are enabled
+[gcov-plugin]: ../plugins/gcov
+[gcov]: http://gcc.gnu.org/onlinedocs/gcc/Gcov.html
+[GCovr]: https://www.gcovr.com/
+[ReportGenerator]: https://reportgenerator.io
+### Ceedling plugin `report_tests_log_factory`
-Notes:
+[This plugin][report_tests_log_factory] produces any or all of three useful test
+suite reports in JSON, JUnit, or CppUnit format. It further provides a
+mechanism for users to create their own custom reports with a small amount of
+custom Ruby rather than a full plugin.
-* Other collections exist within Ceedling. However, they are
- only useful for advanced features not yet documented.
+[report_tests_log_factory]: ../plugins/report_tests_log_factory
-* Wherever multiple path lists are combined for use Ceedling prioritizes
- path groups as follows: test paths, support paths, source paths, include
- paths.
- This can be useful, for instance, in certain testing scenarios
- where we desire Ceedling or the compiler to find a stand-in header file
- before the actual source header file of the same name.
+### Ceedling plugin `report_build_warnings_log`
+[This plugin][report_build_warnings_log] scans the output of build tools for console
+warning notices and produces a simple text file that collects all such warning
+messages.
-**plugins**: Ceedling extensions
+[report_build_warnings_log]: ../plugins/report_build_warnings_log
-* `load_paths`:
+### Ceedling plugin `report_tests_raw_output_log`
- Base paths to search for plugin subdirectories or extra ruby functionalit
+[This plugin][report_tests_raw_output_log] captures extraneous console output
+generated by test executables â typically for debugging â to log files named
+after the test executables.
- **Default**: `[]` (empty)
+[report_tests_raw_output_log]: ../plugins/report_tests_raw_output_log
-* `enabled`:
+### Ceedling plugin `subprojects`
- List of plugins to be used - a plugin's name is identical to the
- subdirectory that contains it (and the name of certain files within
- that subdirectory)
+[This plugin][subprojects] supports subproject release builds of static
+libraries. It manages differing sets of compiler flags and linker flags that
+fit the needs of different library builds.
- **Default**: `[]` (empty)
+[subprojects]: ../plugins/subprojects
+### Ceedling plugin `dependencies`
-Plugins can provide a variety of added functionality to Ceedling. In
-general use, it's assumed that at least one reporting plugin will be
-used to format test results. However, if no reporting plugins are
-specified, Ceedling will print to `$stdout` the (quite readable) raw
-test results from all test fixtures executed.
+[This plugin][dependencies] manages release build dependencies including
+fetching those dependencies and calling a given dependenc's build process.
+Ultimately, this plugin generates the components needed by your Ceedling
+release build target.
-Example [:plugins] YAML blurb
+[dependencies]: ../plugins/dependencies
-```yaml
-:plugins:
- :load_paths:
- - project/tools/ceedling/plugins #home to your collection of plugin directories
- - project/support #maybe home to some ruby code your custom plugins share
- :enabled:
- - stdout_pretty_tests_report #nice test results at your command line
- - our_custom_code_metrics_report #maybe you needed line count and complexity metrics, so you
- #created a plugin to scan all your code and collect that info
-```
+### Ceedling plugin `compile_commands_json_db`
-* `stdout_pretty_tests_report`:
+[This plugin][compile_commands_json_db] create a [JSON Compilation Database][json-compilation-database].
+This file is useful to [any code editor or IDE][lsp-tools] that implements
+syntax highlighting, etc. by way of the LLVM projectâs [`clangd`][clangd]
+Language Server Protocol conformant language server.
- Prints to $stdout a well-formatted list of ignored and failed tests,
- final test counts, and any extraneous output (e.g. printf statements
- or simulator memory errors) collected from executing the test
- fixtures. Meant to be used with runs at the command line.
+[compile_commands_json_db]: ../plugins/compile_commands_json_db
+[lsp-tools]: https://microsoft.github.io/language-server-protocol/implementors/tools/
+[clangd]: https://clangd.llvm.org
+[json-compilation-database]: https://clang.llvm.org/docs/JSONCompilationDatabase.html
-* `stdout_ide_tests_report`:
+
- Prints to $stdout simple test results formatted such that an IDE
- executing test-related Rake tasks can recognize file paths and line
- numbers in test failures, etc. Thus, you can click a test result in
- your IDE's execution window and jump to the failure (or ignored test)
- in your test file (obviously meant to be used with an [IDE like
- Eclipse][ide], etc).
+# Global Collections
- [ide]: http://throwtheswitch.org/white-papers/using-with-ides.html
+Collections are Ruby arrays and Rake FileLists (that act like
+arrays). Ceedling did work to populate and assemble these by
+processing the project file, using internal knowledge,
+expanding path globs, etc. at startup.
-* `xml_tests_report`:
+Collections are globally available Ruby constants. These
+constants are documented below. Collections are also available
+via accessors on the `Configurator` object (same names but all
+lower case methods).
- Creates an XML file of test results in the xUnit format (handy for
- Continuous Integration build servers or as input to other reporting
- tools). Produces a file report.xml in /artifacts/tests.
+Global collections are typically used in Rakefiles, plugins,
+and Ruby scripts where the contents tend to be especially
+handy for crafting custom functionality.
-* `bullseye`:
+Once upon a time collections were a core component of Ceedling.
+As the tool has grown in sophistication and as many of its
+features now operate per test executable, the utility of and
+number of collections has dwindled. Previously, nearly all
+Ceedling actions happened in bulk and with the same
+collections used for all tasks. This is no longer true.
- Adds additional Rake tasks to execute tests with the commercial code
- coverage tool provided by [Bullseye][]. See readme.txt inside the bullseye
- plugin directory for configuration and use instructions. Note:
- Bullseye only works with certain compilers and linkers (healthy list
- of supported toolchains though).
+* `COLLECTION_PROJECT_OPTIONS`:
- [bullseye]: http://www.bullseye.com
+ All project option files with path found in the configured
+ options paths having the configured YAML file extension.
-* `gcov`:
+* `COLLECTION_ALL_TESTS`:
- Adds additional Rake tasks to execute tests with the GNU code coverage
- tool [gcov][]. See readme.txt inside the gcov directory for configuration
- and use instructions. Only works with GNU compiler and linker.
+ All files with path found in the configured test paths
+ having the configured source file extension.
- [gcov]: http://gcc.gnu.org/onlinedocs/gcc/Gcov.html
+* `COLLECTION_ALL_ASSEMBLY`:
-* `warnings_report`:
+ All files with path found in the configured source and
+ test support paths having the configured assembly file
+ extension.
- Scans compiler and linker `$stdout / $stderr` output for the word
- 'warning' (case insensitive). All code warnings (or tool warnings) are
- logged to a file warnings.log in the appropriate `/artifacts` directory (e.g. test/ for test tasks, `release/` for a
- release build, or even `bullseye/` for bullseye runs).
+* `COLLECTION_ALL_SOURCE`:
-Module Generator
-========================
-Ceedling includes a plugin called module_generator that will create a source, header and test file for you.
-There are several possibilities to configure this plugin through your project.yml to suit your project's needs.
+ All files with path found in the configured source paths
+ having the configured source file extension.
-Directory Structure
--------------------------------------------
+* `COLLECTION_ALL_HEADERS`:
-The default configuration for directory/project structure is:
-```yaml
-:module_generator:
- :project_root: ./
- :source_root: src/
- :test_root: test/
-```
-You can change these variables in your project.yml file to comply with your project's directory structure.
+ All files with path found in the configured include,
+ support, and test paths having the configured header file
+ extension.
-If you call `ceedling module:create`, it will create three files:
-1. A source file in the source_root
-2. A header file in the source_root
-3. A test file in the test_root
+* `COLLECTION_ALL_SUPPORT`:
-If you want your header file to be in another location,
-you can specify the ':inc_root:" in your project.yml file:
-```yaml
-:module_generator:
- :inc_root: inc/
-```
-The module_generator will then create the header file in your defined ':inc_root:'.
-By default, ':inc_root:' is not defined so the module_generator will use the source_root.
-
-Sometimes, your project can't be divided into a single src, inc, and test folder. You have several directories
-with sources/..., something like this for example:
-
- - myDriver
- - src
- - inc
- - test
- - myOtherDriver
- - src
- - inc
- - test
- - ...
-
-Don't worry, you don't have to manually create the source/header/test files.
-The module_generator can accept a path to create a source_root/inc_root/test_root folder with your files:
-`ceedling module:create[:]`
-
-F.e., applied to the above project structure:
-`ceedling module:create[myOtherDriver:driver]`
-This will make the module_generator run in the subdirectory 'myOtherDriver' and generate the module files
-for you in that directory. So, this command will generate the following files:
-1. A source file 'driver.c' in /myOtherDriver/
-2. A header file 'driver.h' in /myOtherDriver/ (or if specified)
-3. A test file 'test_driver.c' in /myOtherDriver/
-
-Naming
--------------------------------------------
-By default, the module_generator will generate your files in lowercase.
-`ceedling module:create[mydriver]` and `ceedling module:create[myDriver]`(note the uppercase) will generate the same files:
-1. mydriver.c
-2. mydriver.h
-3. test_mydriver.c
-
-You can configure the module_generator to use a differect naming mechanism through the project.yml:
-```yaml
-:module_generator:
- :naming: "camel"
-```
-There are other possibilities as well (bumpy, camel, snake, caps).
-Refer to the unity module generator for more info (the unity module generator is used under the hood by module_generator).
+ All files with path found in the configured test support
+ paths having the configured source file extension.
+* `COLLECTION_PATHS_INCLUDE`:
-Boilerplate header
--------------------------------------------
-There are two ways of adding a boilerplate header comment to your generated files:
-* With a defined string in the project.yml file:
+ All configured include paths.
-```yaml
-:module_generator:
- :boilerplates:
- :src: '/* This is Boilerplate code. */'
-```
+* `COLLECTION_PATHS_SOURCE`:
-Using the command **ceedling module:create[foo]** it creates the source module as follows:
+ All configured source paths.
-```c
-/* This is Boilerplate code. */
-#include "foo.h"
-```
+* `COLLECTION_PATHS_SUPPORT`:
+
+ All configured support paths.
-It would be the same for **:tst:** and **:inc:** adding its respective options.
+* `COLLECTION_PATHS_TEST`:
-* Defining an external file with boileplate code:
+ All configured test paths.
-```yml
-:module_generator:
- :boilerplate_files:
- :src: '\src_boilerplate.txt'
- :inc: '\inc_boilerplate.txt'
- :tst: '\tst_boilerplate.txt'
-```
+* `COLLECTION_PATHS_SOURCE_AND_INCLUDE`:
-For whatever file names in whichever folder you desire.
+ All configured source and include paths.
+* `COLLECTION_PATHS_SOURCE_INCLUDE_VENDOR`:
-Advanced Topics (Coming)
-========================
+ All configured source and include paths plus applicable
+ vendor paths (Unity's source path plus CMock and
+ CException's source paths if mocks and exceptions are
+ enabled).
-Modifying Your Configuration without Modifying Your Project File: Option Files & User Files
--------------------------------------------------------------------------------------------
+* `COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE`:
-Modifying your project file without modifying your project file
+ All configured test, support, source, and include paths.
-Debugging and/or printf()
--------------------------
+* `COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR`:
-When you gotta get your hands dirty...
+ All test, support, source, include, and applicable
+ vendor paths (Unity's source path plus CMock and
+ CException's source paths if mocks and exceptions are
+ enabled).
-Ceedling Plays Nice with Others - Using Ceedling for Tests Alongside Another Release Build Setup
-------------------------------------------------------------------------------------------------
+* `COLLECTION_PATHS_RELEASE_TOOLCHAIN_INCLUDE`:
-You've got options.
+ All configured release toolchain include paths.
-Adding Handy Rake Tasks for Your Project (without Fancy Pants Custom Plugins)
------------------------------------------------------------------------------
+* `COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE`:
-Add a file `rakefile.rb` at the root of your project that loads Ceedling. This
-differs whether you are using the gem version or a local Ceedling version.
+ All configured test toolchain include paths.
-Gem Version:
-```ruby
-require('ceedling')
-Ceedling.load_project
-```
+* `COLLECTION_PATHS_VENDOR`:
-Local Ceedling Version (assuming local ceedling is in `vendor/ceedling`):
-```ruby
-PROJECT_CEEDLING_ROOT = "vendor/ceedling"
-load "#{PROJECT_CEEDLING_ROOT}/lib/ceedling.rb"
-Ceedling.load_project
-```
+ Unity's source path plus CMock and CException's source
+ paths if mocks and exceptions are enabled.
-Now you simply add your rake task to the file e.g.:
-```ruby
-desc "Print hello world in sh" # Only tasks with description are listed by ceedling -T
-task :hello_world do
- sh "echo Hello World!"
-end
-```
+* `COLLECTION_VENDOR_FRAMEWORK_SOURCES`:
-The task can now be called with: `ceedling hello_world`
+ Unity plus CMock, and CException's .c filenames (without
+ paths) if mocks and exceptions are enabled.
-Working with Non-Desktop Testing Environments
----------------------------------------------
+* `COLLECTION_RELEASE_BUILD_INPUT`:
-For those crazy platforms lacking command line simulators and for which
-cross-compiling on the desktop just ain't gonna get it done.
+ * All files with path found in the configured source
+ paths having the configured source file extension.
+ * If exceptions are enabled, the source files for
+ CException.
+ * If assembly support is enabled, all assembly files
+ found in the configured paths having the configured
+ assembly file extension.
-Creating Custom Plugins
------------------------
+* `COLLECTION_EXISTING_TEST_BUILD_INPUT`:
+
+ * All files with path found in the configured source
+ paths having the configured source file extension.
+ * All files with path found in the configured test
+ paths having the configured source file extension.
+ * Unity's source files.
+ * If exceptions are enabled, the source files for
+ CException.
+ * If mocks are enabled, the C source files for CMock.
+ * If assembly support is enabled, all assembly files
+ found in the configured paths having the configured
+ assembly file extension.
+
+ This collection does not include .c files generated by
+ Ceedling and its supporting frameworks at build time
+ (e.g. test runners and mocks). Further, this collection
+ does not include source files added to a test
+ executable's build list with the `TEST_SOURCE_FILE()`
+ build directive macro.
+
+* `COLLECTION_RELEASE_ARTIFACT_EXTRA_LINK_OBJECTS`:
+
+ If exceptions are enabled, CException's .c filenames
+ (without paths) remapped to configured object file
+ extension.
+
+* `COLLECTION_TEST_FIXTURE_EXTRA_LINK_OBJECTS`:
+
+ All test support source filenames (without paths)
+ remapped to configured object file extension.
-Oh boy. This is going to take some explaining.
+
diff --git a/docs/Changelog.md b/docs/Changelog.md
new file mode 100644
index 000000000..8ed5e2783
--- /dev/null
+++ b/docs/Changelog.md
@@ -0,0 +1,472 @@
+# đ± Ceedling Changelog
+
+This format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+This changelog is complemented by two other documents:
+
+1. đ **[Release Notes](ReleaseNotes.md)** for announcements, education, acknowledgements, and known issues.
+1. đ **[Breaking Changes](BreakingChanges.md)** for a list of impacts to existing Ceedling projects.
+
+---
+
+# [1.0.0 pre-release] â 2024-11-28
+
+## đ Added
+
+### Parallel execution of build steps
+
+As was explained in the _[Highlights](#-Highlights)_, Ceedling can now run its internal tasks in parallel and take full advantage of your build systemâs resources. Even lacking various optimizations (see _[Known Issues](#-Known-Issues)_) builds are now often quite speedy.
+
+Enabling this speedup requires either or both of two simple configuration settings. See Ceedlingâs [documentation](CeedlingPacket.md) for `:project` âł `:compile_threads` and `:project` âł `:test_threads`.
+
+### A proper command line
+
+Ceedling now offers a full command line interface with rich help, useful order-independent option flags, and more.
+
+The existing `new`, `upgrade`, `example`, and `exampples` commands remain but have been improved. For those commands that support it, you may now specify the project file to load (see new, related mixins feature discussed elsewhere), log file to write to, exit code handling behavior, and more from the command line.
+
+Try `ceedling help` and then `ceedling help ` to get started.
+
+See the _[Release Notes](ReleaseNotes.md)_ and _[CeedlingPacket](CeedlingPacket.md)_ for more on the new and improved command line.
+
+### `TEST_INCLUDE_PATH(...)` & `TEST_SOURCE_FILE(...)`
+
+Issue [#743](https://github.com/ThrowTheSwitch/Ceedling/issues/743)
+
+Using what we are calling test build directive macros, you can now provide Ceedling certain configuration details from inside a test file.
+
+See the [documentation](CeedlingPacket.md) discussion on include paths, Ceedling conventions, and these macros to understand all the details.
+
+_Notes:_
+
+* Ceedling can preserves these test build directive macros through preprocessing of test files. However, wrapping `TEST_INCLUDE_PATH()` in conditional compilation C preprocessing statements (e.g. `#ifdef`) can produce unexpected resutls (see documentation for more).
+* Both `TEST_INCLUDE_PATH()` & `TEST_SOURCE_FILE()` can be disabled with standard C comments.
+* However, preprocessing of mockable header files can now be enabled separately (see `:project` âł `:use_test_preprocessor`).
+
+#### `TEST_INCLUDE_PATH(...)`
+
+In short, `TEST_INCLUDE_PATH()` allows you to add a header file search path to the build of the test executable in which it is found. This can mean much shorter compilation command lines and good flexibility for complicated projects. Unlike , `TEST_SOURCE_FILE()` this should _**not**_ be wrapped in conditional compilation preprocessing statements (see documentation for more).
+
+#### `TEST_SOURCE_FILE(...)`
+
+In short, `TEST_SOURCE_FILE()` allows you to be explicit as to which source C files should be compiled and linked into a test executable. Sometimes Ceedlingâs convention for matching source files with test files by way of `#include`d header files does not meet the need. This solves the problems of those scenarios. Unlike `TEST_INCLUDE_PATH()` , this test build directive _can_ be wrapped in in conditional compilation preprocessing statements (see documentation for more).
+
+### Mixins for modifying your configuration
+
+Thorough documentation on Mixins can be found in _[CeedlingPacket](CeedlingPacket.md)_.
+
+### Additional options for loading a base configuration from a project file
+
+Once upon a time, you could load a project configuration in just two simple ways â _project.yml_ in your working directory and an environment variable pointing to a different file. Those days are over.
+
+You may now:
+
+* Load your project configuration from a filepath provided at the command line.
+* Load your project configuration from an environment variable hoding a filepath.
+* Load your project configuration from the default _project.yml_ in your working directory.
+* Modify your configuration with Mixins loaded from your project file, environment variables, and/or from the command line.
+
+All the options for loading and modifying a project configuration are thoroughly documented in _[CeedlingPacket](CeedlingPacket.md))_.
+
+### Additional and improved configuration validation
+
+Ceedlingâs validation of your configuration has been significantly expanded to cover more sections and with more helpful error messages.
+
+### Broader crash detection in test suites and new backtrace abilities
+
+Previously Ceedling had a limited ability to detect and report segmentation faults and primarily only on Unix-like platforms. This has been expanded and improved to crash detection more broadly. Invalid memory accesses, stack overflows, heap errors, and branching problems can all lead to crashed test executables. Ceedling is now able to detect these across platforms and report on them appropriately.
+
+Ceedling defaults to executing this new behavior. Optionally, it can be disabled or its reporting enhanced further by enabling the use of `gdb`.
+
+See _[CeedlingPacket](CeedlingPacket.md))_ for the new `:project` âł `:use_backtrace` feature to control how much detail is extracted from a crashed test executable to help you find the cause.
+
+### More better `:flags` handling
+
+Issue [#43](https://github.com/ThrowTheSwitch/Ceedling/issues/43)
+
+Each test executable is now built as a mini project. Using improved `:flags` handling and an updated section format within Ceedlingâs project configuration, you have much better options for specifying flags presented to the various tools within your build, particulary within test builds.
+
+### More better `:defines` handling
+
+Each test executable is now built as a mini project. Using improved `:defines` handling and an updated section format within Ceedlingâs project configuration, you have much better options for specifying symbols used in your builds' compilation steps, particulary within test builds.
+
+One powerful new feature is the ability to test the same source file built differently for different tests. Imagine a source file has three different conditional compilation sections. You can now write unit tests for each of those sections without complicated gymnastics to cause your test suite to build and run properly.
+
+### Inline Ruby string expansion for `:flags` and `:defines` configuration entries
+
+Inline Ruby string expansion has been, well, expanded for use in `:flags` and `:defines` entries to complement existing such functionality in `:environment`, `:paths`, `:tools`, etc.
+
+The previously distributed documentation for inline Ruby string expansion has been collected into a single subsection within the project file documentation and improved.
+
+### `:unity` âł `:use_param_tests`
+
+Previous versions of Ceedling had limited support for enabling builds of Unityâs parameterized test cases. Multiple configuration settings were needed to enable test builds with these test case features. Now, setting this single configuration value in the `:unity` section of your Ceedling project configuration automatically assembles the correct compilation and test runner generation options.
+
+### `report_tests_log_factory` plugin
+
+This new plugin consolidates a handful of previously discrete report gernation plugins into a single plugin that also enables low-code, custom, end-user created reports.
+
+The abilities of these previously independent plugins are now supersededed by configuration options for the single, new `report_tests_log_factory` plugin:
+
+1. `junit_tests_report`
+1. `json_tests_report`
+1. `xml_tests_report`
+
+This new plugin also includes the option to generate an HTML report (see next section).
+
+### HTML tests report
+
+A community member submitted an [HTML report generation plugin](https://github.com/ThrowTheSwitch/Ceedling/pull/756/) that was not officially released before 0.32. It has been absorbed into the new `report_tests_log_factory` plugin (see previous section).
+
+### Improved Segfault Handling
+
+Segmentation faults are now reported as failures with as much details as possible instead of as build errors. If `gdb` is available, Ceedling can now even automatically highlight the source of the segfault (see section above on crash detection).
+
+### Support for assembly code in test builds with `:test_build` âł `:use_assembly`
+
+Previous versions of Ceedling included support for including assembly code in release builds. Now Ceedling can include assembly code in test builds as well.
+
+The default assembler is the GNU tool `as`. Like all other tools it may be overridden in the `:tools` section.
+
+To enable this feature, use the following in your project configuration:
+
+```yaml
+:test_build:
+ :use_assembly: TRUE
+```
+
+In order to inject assembly code files into the build of a test executable after enabling test build assembly code, two conditions must be true:
+
+1. The assembly files must be visible to Ceedling by way of `:paths` and `:extension` settings for assembly files â just like C code files.
+1. Ceedling must be told into which test executable build to insert a given assembly file. The easiest way to do so is with the new `TEST_SOURCE_FILE()` build directive macro â described elsewhere in this Changelog and documented in _[CeedlingPacket](CeedlingPacket.md)_.
+
+When either `:test_build` âł `:use_assembly` or `:release_build` âł `:use_assembly` are enabled, Ceedlingâs command line `files:` tasks will list assembly files among the files it discovers from your project configuration. That is, you can confirm your settings for assembly code with those tasks. See _[CeedlingPacket](CeedlingPacket.md)_âs documentation for the command line.
+
+### Pretty logging output
+
+Ceedling logging now optionally includes emoji and nice Unicode characters. Ceedling will attempt to determine if your platform supports it. You can use the environment variable `CEEDLING_DECORATORS` to force the feature on or off. See the documentation for logging decorators in _[CeedlingPacket](CeedlingPacket.md)_.
+
+### Vendored license files
+
+The application commands `ceedling new` and `ceedling upgrade` at the command line provide project creation and management functions. Optionally, these commands can vendor tools and libraries locally alongside your project. These vendoring options now include license files along with the source of the vendored tools and libraries.
+
+### Additional details in Ceedling version output
+
+`ceedling version` output now includes the Git Commit short SHA in Ceedlingâs build identifier and Ceedlingâs path of origin.
+
+```
+đ± Welcome to Ceedling!
+
+ Ceedling => #.#.#-
+ ----------------------
+
+
+ Build Frameworks
+ ----------------------
+ CMock => #.#.#
+ Unity => #.#.#
+ CException => #.#.#
+```
+
+If the short SHA information is unavailable such as in local development, the SHA is omitted. The source for this string is generated and captured in the Gem at the time of Ceedlingâs automated build in CI.
+
+### Tool definition modification shortcuts expanded for `:executable`
+
+A shortcut for adding arguments to an existing tool defition already existed. The handling for this shortcut has been expanded to allow `:executable` to be redefined.
+
+```yaml
+:tools_test_compiler:
+ :executable: foo # Shell out for `foo` instead of `gcc`
+ :arguments: # Existing functionality
+ - --flag1 # Add the following at the end of existing list of command line arguments
+ - --flag2
+```
+
+### Gcov plugin: Support for `gcovr`'s `--merge-mode-functions` for v6.0+
+
+Starting with `gcovr` v6.0 (now at v7.2), report generation can encounters a fatal error if multiple coverage results exist for the same function. This is a very possible scenario with Ceedling 1.0.0 now being able to build and run the same same test executable multiple ways.
+
+Support for this option, enacted based on `gcovr`âs reported version, has been added to the Gcov plugin with a reasonable default setting.
+
+## đȘ Fixed
+
+### `:paths` and `:files` handling bug fixes and clarification
+
+Most project configurations are relatively simple, and Ceedlingâs features for collecting paths worked fine enough. However, bugs and ambiguities lurked. Further, insufficient validation left users resorting to old fashioned trial-and-error troubleshooting.
+
+Much glorious filepath and pathfile handling now abounds:
+
+* The purpose and use of `:paths` and `:files` has been clarified in both code and documentation. `:paths` are directory-oriented while `:files` are filepath-oriented.
+* [Documentation](CeedlingPacket.md) is now accurate and complete.
+* Path handling edge cases have been properly resolved (`./foo/bar` is the same as `foo/bar` but was not always processed as such).
+* Matching globs were advertised in the documentation (erroneously, incidentally) but lacked full programmatic support.
+* Ceedling now tells you if your matching patterns don't work. Unfortunately, all Ceedling can determine is if a particular pattern yielded 0 results.
+
+### Ceedlingâs `:use_test_preprocessor` and CMockâs `:treat_inlines` now work together properly
+
+This fix addresses the problem detailed in PR [#728](https://github.com/ThrowTheSwitch/Ceedling/pull/728) and related issues.
+
+CMock can optionally mock inline functions. This requires ingesting, modifying, and rewriting a source hearder file along with then mocking it. Sophisticated header files with complex macros can require that the source header file be preprocessed before CMock then processes it a second time. In previous versions of Ceedling the preprocessing steps and handoff to CMock were not working as intended. This has been fixed.
+
+### Bug fix for test runner generation
+
+Issue [#621](https://github.com/ThrowTheSwitch/Ceedling/issues/621)
+
+For certain advanced testing scenarios test runners generated by Ceedling + Unity must have the same `#include` list as that of the test file itself from which a runner is gnerated. Previous versions of Ceedling did not provide the proper list of `#include` directives to runner generation. This has been fixed.
+
+### Bug fixes for command line build tasks `files:header` and `files:support`
+
+Longstanding bugs produced duplicate and sometimes incorrect lists of header files. Similarly, support file lists were not properly expanded from globs. Both of these problems have been fixed. The `files:header` command line task has replaced the `files:include` task.
+
+### Dashed filename handling bug fix
+
+Issue [#780](https://github.com/ThrowTheSwitch/Ceedling/issues/780)
+
+In certain combinations of Ceedling features, a dash in a C filename could cause Ceedling to exit with an exception. This has been fixed.
+
+### Source filename extension handling bug fix
+
+Issue [#110](https://github.com/ThrowTheSwitch/Ceedling/issues/110)
+
+Ceedling has long had the ability to configure a source filename extension other than `.c` (`:extension` âł `:source`). However, in most circumstances this ability would lead to broken builds. Regardless of user-provided source files and filename extenion settings, Ceedlingâs supporting frameworks â Unity, CMock, and CException â all have `.c` file components. Ceedling also generates mocks and test runners with `.c` filename extensions regardless of any filename extension setting. Changing the source filename extension would cause Ceedling to miss its own core source files. This has been fixed.
+
+### Bug fixes for `gcov` plugin
+
+The most commonly reported bugs have been fixed:
+
+* `nil` references
+* Exit code issues with recent releases of `gcov`
+* Empty coverage results and related build failures
+
+### Bug fixes for `beep` plugin
+
+A handful of small bugs in using shell `echo` with the ASCII bell character have been fixed.
+
+### Which Ceedling handling includes new environment variable `WHICH_CEEDLING`
+
+A previously semi-documented feature allowed you to point to a version of Ceedling on disk to run from within your project file, `:project` âł `:which_ceedling`.
+
+This feature is primarily of use to Ceedling developers but can be useful in other specialized scenarios. See the documentation in _[CeedlingPacket](CeedlingPacket.md))_ for full deatils as this is an advanced feature.
+
+The existing feature has been improved with logging and validation as well as proper documentation. An environment variable `WHICH_CEEDLING` is now also supported. If set, this variable supersedes any other settings. In the case of `ceedling new` and `ceedling upgrade`, it is the only way to change which Ceedling is in use as a project file either does not exist for the former or is not loaded for the latter.
+
+### Ceedling now handles C files with dots in their filenames
+
+Previous versions of Ceedling made assumptions about file naming conventions â specifically that the only place a period occurred was in a filename extension. In reality, C supports the same basic filenames as any file system does. Filenames can include periods throughout their name.
+
+As an example, some legacy code includes a versioning scheme in the name itself â _foo.12.h_. Such names would previously break builds. This has been fixed.
+
+## â ïž Changed
+
+### Preprocessing improvements
+
+Issues [#806](https://github.com/ThrowTheSwitch/Ceedling/issues/806) + [#796](https://github.com/ThrowTheSwitch/Ceedling/issues/796)
+
+Preprocessing refers to expanding macros and other related code text manipulations often needed in sophisticated projects before key test suite generation steps. Without (optional) preprocessing in complicated code bases, generating test runners from test files and generating mocks from header files lead to all manner of build shenanigans.
+
+The preprocessing needed by Ceedling for sophisticated projects has always been a difficult feature to implement. The most significant reason is simply that there is no readily available cross-platform C code preprocessing tool that provides Ceedling everything it needs to accomplish this task. Even gccâs `cpp` preprocessor tool comes up short. Over time Ceedlingâs attempt at preprocessing grew more brittle and complicated as community contribturs attempted to fix it or cause it to work properly with other new features.
+
+This release of Ceedling stripped the feature back to basics and largely rewrote it. Complicated regular expressions and Ruby-generated temporary files have been eliminated. Instead, Ceedling now blends two reports from gccâs `cpp` tool and complements this with additional context. In addition, preprocessing now occurs at the right moments in the build pipeline.
+
+While this new approach is not 100% foolproof, it is far more robust and far simpler than previous attempts. Other new Ceedling features should be able to address shortcomings in edge cases.
+
+### Project file environment variable name change `CEEDLING_MAIN_PROJECT_FILE` âĄïž `CEEDLING_PROJECT_FILE`
+
+Options and support for loading a project configuration have expanded significantly, mostly notably with the addition of Mixins.
+
+The environment variable option for pointing Ceedling to a project file other than _project.yml_ in your working directory has been renamed `CEEDLING_MAIN_PROJECT_FILE` âĄïž `CEEDLING_PROJECT_FILE`.
+
+Documentation on Mixins and the new options for loading a project configuration are thoroughly documented in _[CeedlingPacket](CeedlingPacket.md))_.
+
+### Configuration defaults and configuration set up order
+
+Ceedlingâs previous handling of defaults and configuration processing order certainly worked, but it was not as proper as it could be. To oversimplify, default values were applied in an ordering that caused complications for advanced plugins and advanced users. This has been rectified. Default settings are now processed after all user configurations and plugins.
+
+### `:project` âł `:use_test_preprocessor` has new configuration options
+
+`:project` âł `:use_test_preprocessor` is no longer a binary setting (true/false). What is preprocessed can be chosen with the options `:none`, `:tests`, `:mocks`, `:all`.
+
+* `:none` maps to the previous false option (preprocessing disabled).
+* `:all` maps to the previous true option running preprpocessing for all mockable header files and test C files.
+* `:mocks` enables only preprocessing of header files that are to be mocked.
+* `:tests` enables only preprocessing of your test files.
+
+### Plugin system improvements
+
+1. The plugin subsystem has incorporated logging to trace plugin activities at high verbosity levels.
+1. Additional events have been added for test preprocessing steps (the popular and useful [`command_hooks` plugin](plugins/command_hooks/README.md) has been updated accordingly).
+1. Built-in plugins have been updated for thread-safety as Ceedling is now able to execute builds with multiple threads.
+
+### Logging improvements
+
+Logging messages are more useful. A variety of logging messages have been added throughout Ceedling builds. Message labels (e.g. `ERROR:`) are now applied automatically). Exception handling is now centralized and significantly cleans up exception messages (backtraces are available with debug verbosity).
+
+### Exit code options for test suite failures
+
+Be default Ceedling terminates with an exit code of `1` when a build succeeds but unit tests fail.
+
+A previously undocumented project configuration option `:graceful_fail` could force a Ceedling exit code of `0` upon test failures.
+
+This configuration option has moved but is now [documented](CeedlingPacket.md). It is also available as a new command line argument (`--graceful-fail`).
+
+```yaml
+:test_build:
+ :graceful_fail: TRUE
+```
+
+### Improved Segfault Handling in Test Suites
+
+Segmentation faults are now reported as failures instead of an error with as much detail as possible. See the project configuration file documentation discussing the `:project` âł `:use_backtrace` option for more!
+
+### Altered local documentation file directory structure
+
+The application commands `ceedling new` and `ceedling upgrade` at the command line provide options for local copies of documentation when creating or upgrading a project. Previous versions of Ceedling used a flat file structure for the _docs/_ directory. Ceedling now uses subdirectories to organize plugin and tool documentation within the _docs/_ directory for clearer organization and preserving original filenames.
+
+### JUnit, XML & JSON test report plugins consolidation
+
+The three previously discrete plugins listed below have been consolidated into a single new plugin, `report_tests_log_factory`:
+
+1. `junit_tests_report`
+1. `json_tests_report`
+1. `xml_tests_report`
+
+`report_tests_log_factory` is able to generate all 3 reports of the plugins it replaces, a new HTML report, and custom report formats with a small amount of user-written Ruby code (i.e. not an entire Ceedling plugun). See its [documentation](../plugins/report_tests_log_factory) for more.
+
+The report format of the previously independent `xml_tests_report` plugin has been renamed from _XML_ in all instances to _CppUnit_ as this is the specific test reporting format the former plugin and new `report_tests_log_factory` plugin outputs.
+
+In some circumstances, JUnit report generation would yield an exception in its routines for reorganizing test results (Issues [#829](https://github.com/ThrowTheSwitch/Ceedling/issues/829) & [#833](https://github.com/ThrowTheSwitch/Ceedling/issues/833)). The true source of the nil test results entries has likely been fixed but protections have also been added in JUnit report generation as well.
+
+### Improvements and changes for Gcov plugin
+
+1. Documentation has been significantly updated including a _Troubleshooting_ for common issues.
+1. Compilation with coverage now only occurs for the source files under test and no longer for all C files (i.e. coverage for unity.c, mocks, and test files that is meaningless noise has been eliminated).
+1. Coverage summaries printed to the console after `gcov:` test task runs now only concern the source files exercised instead of all source files. A final coverage tally has been restored.
+1. Coverage summaries can now be disabled.
+1. Coverage reports are now automatically generated after `gcov:` test tasks are executed. This behvaior can be disabled with a new configuration option. When enabled, a separate task is made available to trigger report generation.
+1. To maintain consistency, repports generated by `gcovr` and `reportgenerator` are written to subdirectories named for the respective tools benath the `gcov/` artifacts path.
+
+See the [gcov pluginâs documentation](plugins/gcov/README.md).
+
+### Improvements for `compile_commands_json_db` plugin
+
+1. The plugin creates a compilation database that distinguishes the same code file compiled multiple times with different configurations as part of the new test suite build structure. It has been updated to work with other Ceedling changes.
+1. Documentation has been greatly revised.
+
+### Improvements for Beep plugin
+
+1. Additional sound tools â `:tput`, `:beep`, and `:say` â have been added for more platform sound output options and fun.
+1. Documentation has been greatly revised.
+1. The plugin more properly uses looging and system shell calls.
+
+## Improvements for Command Hooks plugin
+
+In previous versions of Ceedling, the Command Hooks plugin associated tools and hooks by a naming convention within the top-level `:tools` section of your project configuration. This required some semi-ugly tool names and could lead to a rather unwieldy `:tools` list. Further, this convention also limited a hook to an association with only a single tool.
+
+Hooks are now enabled within a top-level `:command_hooks` section in your project configuration. Each hook key in this configuration block can now support one or more tools organized beneath it. As such, each hook can execute one or more tools.
+
+### Tool definition inline Ruby string expansion now happens at each execution
+
+Reaching back to the earliest days of Ceedling, tool definitions supported two slightly different string replacement options that executed at different points in a buildâs lifetime. Yeah. It was maybe not great. This has been simplfied.
+
+Only support for `#{...}` Ruby string expansion in tool definitions remains. Any such expansions are now evaluated each time a tool is executed during a build.
+
+## đ Removed
+
+### `verbosity` and `log` command line tasks have been replaced with command line switches
+
+These command line features were implemented using Rake. That is, they were Rake tasks, not command line switches, and they were subject to the peculiarities of Rake tasks. Specifically, order mattered â these tasks had to precede build tasks they were to affect â and `verbosity` required a non-standard parameter convention for numeric values.
+
+These command line tasks no longer exist. They are now proper command line flags. These are most useful (and, in the case of logging, only availble) with Ceedlingâs new `build` command line argument. The `build` command takes a list of build & plugin tasks to run. It is now complmented by `--verbosity`, `--log`, and `--logfile` flags. See the detailed help at `ceedling help build` for these.
+
+The `build` keyword is optional. That is, omitting it is allowed and operates largely equivalent to the historical Ceedling command line.
+
+The previous command line of `ceedling verbosity[4] test:all release` or `ceedling verbosity:obnoxious test:all release` can now be any of the following:
+
+* `ceedling test:all release --verbosity=obnoxious`
+* `ceedling test:all release -v 4`
+* `ceedling --verbosity=obnoxious test:all release`
+* `ceedling -v 4 test:all release`
+
+Note: In the above list Ceedling is actually executing as though `ceedling build ` were entered at the command line. It is entirely acceptable to use the full form. The above list is provided as its form is the simplest to enter and consistent with the command line conventions of previous Ceedling versions.
+
+### `options:` tasks have been removed
+
+Options files were a simple but limited way to merge configuration with your base configuration from the command line. This feature has been superseded by Ceedling Mixins.
+
+### `:import` project configuration section is no longer supported
+
+The `:import` project configuration section was a simple but limited way to merge configuration with your base configuration. This feature has been superseded by all new and more powerful Ceedling Mixins.
+
+### Test suite smart rebuilds have been temporarily removed
+
+All âsmartâ test suite rebuild features built around Rake no longer exist. That is, incremental test suite builds for only changed files are no longer possible. Any test build is a full rebuild of its components (the speed increase due to parallel build tasks more than makes up for this).
+
+These project configuration options related to smart builds are no longer recognized and likely will not return in this form:
+ - `:use_deep_dependencies`
+ - `:generate_deep_dependencies`
+ - `:auto_link_deep_dependencies`
+
+In future revisions of Ceedling, smart rebuilds will be brought back (without relying on Rake) and without a list of possibly conflicting configuation options to control related features.
+
+Note: Release builds do retain a fair amount of smart rebuild capabilities. Release builds continue to rely on Rake (for now).
+
+### Temporarily removed preprocessor support for Unityâs parameterized test case macros `TEST_CASE()` and `TEST_RANGE()`
+
+Unityâs `TEST_CASE()` and `TEST_RANGE()` continue to work but only when `:project` âł `:use_test_preprocessor` is not enabled for test files. The previous project configuration option `:use_preprocessor_directives` that preserved these and other directive macros when preprocessing is enabled is no longer recognized.
+
+`TEST_CASE()` and `TEST_RANGE()` are macros that disappear when the GNU preprocessor digests a test file. After preprocessing, these macros no longer exist in the test file that is compiled. They and some other macros are largely used as markers for advanced abilities discovered by parsing a test file rather than compiling it.
+
+In future revisions of Ceedling, support for `TEST_CASE()` and `TEST_RANGE()` when test file preprocessing is enabled will be brought back (very likely without a dedicated configuration option â hopefully, weâll get it to just work).
+
+Note: `:project` âł `:use_test_preprocessor` is no longer a binary setting (`true`/`false`). Mockable header file preprocessing can now be enabled with a `:mocks` setting while test files are left untouched by preprocessing. This should support the majority of advanced use cases for preprocessing.
+
+### Removed background task execution
+
+Background task execution for tool configurations (`:background_exec`) has been deprecated. This option was one of Ceedlingâs earliest features attempting to speed up builds within the constraints of relying on Rake. This feature has rarely, if ever, been used in practice, and other, better options exist to manage any scenario that might motivate a background task.
+
+### Removed `colour_report` plugin
+
+Colored build output and test results in your terminal is glorious. Long ago the `colour_report` plugin provided this. It was a simple plugin that hooked into Ceedling in a somewhat messy way. Its approach to coloring output was also fairly brittle. It long ago stopped coloring build output as intended. It has been removed.
+
+Ceedlingâs logging will eventually be updated to rely on a proper logging library. This will provide a number of important features along with greater speed and stability for the tool as a whole. This will also be the opportunity to add robust terminal text coloring support.
+
+### Bullseye code coverage plugin temporarily disabled
+
+The Gcov plugin has been updated and improved, but its proprietary counterpart, the [Bullseye](https://www.bullseye.com) plugin, is not presently functional. The needed fixes and updates require a software license that we do not (yet) have.
+
+### Gcov pluginâs support for deprecated features removed
+
+The configuration format for the `gcovr` utility changed when support for the `reportgenerator` utility was added. A format that accomodated a more uniform and common layout was adopted. However, support for the older, deprecated `gcovr`-only configuration was maintained. This support for the deprecated `gcovr` configuration format has been removed.
+
+Please consult the [gcov pluginâs documentation](plugins/gcov/README.md) to update any old-style `gcovr` configurations.
+
+### Gcov pluginâs `:abort_on_uncovered` option temporarily removed
+
+Like Ceedlingâs preprocessing features, the Gcov plugin had grown in features and complexity over time. The plugin had become difficult to maintain and some of its features had become user unfriendly at best and misleading at worst.
+
+The Gcov pluginâs `:abort_on_uncovered` option plus the related `:uncovered_ignore_list` option were not preserved in this release. They will be brought back after some noodling on how to make these features user friendly again.
+
+### Undocumented environment variable `CEEDLING_USER_PROJECT_FILE` support removed
+
+A previously undocumented feature for merging a second configuration via environment variable `CEEDLING_USER_PROJECT_FILE` has been removed. This feature has been superseded by the new Mixins functionality.
+
+### Tool definition inline Ruby _evaluation_ replacement removed (inline Ruby string _expansion_ remains)
+
+Reaching back to the earliest days of Ceedling, tool definitions supported two slightly different string replacement options that executed at different points in a buildâs lifetime. Yeah. It was maybe not great.
+
+Support for `{...}` Ruby evaluation in tool definitions has been removed. Support for `#{...}` Ruby string expansion in tool definitions remains.
+
+### Tool definition defaults use of environment variables
+
+Ceedlingâs internal default tool definitions no longer incorporate (undocumented) environment variable lookups.
+
+When Ceedling was very young and tool definitions were relatively simple, Ceedlingâs defaults were configured to incorporate commonly used environment variables (e.g. `CC_FLAGS`). This made sense at the time. As Ceedlingâs tool processing grew in sophistication, this convention no longer made sense for a variety of reasons. All such references have been removed.
+
+If you want to incorporate environment variables into your tool definitions, you may still do so. See the documentation for inline Ruby string exapnsion and the various options for defining or modifying a tool definition. In short, you may incorporate `"#{ENV['']}"` strings into your tooling.
+
+### Undocumented `:project` âł `:debug` has been removed
+
+This project setting existed from Ceedlingâs earliest days and was a crude stand-in for command line debug verbosity handling.
+
+It has been removed as it was rarely if ever utilized and needlessly complicated internal mechanisms for verbosity handling and project validation.
+
diff --git a/docs/PluginDevelopmentGuide.md b/docs/PluginDevelopmentGuide.md
new file mode 100644
index 000000000..64565ad9b
--- /dev/null
+++ b/docs/PluginDevelopmentGuide.md
@@ -0,0 +1,766 @@
+# Developing Plugins for Ceedling
+
+This guide walks you through the process of creating custom plugins for
+[Ceedling](https://github.com/ThrowTheSwitch/Ceedling).
+
+It is assumed that the reader has a working installation of Ceedling and some
+basic usage experience, *i.e.* project creation/configuration and running tasks.
+
+Some experience with Ruby and Rake will be helpful but not absolutely required.
+You can learn the basics as you go â often by looking at other, existing
+Ceedling plugins or by simply searching for code examples online.
+
+## Contents
+
+* [Custom Plugins Overview](#custom-plugins-overview)
+* [Plugin Conventions & Architecture](#plugin-conventions--architecture)
+ 1. [Configuration Plugin](#plugin-option-1-configuration)
+ 1. [Programmatic `Plugin` subclass](#plugin-option-2-plugin-subclass)
+ 1. [Rake Tasks Plugin](#plugin-option-3-rake-tasks)
+
+## Development Roadmap & Notes
+
+_November 28, 2024_
+
+(See Ceedling's _[release notes](ReleaseNotes.md)_ for more.)
+
+* Ceedling 0.32 marks the beginning of moving all of Ceedling away from relying
+ on Rake. New, Rake-based plugins should not be developed. Rake dependencies
+ among built-in plugins will be refactored as the transition occurs.
+* Ceedling's entire plugin architecture will be overhauled in future releases.
+ The current structure is too dependent on Rake and provides both too little
+ and too much access to Ceedling's core.
+* Certain aspects of Ceedling's plugin structure have developed organically.
+ Consistency, coherence, and usability may not be high â particularly for
+ build step hook argument hashes and test results data structures used in
+ programmatic plugins.
+* Because of iterating on Ceedling's core design and features, documentation
+ here may not always be perfectly up to date.
+
+---
+
+# Custom Plugins Overview
+
+Ceedling plugins extend Ceedling without modifying its core code. They are
+implemented in YAML and the Ruby programming language and are loaded by
+Ceedling at runtime.
+
+Plugins provide the ability to customize the behavior of Ceedling at various
+stages of a build â preprocessing, compiling, linking, building, testing, and
+reporting.
+
+See _[CeedlingPacket]_ for basic details of operation (`:plugins` configuration
+section) and for a [directory of built-in plugins][plugins-directory].
+
+[CeedlingPacket]: CeedlingPacket.md
+[plugins-directory]: CeedlingPacket.md#ceedlings-built-in-plugins-a-directory
+
+# Plugin Conventions & Architecture
+
+Plugins are enabled and configured from within a Ceedling project's YAML
+configuration file (`:plugins` section).
+
+Conventions & requirements:
+
+* Plugin configuration names, the containing directory names, and filenames
+ must:
+ * All match (i.e. identical names)
+ * Be snake_case (lowercase with connecting underscores).
+* Plugins must be organized in a containing directory (the name of the plugin
+ as used in the project configuration `:plugins` âł `:enabled` list is its
+ containing directory name).
+* A plugin's containing directory must be located in a Ruby load path. Load
+ paths may be added to a Ceedling project using the `:plugins` âł `:load_paths`
+ list.
+* Rake plugins place their Rakefiles in the root of thecontaining plugin
+ directory.
+* Programmatic plugins must contain either or both `config/` and `lib/`
+ subdirectories within their containing directories.
+* Configuration plugins must place their files within a `config/` subdirectory
+ within the plugin's containing directory.
+
+Ceedling provides 3 options to customize its behavior through a plugin. Each
+strategy is implemented with source files conforming to location and naming
+conventions. These approaches can be combined.
+
+1. Configuration (YAML & Ruby)
+1. `Plugin` subclass (Ruby)
+1. Rake tasks (Ruby)
+
+# Plugin Option 1: Configuration
+
+The configuration option, surprisingly enough, provides Ceedling configuration
+values. Configuration plugin values can supplement or override project
+configuration values.
+
+Not long after Ceedling plugins were developed the `option:` feature was added
+to Ceedling to merge in secondary configuration files. This feature is
+typically a better way to manage nultiple configurations and in many ways
+supersedes a configuration plugin.
+
+That said, a configuration plugin is more capable than the `option:` feature and
+can be appropriate in some circumstances. Further, Ceedling's configuration
+pluging abilities are often a great way to provide configuration to
+programmatic `Plugin` subclasses (Ceedling plugins options #2).
+
+## Three flavors of configuration plugins exist
+
+1. **YAML defaults.** The data of a simple YAML file is incorporated into
+ Ceedling's configuration defaults during startup.
+1. **Programmatic (Ruby) defaults.** Ruby code creates a configuration hash
+ that Ceedling incorporates into its configuration defaults during startup.
+ This provides the greatest flexibility in creating configuration values.
+1. **YAML configurations.** The data of a simple YAML file is incorporated into
+ Ceedling's configuration much like your project configuration file.
+
+## Example configuration plugin layout
+
+Project configuration file:
+
+```yaml
+:plugins:
+ :load_paths:
+ - support/plugins
+ :enabled:
+ - zoom_zap
+```
+
+Ceedling project directory sturcture:
+
+(Third flavor of configuration plugin shown.)
+
+```
+project/
+âââ project.yml
+âââ support/
+ âââ plugins/
+ âââ zoom_zap/
+ âââ config/
+ âââ zoom_zap.yml
+```
+
+## Ceedling configuration build & use
+
+Configuration is developed at startup by assembling defaults, collecting
+user-configured settings, and then populating any missing values with defaults.
+
+Defaults:
+
+1. Ceedling loads its own defaults separately from your project configuration
+1. Supporting framework defaults such as for CMock are populated into (1)
+1. Any plugin defaults are merged with (2).
+
+Final project configuration:
+
+1. Your project file is loaded and any mixins merged
+1. Supporting framework settings that depend on project configuration are populated
+1. Plugin configurations are merged with the result of (1) and (2)
+1. Defaults are populated into your project configuration
+1. Path standardization, string replacement, and related occur throughout the final
+ configuration
+
+Merging means that existing simple configuration valuees are replaced or, in the
+case of containers such as lists and hashes, values are added to. If no such
+key/value pairs already exist, they are simply inserted into the configuration.
+
+Populating means inserting a configuration value if none already exists. As an
+example, if Ceedling finds no compiler defined for test builds in your project
+configuration, it populates your configuration with its own internal tool definition.
+
+A plugin may implement its own code to use extract custom configuration from
+the Ceedling project file. See the built-in plugins for examples. For instance, the
+Beep plugin makes use of a top-level `:beep` section in project configuration. In
+such cases, it's typically wise to make use of a plugin's option for defining
+default values. Configuration handling code is greatly simplified if values are
+guaranteed to exist in some form. This elimiates a great deal of presence checking
+and related code.
+
+## Configuration Plugin Flavors
+
+### Configuration Plugin Flvaor A: YAML Defaults
+
+Naming and location convention: `/config/defaults.yml`
+
+Configuration values are defined inside a YAML file just as the Ceedling project
+configuration file.
+
+Keys and values are defined in Ceedling's âbaseâ configuration along with all
+default values Ceedling loads at startup. If a particular key/value pair is
+already set at the time the plugin attempts to set it, it will not be
+redefined.
+
+YAML values are static apart from Ceedling's ability to perform string
+substitution at configuration load time (see _[CeedlingPacket]_ for more).
+Programmatic Ruby defaults (next section) are more flexible but more
+complicated.
+
+```yaml
+# Any valid YAML is appropriate
+:key:
+ :value:
+```
+
+### Configuration Plugin Flvaor B: Programmatic (Ruby) Defaults
+
+Naming and location convention: `/config/defaults_.rb`
+
+Configuration values are defined in a Ruby hash returned by a ânakedâ function
+`get_default_config()` in a Ruby file. The Ruby file is loaded and evaluated at
+Ceedling startup. It can contain anything allowed in a Ruby script file but
+must contain the accessor function. The returned hash's top-level keys will
+live in Ceedling's configuration at the same level in the configuration
+hierarchy as a Ceedling project file's top-level keys ('top-level' refers to
+the left-most keys in the YAML, not to how âhighâ the keys are towards the top
+of the file).
+
+Keys and values are defined in Ceedling's âbaseâ configuration along with all
+default values Ceedling loads at startup. If a particular key/value pair is
+already set at the time the plugin attempts to set it, it will not be
+redefined.
+
+This configuration option is more flexible than that documented in the previous
+section as full Ruby execution is possible in creating the defaults hash.
+
+### Configuration Plugin Flvaor C: YAML Values
+
+Naming and location convention: `/config/.yml`
+
+Configuration values are defined inside a YAML file just as the Ceedling project
+configuration file.
+
+Keys and values are defined in Ceedling's âbaseâ configuration along with all
+default values Ceedling loads at startup. If a particular key/value pair is
+already set at the time the plugin attempts to set it, it will not be
+redefined.
+
+YAML values are static apart from Ceedling's ability to perform string
+substitution at configuration load time (see _[CeedlingPacket]_ for more).
+Programmatic Ruby defaults (next section) are more flexible but more
+complicated.
+
+```yaml
+# Any valid YAML is appropriate
+:key:
+ :value:
+```
+
+# Plugin Option 2: `Plugin` Subclass
+
+Naming and location conventions:
+
+* `/lib/.rb`
+* The plugin's class name must be the camelized version (a.k.a. âbumpy case")
+ of the plugin filename â `whiz_bang.rb` âĄïž `WhizBang`.
+
+This plugin option allows full programmatic ability connceted to any of a number
+of predefined Ceedling build steps.
+
+The contents of `.rb` must implement a class that subclasses
+`Plugin`, Ceedling's plugin base class.
+
+## Example `Plugin` subclass
+
+An incomplete `Plugin` subclass follows to illustate the basics.
+
+```ruby
+# whiz_bang/lib/whiz_bang.rb
+require 'ceedling/plugin'
+
+class WhizBang < Plugin
+ def setup
+ # ...
+ end
+
+ # Build step hook
+ def pre_test(test)
+ # ...
+ end
+
+ # Build step hook
+ def post_test(test)
+ # ...
+ end
+end
+```
+
+## Example programmatic plugin layout
+
+Project configuration file:
+
+```yaml
+:plugins:
+ :load_paths:
+ - support/plugins
+ :enabled:
+ - whiz_bang
+```
+
+Ceedling project directory sturcture:
+
+```
+project/
+âââ project.yml
+âââ support/
+ âââ plugins/
+ âââ whiz_bang/
+ âââ lib/
+ âââ whiz_bang.rb
+```
+
+It is possible and often convenient to add more `.rb` files to the containing
+`lib/` directory to allow good organization of plugin code. No Ceedling
+conventions exist for these supplemental code files. Only standard Ruby
+constaints exists for these filenames and content.
+
+## `Plugin` instance variables
+
+Each `Plugin` sublcass has access to the following instance variables:
+
+* `@name`
+* `@ceedling`
+
+`@name` is self explanatory. `@ceedling` is a hash containing every object
+within the Ceedling application; its keys are the filenames of the objects
+minus file extension.
+
+Objects commonly used in plugins include:
+
+* `@ceedling[:configurator]` â Project configuration
+* `@ceedling[:streaminator]` â Logging
+* `@ceedling[:reportinator]` â String formatting for logging
+* `@ceedling[:file_wrapper]` â File operations
+* `@ceedling[:plugin_reportinator]` â Various needs including gathering test
+ results
+
+## `Plugin` method `setup()`
+
+If your plugin defines this method, it will be called during plugin creation at
+Ceedling startup. It is effectively your constructor for your custom `Plugin`
+subclass.
+
+## `Plugin` hook methods `pre_` and `post_` conventions & concerns
+
+### Multi-threaded protections
+
+Because Ceedling can run build operations in multiple threads, build step hook
+handliers must be thread safe. Practically speaking, this generally requires
+a `Mutex` object `synchronize()`d around any code that writes to or reads from
+a common data structure instantiated within a plugin.
+
+A common example is collecting test results filepaths from the
+`post_test_fixture_execute()` hook. A hash or array accumulating these
+filepaths as text executables complete their runs must have appropriate
+threading protections.
+
+### Command line tool shell results
+
+Pre and post build step hooks are often called on either side of a command line
+tool operation. If a command line tool is executed for a build step (e.g. test
+compilation), the `arg_hash` will be the same for the pre and post hooks with
+one difference.
+
+In the `post_` hook, the `arg_hash` parameter will contain a `shell_result` key
+whose associated value is itself a hash with the following contents:
+
+```ruby
+{
+ :output => "", # String holding any $stdout / redirected $stderr output
+ :status => , # Ruby object of type Process::Status
+ :exit_code => , # Command line exit code (extracted from :status object)
+ :time => # Seconds elapsed for shell operation
+}
+```
+
+_**Note:**_ Test preprocessing steps are quite sophissticated and involve various
+combination of tool executions. The `post_` preprocessing hooks do not inlucde shell
+results. Future updates to Ceedlingâs plugin system will create a more robust means
+of attaching custom behaviors to test preprocessing or connecting your own preprocessing
+pipeline with toolchains other than GCC.
+
+## `Plugin` hook methods `pre_mock_preprocess(arg_hash)` and `post_mock_preprocess(arg_hash)`
+
+These methods are called before and after execution of preprocessing for header
+files to be mocked (see [CeedlingPacket] to understand preprocessing). If a
+project does not enable preprocessing or a build does not include tests, these
+are not called. This pair of methods is called a number of times equal to the
+number of mocks in a test build.
+
+The argument `arg_hash` follows the structure below:
+
+```ruby
+arg_hash = {
+ # Filepath of header file to be preprocessed on its way to being mocked
+ :header_file => "",
+ # Filepath of processed header file
+ :preprocessed_header_file => "",
+ # Filepath of tests C file the mock will be used by
+ :test => "",
+ # List of flags to be provided to `cpp` GNU preprocessor tool
+ :flags => [],
+ # List of search paths to be provided to `cpp` GNU preprocessor tool
+ :include_paths => [],
+ # List of compilation symbols to be provided to `cpp` GNU preprocessor tool
+ :defines => []
+}
+```
+
+## `Plugin` hook methods `pre_test_preprocess(arg_hash)` and `post_test_preprocess(arg_hash)`
+
+These methods are called before and after execution of test file preprocessing
+(see [CeedlingPacket] to understand preprocessing). If a project does not
+enable preprocessing or a build does not include tests, these are not called.
+This pair of methods is called a number of times equal to the number of test
+files in a test build.
+
+The argument `arg_hash` follows the structure below:
+
+```ruby
+arg_hash = {
+ # Filepath of C test file to be preprocessed on its way to being used to generate runner
+ :test_file => "",
+ # Filepath of processed tests file
+ :preprocessed_test_file => "",
+ # Filepath of tests C file the mock will be used by
+ :test => "",
+ # List of flags to be provided to `cpp` GNU preprocessor tool
+ :flags => [],
+ # List of search paths to be provided to `cpp` GNU preprocessor tool
+ :include_paths => [],
+ # List of compilation symbols to be provided to `cpp` GNU preprocessor tool
+ :defines => []
+}
+```
+
+## `Plugin` hook methods `pre_mock_generate(arg_hash)` and `post_mock_generate(arg_hash)`
+
+These methods are called before and after mock generation. If a project does not
+enable mocks or a build does not include tests, these are not called. This pair
+of methods is called a number of times equal to the number of mocks in a test
+build.
+
+The argument `arg_hash` follows the structure below:
+
+```ruby
+arg_hash = {
+ # Filepath of the header file being mocked.
+ :header_file => "",
+ # Additional context passed by the calling function.
+ # Ceedling passes the :test symbol by default while plugins may provide another
+ :context => :,
+ # Filepath of the tests C file that references the requested mock
+ :test => "",
+ # Filepath of the generated mock C code.
+ :output_path => ""
+}
+```
+
+## `Plugin` hook methods `pre_runner_generate(arg_hash)` and `post_runner_generate(arg_hash)`
+
+These methods are called before and after execution of test runner generation. A
+test runner includes all the necessary C scaffolding (and `main()` entry point)
+to call the test cases defined in a test file when a test executable runs. If a
+build does not include tests, these are not called. This pair of methods is
+called a number of times equal to the number of test files in a test build.
+
+The argument `arg_hash` follows the structure below:
+
+```ruby
+arg_hash = {
+ # Additional context passed by the calling function.
+ # Ceedling passes the :test symbol by default while plugins may provide another
+ :context => :,
+ # Filepath of the tests C file.
+ :test_file => "",
+ # Filepath of the test file to be processed (if preprocessing enabled, this is not the same as :test_file).
+ :input_file => "",
+ # Filepath of the generated tests runner file.
+ :runner_file => ""
+}
+```
+
+## `Plugin` hook methods `pre_compile_execute(arg_hash)` and `post_compile_execute(arg_hash)`
+
+These methods are called before and after source file compilation. These are
+called in both test and release builds. This pair of methods is called a number
+of times equal to the number of C files in a test or release build.
+
+The argument `arg_hash` follows the structure below:
+
+```ruby
+arg_hash = {
+ :tool => {
+ # Hash holding compiler tool elements (see CeedlingPacket)
+ },
+ # Symbol of the operation being performed, e.g. :compile, :assemble or :link
+ :operation => :,
+ # Additional context passed by the calling function.
+ # Ceedling provides :test or :release by default while plugins may provide another.
+ :context => :,
+ # Filepath of the input C file
+ :source => "",
+ # Filepath of the output object file
+ :object => "",
+ # List of flags to be provided to compiler tool
+ :flags => [],
+ # List of search paths to be provided to compiler tool
+ :search_paths => [],
+ # List of compilation symbols to be provided to compiler tool
+ :defines => [],
+ # Filepath of the listing file, e.g. .lst file
+ :list => "",
+ # Filepath of the dependencies file, e.g. .d file
+ :dependencies => ""
+}
+```
+
+## `Plugin` hook methods `pre_link_execute(arg_hash)` and `post_link_execute(arg_hash)`
+
+These methods are called before and after linking an executable. These are
+called in both test and release builds. These are called for each test
+executable and each release artifact. This pair of methods is called a number
+of times equal to the number of test files in a test build or release artifacts
+in a release build.
+
+The argument `arg_hash` follows the structure below:
+
+```ruby
+arg_hash = {
+ # Hash holding linker tool properties.
+ :tool => {
+ # Hash holding compiler tool elements (see CeedlingPacket)
+ },
+ # Additional context passed by the calling function.
+ # Ceedling provides :test or :release by default while plugins may provide another.
+ :context => :,
+ # List of object files paths being linked, e.g. .o files
+ :objects => [],
+ # List of flags to be provided to linker tool
+ :flags => [],
+ # Filepath of the output file, e.g. .out file
+ :executable => "",
+ # Filepath of the map file, e.g. .map file
+ :map => "",
+ # List of libraries to link, e.g. those passed to the (GNU) linker with -l
+ :libraries => [],
+ # List of libraries paths, e.g. the ones passed to the (GNU) linker with -L
+ :libpaths => []
+}
+```
+
+## `Plugin` hook methods `pre_test_fixture_execute(arg_hash)` and `post_test_fixture_execute(arg_hash)`
+
+These methods are called before and after running a test executable. If a build
+does not include tests, these are not called. This pair of methods is called
+for each test executable in a build (each test file is ultimately built into a
+test executable).
+
+The argument `arg_hash` follows the structure below:
+
+```ruby
+arg_hash = {
+ # Hash holding execution tool properties.
+ :tool => {
+ # Hash holding compiler tool elements (see CeedlingPacket)
+ },
+ # Additional context passed by the calling function.
+ # Ceedling provides :test or :release by default while plugins may provide another.
+ :context => :,
+ # Name of the test file minus path and extension (`test/TestIness.c` -> 'TestIness')
+ :test_name => "",
+ # Filepath of original tests C file that became the test executable
+ :test_filepath => "",
+ # Path to the tests executable file, e.g. .out file
+ :executable => "",
+ # Path to the tests result file, e.g. .pass/.fail file
+ :result_file => ""
+}
+```
+
+## `Plugin` hook methods `pre_test(test)` and `post_test(test)`
+
+These methods are called before and after performing all steps needed to run a
+test file â i.e. configure, preprocess, compile, link, run, get results, etc.
+This pair of methods is called for each test file in a test build.
+
+The argument `test` corresponds to the path of the test C file being processed.
+
+## `Plugin` hook methods `pre_release()` and `post_release()`
+
+These methods are called before and after performing all steps needed to run the
+release task â i.e. configure, preprocess, compile, link, etc.
+
+## `Plugin` hook methods `pre_build` and `post_build`
+
+These methods are called before and after executing any ceedling task â e.g:
+test, release, coverage, etc.
+
+## `Plugin` hook methods `post_error()`
+
+This method is called at the conclusion of a Ceedling build that encounters any
+error that halts the build process. To be clear, a test build with failing test
+cases is not a build error.
+
+## `Plugin` hook methods `summary()`
+
+This method is called when invoking the summary task, `ceedling summary`. This
+method facilitates logging the results of the last build without running the
+previous build again.
+
+## Validating a pluginâs tools
+
+By default, Ceedling validates configured tools at startup according to a
+simple setting within the tool definition. This works just fine for default
+core tools and options. However, in the case of plugins, tools may not be even
+relevant to a plugin's operation depending on its configurable options. It's
+a bit silly for a tool not needed by your project to fail validation if
+Ceedling can't find it in your `$PATH`. Similarly, it's irresponsible to skip
+validating a tool just because it may not be needed.
+
+Ceedling provides optional, programmatic tool validation for these cases.
+`@ceedling]:tool_validator].validate()` can be forced to ignore a tool's
+`required:` setting to validate it. In such a scenario, a plugin should
+configure its own tools as `:optional => true` but forcibly validate them at
+plugin startup if the plugin's configuration options require said tool.
+
+An example from the `gcov` plugin illustrates this.
+
+```ruby
+# Validate gcov summary tool if coverage summaries are enabled (summaries rely on the `gcov` tool)
+if summaries_enabled?( @project_config )
+ @ceedling[:tool_validator].validate(
+ tool: TOOLS_GCOV_SUMMARY, # Tool defintion as Ruby hash
+ boom: true # Ignore optional status (raise exception if invalid)
+ )
+end
+```
+
+The tool `TOOLS_GCOV_SUMMARY` is defined with a Ruby hash in the plugin code.
+It is configured with `:optional => true`. At plugin startup, configuration
+options determine if the tool is needed. It is forcibly validated if the plugin
+configuration requires it.
+
+## Collecting test results from within `Plugin` subclass
+
+Some testing-specific plugins need access to test results to do their work. A
+utility method is available for this purpose.
+
+`@ceedling[:plugin_reportinator].assemble_test_results()`
+
+This method takes as an argument a list of results filepaths. These typically
+correspond directly to the collection of test files Ceedling processed in a
+given test build. It's common for this list of filepaths to be assembled from
+the `post_test_fixture_execute` build step execution hook.
+
+The data that `assemble_test_results()` returns hss a structure as follows. In
+this example, actual results from a single, real test file are presented as
+hash/array Ruby code with comments and with some edits to reduce line length.
+
+```ruby
+{
+ # Associates each test executable (i.e. test file) with an execution run time
+ :times => {
+ "test/TestUsartModel.c" => 0.21196400001645088
+ },
+
+ # List of succeeding test cases, grouped by test file.
+ :successes => [
+ {
+ :source => {:file => "test/TestUsartModel.c", :dirname => "test", :basename => "TestUsartModel.c"},
+ :collection => [
+ # If Unity is configured to do so, it will output execution run time for each test case.
+ # Ceedling creates a zero entry if the Unity option is not enabled.
+ {:test => "testCase1", :line => 17, :message => "", :unity_test_time => 0.0},
+ {:test => "testCase2", :line => 31, :message => "", :unity_test_time => 0.0}
+ ]
+ }
+ ],
+
+ # List of failing test cases, grouped by test file.
+ :failures => [
+ {
+ :source => {:file => "test/TestUsartModel.c", :dirname => "test", :basename => "TestUsartModel.c"},
+ :collection => [
+ {:test => "testCase3", :line => 25, :message => "", :unity_test_time => 0.0}
+ ]
+ }
+ ],
+
+ # List of ignored test cases, grouped by test file.
+ :ignores => [
+ {
+ :source => {:file => "test/TestUsartModel.c", :dirname => "test", :basename => "TestUsartModel.c"},
+ :collection => [
+ {:test => "testCase4", :line => 39, :message => "", :unity_test_time => 0.0}
+ ]
+ }
+ ],
+
+ # List of strings printed to $stdout, grouped by test file.
+ :stdout => [
+ {
+ :source => {:file => "test/TestUsartModel.c", :dirname => "test", :basename => "TestUsartModel.c"},
+ # Calls to print to $stdout are outside Unity's scope, preventing attaching test file line numbers
+ :collection => [
+ "<$stdout string (e.g. printf() call)>"
+ ]
+ }
+ ],
+
+ # Test suite run stats
+ :counts => {
+ :total => 4,
+ :passed => 2,
+ :failed => 1,
+ :ignored => 1,
+ :stdout => 1},
+
+ # The sum of all test file execution run times
+ :total_time => 0.21196400001645088
+}
+```
+
+# Plugin Option 3: Rake Tasks
+
+This plugin type adds custom Rake tasks to your project that can be run with `ceedling `.
+
+Naming and location conventions: `/.rake`
+
+## Example Rake task
+
+```ruby
+# Only tasks with description are listed by `ceedling -T`
+desc "Print hello world to console"
+task :hello_world do
+ sh "echo Hello World!"
+end
+```
+
+Resulting, example command line:
+
+```shell
+ > ceedling hello_world
+ > Hello World!
+```
+
+## Example Rake plugin layout
+
+Project configuration file:
+
+```yaml
+:plugins:
+ :load_paths:
+ - support/plugins
+ :enabled:
+ - hello_world
+```
+
+Ceedling project directory sturcture:
+
+```
+project/
+âââ project.yml
+âââ support/
+ âââ plugins/
+ âââ hello_world/
+ âââ hello_world.rake
+```
\ No newline at end of file
diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md
new file mode 100644
index 000000000..8eebe9ff5
--- /dev/null
+++ b/docs/ReleaseNotes.md
@@ -0,0 +1,345 @@
+# đ± Ceedling Release Notes
+
+These release notes are complemented by two other documents:
+
+1. đȘ” **[Changelog](Changelog.md)** for a structured list of additions, fixes, changes, and removals.
+1. đ **[Breaking Changes](BreakingChanges.md)** for a list of impacts to existing Ceedling projects.
+
+---
+
+# 1.0.0 pre-release â November 28, 2024
+
+**This Ceedling release is probably the most significant since the project was first [posted to SourceForge in 2009][sourceforge].**
+
+Ceedling now runs in Ruby 3. Builds can now run much faster than previous versions because of parallelized tasks. In test suites, header file search paths, code defines, and tool run flags are now customizable per test executable. Ceedling now also offers integrated debugging options to find the cause of crashing tests.
+
+* See all the [Highlights](#-highlights) below for an overview of everything in this big release.
+* See the [Changelog](Changelog.md) for a detailed list of new features, fixes, and changes in this release.
+* Weâve included below a [project configuration cheatsheet](#-project-configuration-cheatsheet-for-100-changes) for those already familiar with Ceedling that want to understand the various configuration changes.
+
+## đŽââ ïž Avast, Breaking Changes, Ye Scallywags!
+
+**_Ahoy!_** There be plenty oâ **[breaking changes](BreakingChanges.md)** ahead too, mateys! ArrrâŠ
+
+## đŁ Shout-outs and Special Thank-Youâs
+
+A **HUGE** Thanks to the ThrowTheSwitch.org community, for continuing to use, critique, and contribute to these tools. We're making the C world a better place and we appreciate all of you!
+
+We'd like to make some quick shout-outs to some especially helpful contributions. THANK YOU!
+
+ -- Mark VanderVoord & Machael Karlesky, ThrowTheSwitch.org Project Maintainers
+
+### Sponsors of Ceedling 1.0.0
+
+ - [ThingamaByte, LLC](https://thingamabyte.com) - For continuing to nurture these projects and community with so much of their time.
+ - [Kamstrup, A/S](https://kamstrup.com) - For sponsoring and testing Ceedling's new parallel build/test support
+ - [Fraunhofer Institute for Integrated Systems and Device Technology IISB](https://iisb.fraunhofer.de) - For also sponsoring and testing Ceedling's new parallel build/test support
+ - [Peter Membrey](https://github.com/pmembrey) - For sponsoring, helping to plan, and validating Ceedling's new dependencies plugin
+
+### Major Code/Doc Contributors
+
+These individuals contributed significant features, bugfixes, and improvements. This list was generated by git, so if you feel you should be here, you're probably right. Please let us know and we're very sorry to have missed you!
+
+ - Dom Postorivo
+ - Cezary Gapinski
+ - Aaron Schlicht
+ - Tim Bates
+ - Patrick Junger
+ - Austin Glaser
+ - Ćukasz Ć»egliĆski
+ - Anthony Male
+ - Peter Membrey
+ - Laurens Miers
+ - Alejandro Rosso
+ - Tony Webb
+ - Greg Williams
+ - John Van Enk
+ - Job Vranish
+
+### Major Forum Contributors
+
+These individuals have been a huge help in answering questions and guiding newcomers on our forums. Thanks for making this a welcoming community!
+
+ - @Letme
+ - @dpostorivo
+ - @swaldhoer
+ - @CezaryGapinski
+ - @aschlicht
+
+### Also, thanks for your contributions!
+
+Hiroaki Yamazoe, Lucas Becker, Rafael Campos Las Heras, Scott Vokes, Zane D. Purvis, ĐĐ°ĐœĐžĐ»Đ° ĐĐ°Đ»ŃĐșĐŸĐČĐ”Ń, Aaron Schlicht,
+Carl-Oskar Larsson, Javier TiĂĄ, Jesper L. Nielsen, MrRedKite, Nik Krause, Rasmus Melchior Jacobsen, serjche,
+Andrei Korigodskii, Eder Clayton, Felipe Balbi, Hannes Bachl, Mike D. Lowis, Peter Horn, Rasmus Uth Pedersen,
+Simon Grossenbacher, AlexandreMarkus, André Draszik, Aurelien CHAPPUIS, Austin Yates, Ben Wainwright,
+Christopher Cichiwskyj, Crt Mori, Horacio Mijail AntĂłn Quiles, John Hutchinson, Joseph Gaudet, Julien Peyregne, KGons,
+Kalle MĂžller, Peter Kempter, Luca Cavalli, Maksim Chichikalov, Marcelo Jo, Matt Chernosky, Niall Cooling,
+Olivier C. Larocque, Patrick Little, Richard Eklycke, Serjche, Spencer Russell, Stavros Vagionitis, Steven Huang,
+Toby Mole, Tom Hotston, Yuanqing Liu, afacotti, ccarrizosa, diachini, Steven Willard
+
+## đ Project Configuration Cheatsheet for 1.0.0 Changes
+
+The following is not a complete project configuration. But, for those already familiar with Ceedling, this cheatsheet illustrates some of the important changes in this latest release of Ceedling through the lens of a project configuration.
+
+To be clear, more has changed than what is referenced in this YAML blurb. Most notably:
+
+* Ceedlingâs command line is more robust and conforms to common CLI conventions.
+* Various plugins have grown in functionality and changed in name and configuration convention.
+* Build directive macros are available that provide build customization abilities through their use in your test files.
+
+```yaml
+# Mixins are an all new feature that allow you to easily merge alternate project configurations.
+# Mixins replace a variety of other features, namely the :import project file section and option: command line task.
+# A frequent need is a base project configuration complemented by variants of projects for different flavors of the same codebase. Mixins provide the features to support these kinds of needs.
+# Mixins have few limitations as compared to the features Mixins replace.
+# Mixins can be merged from within your project configuration file (shown here), from paths in environment variables, and from command line --mixin path switches.
+# ---------------------------
+:mixins:
+ :enabled: # :enabled list supports names and filepaths
+ - enabled # Look for enabled.yml in load paths and merge if found
+ - my/mixin/cfg.yml # A full path to a configuration file to merge
+ :load_paths: # Load paths to search for mixins specified by name only in :enabled
+ - support/mixins
+
+# Importing project configuration files with :import is superseded by the more capable Mixins (above).
+# ---------------------------
+# :import:
+# - path/to/config.yml
+
+:project:
+ # Ceedling is now multi-threaded for speedy builds.
+ # The default is a single thread (setting of 1). :auto tells Ceedling to query your system and make an educated guess on a number of threads to use.
+ # Threading is broken into two categories to provide for controlling threading where build tooling and test executable tooling have different restrictions.
+ # ---------------------------
+ :compile_threads: :auto
+ :test_threads: :auto
+
+ # Ceedling's preprocessing abilities have been totally revamped to fix bugs, eliminate complexity, and improve results.
+ # Preprocessing can now be selectively applied to test files and to mockable headers using options :none, :mocks, :tests, or :all.
+ # ---------------------------
+ :use_test_preprocessor: :all
+
+ # The following configuration options have been deprecated.
+ # These are no longer available as the underlying functionality has been reimplemented with no need to configure it.
+ # If these settings remain in your configuration file, they are harmless but do zilch for you.
+ # ---------------------------
+ # :use_deep_dependencies
+ # :generate_deep_dependencies
+ # :auto_link_deep_dependencies
+
+ # Backtrace is an all new feature in Ceedling.
+ # When enabled (default is :simple), backtrace figures out which test case in a crashed test executable is exercising the bug causing you grief.
+ # If the :gdb option is enabled (and the GNU debugger is installed), Ceedling will provide you the trace to the line of code causing a test case to crash.
+ # ---------------------------
+ :use_backtrace: :simple
+
+# Complemeneting its existing abilities to build assembly code as part of a release artifact, Ceedling can now also incorporate assembly code into test builds.
+# See CeedlingPacket for full details on how to make use of this feature after enabling it.
+# In short, your assembly code will need to be findable in your project paths, and you will need to use the new test directive macro TEST_SOURCE_FILE() inside your test files to tell Ceedling which assembly file to include in the respective test executable build.
+:test_build:
+ :use_assembly: TRUE
+
+# Ceedling executables are now built as self-contained mini-projects.
+# You can now define symbols for a release build and each test executable build.
+# Symbols defined for a test executable are applied during compilation for each component of the executable.
+# The :defines section supports several syntaxes.
+# - Sophisticated matchers are available for test executable builds (shown here).
+# - Simple lists to apply flags to all files in a build step are supported for release builds (only option) and test builds.
+# See Ceedling Packet for details.
+# ---------------------------
+:defines:
+ :test:
+ :*: # Wildcard: Add '-DA' for compilation of all files for all tests
+ - A
+ :Model: # Substring: Add '-DCHOO' for compilation of all files of any test with 'Model' in its name
+ - CHOO
+ :/M(ain|odel)/: # Regex: Add '-DBLESS_YOU' for all files of any test with 'Main' or 'Model' in its name
+ - BLESS_YOU
+ :Comms*Model: # Wildcard: Add '-DTHANKS' for all files of any test that have zero or more characters
+ - THANKS # between 'Comms' and 'Model'
+
+ :release:
+ - FEATURE_X=ON # Add these two symbols to compilation of all release C files (:test supports this syntax too)
+ - PRODUCT_CONFIG_C
+
+# Ceedling executables are now built as self-contained mini-projects.
+# Flags can be specified for each build step and for each component of a build step.
+# The :flags section supports several syntaxes.
+# - Sophisticated matchers are available for test executable builds (shown here).
+# - Simple lists to apply flags to all files in a build step are supported for release builds (only option) and test builds.
+# See Ceedling Packet for details.
+# ---------------------------
+:flags:
+ :test:
+ :compile:
+ :*: # Wildcard: Add '-foo' for all files for all tests
+ - -foo
+ :Model: # Substring: Add '-Wall' for all files of any test with 'Model' in its name
+ - -Wall
+ :/M(ain|odel)/: # Regex: Add đŽââ ïž flag for all files of any test with 'Main' or 'Model' in its name
+ - -đŽââ ïž
+ :Comms*Model:
+ - --freak # Wildcard: Add your `--freak` flag for all files of any test name with zero or more
+ # characters between 'Comms' and 'Model'
+ :release:
+ :compile:
+ - -std=c99 # Add `-std=c99` to compilation of all release build C files (:test supports this syntax too)
+
+# Ceedlingâs Unity configuration now properly supports test executable builds for Unity's parameterized test cases.
+# Previously a handful of settings were required throughout a project configuration to successfully use these abilities.
+# ---------------------------
+:unity:
+ :use_param_tests: TRUE
+
+```
+
+## đ Highlights
+
+### Big Deal Highlights đ
+
+#### Ruby3
+
+Ceedling now runs in Ruby3. This latest version of Ceedling is _not_ backwards compatible with earlier versions of Ruby.
+
+#### Way faster execution with parallel build steps
+
+Previously, Ceedling builds were depth-first and limited to a single line of execution. This limitation was an artifact of how Ceedling was architected and relying on general purpose Rake for the build pipeline. Rake does, in fact, support multi-threaded builds, but, Ceedling was unable to take advantage of this. As such, builds were limited to a single line of execution no matter how many CPU resources were available.
+
+Ceedling 1.0.0 introduces a new build pipeline that batches build steps breadth-first. This means all test preprocessor steps, all compilation steps, all linking steps, etc. can benefit from concurrent and parallel execution. This speedup applies to both test suite and release builds.
+
+#### Per-test-executable configurations
+
+In previous versions of Ceedling each test executable was built with essentially the same global configuration. In the case of `#define`s and tool command line flags, individual files could be handled differently, but configuring Ceedling for doing so for all the files in any one test executable was tedious and error prone.
+
+Now Ceedling builds each test executable as a mini project where header file search paths, compilation `#define` symbols, and tool flags can be specified per test executable. That is, each file that ultimately comprises a test executable is handled with the same configuration as the other files that make up that test executable.
+
+Now you can have tests with quite different configurations and behaviors. Two tests need different mocks of the same header file? No problem. You want to test the same source file two different ways? We got you.
+
+The following new features (discussed in later sections) contribute to this new ability:
+
+- `TEST_INCLUDE_PATH(...)`. This build directive macro can be used within a test file to tell Ceedling which header search paths should be used during compilation. These paths are only used for compiling the files that comprise that test executable.
+- `:defines` handling. `#define`s are now specified for the compilation of all modules comprising a test executable. Matching is only against test file names but now includes wildcard and regular expression options.
+- `:flags` handling. Flags (e.g. `-std=c99`) are now specified for the build steps â preprocessing, compilation, and linking â of all modules comprising a test executable. Matching is only against test file names and now includes more sensible and robust wildcard and regular expression options.
+
+#### Mixins for configuration variations
+
+Ever wanted to smoosh in some extra configuration selectively? Letâs say you have different build scenarios and you'd like to run different variations of your project for them. Maybe you have core configuration that is common to all those scenarios. Previous versions of Ceedling included a handful of features that partially met these sorts of needs.
+
+All such features have been superseded by _Mixins_. Mixins are simply additional YAML that gets merged into you base project configuration. However, Mixins provide several key improvements over previous features:
+
+1. Mixins can be as little or as much configuration as you want. You could push all your configuration into mixins with a base project file including nothing but a `:mixins` section.
+1. Mixins can be specified in your project configuration, via environment variables, and from the command line. A clear order of precedence controls the order of merging. Any conflicts or duplicates are automatically resolved.
+1. Logging makes clear what proejct file and mixins are loaded and merged at startup.
+1. Like built-in plugins, Ceedling will soon come with built-in mixins available for common build scenarios.
+
+#### A proper command line
+
+Until this release, Ceedling depended on Rake for most of its command line handling. Rakeâs task conventions provide poor command line handling abilities. The core problems with Rake command line handling include:
+
+1. Only brief, limited help statements.
+1. No optional flags to modify a task â verbosity, logging, etc. were their own tasks.
+1. Complex/limited parameterization (e.g. `verbosity[3]` instead of `--verbosity normal`).
+1. Tasks are order-dependent. So, for example, `test:all verbosity[5]` changes verbosity after the tests are run.
+
+Ceedling now offers a full command line interface with rich help, useful order-independent option flags, and more.
+
+The existing `new`, `upgrade`, `example`, and `exampples` commands remain but have been improved. For those commands that support it, you may now specify the project file to load (see new, related mixins feature discussed elsewhere), log file to write to, exit code handling behavior, and more from the command line.
+
+Try `ceedling help` and then `ceedling help ` to get started.
+
+**_Important Notes on the New Command Line:_**
+
+* The new and improved features for running build tasks â loading a project file, merging mixins, verbosity handling, etc. â are documented within the application command `build` keyword. A build command line such as the following is now possible: `ceedling test:all --verbosity obnoxious --logfile my/path/build.log`. Run `ceedling help build` to learn more and definitely see the next bullet point as well.
+* The `build` keyword is assumed by Ceedling. That is, itâs optional. `ceedling test:all` is the same as `ceedling build test:all`. The `build` keyword handling tells the Ceedling application to execute the named build task dynamically generated from your project configuration.
+* In the transition to remove Rake from Ceedling, two categories of command line interactions now exist. Note this distinction in the `help` headings.
+ 1. **Application Commands** â `help`, `build`, `new`, `upgrade`, `environment`, `examples`, `example`, `dumpconfig`, and `version`. These have full help via `ceedling help ` and a variety of useful command line switches that conform to typical command line conventions.
+ 1. **Build & Plugin Tasks** â Operations dynamically generated from your project configuration. These have only summary help (listed in `ceedling help`) and work just as they previously did. Common command line tasks including `ceedling test:all` and `ceedling release` are in this category.
+
+### Medium Deal Highlights đ„
+
+#### `TEST_SOURCE_FILE(...)`
+
+In previous versions of Ceedling, a new, undocumented build directive feature was introduced. Adding a call to the macro `TEST_FILE(...)` with a C fileâs name added that C file to the compilation and linking list for a test executable.
+
+This approach was helpful when relying on a Ceedling convention was problematic. Specifically, `#include`ing a header file would cause any correspondingly named source file to be added to the build list for a test executable. This convention could cause problems if, for example, the header file defined symbols that complicated test compilation or behavior. Similarly, if a source file did not have a corresponding header file of the same name, sometimes the only option was to `#include` it directly; this was ugly and problematic in its own way.
+
+The previously undocumented build directive macro `TEST_FILE(...)` has been renamed to `TEST_SOURCE_FILE(...)` and is now [documented](CeedlingPacket.md).
+
+#### Preprocessing improvements
+
+Ceedling has been around for a number of years and has had the benefit of many contributors over that time. Preprocessing (e.g. expanding macros in test files and header files to be mocked) is quite tricky to get right but is essential for big, complicated test suites. Over Ceedlingâs long life various patches and incremental improvements have evolved in such a way that preprocessing had become quite complicated and often did the wrong thing. Much of this has been fixed and improved in this release. Considerable memory and performance improvements have been made as well.
+
+#### Test Suite Crash Handling
+
+Previously, if a test executable ran into a segmentation fault (usually caused by memory issues in the code), the entire test executable would report nothing but a simple error. This behavior has been expanded to handle any crash condition and further improved.
+
+By default, a crashed test executable is automatically rerun for each test case individually to narrow down which test case(s) caused the problem. If `gdb` is properly installed and configured the specific line that caused the crash can be reported.
+
+The `:simple` and `:gdb` options for this feature fully and correctly report each test caseâs status for a crashed test executable. Crashed test cases are counted as failures. The `:none` option does not run each test case individually. Instead, in the case of crashed test executable, it marks each test case as a failure reporting that the entire test executable crashed.
+
+See _[CeedlingPacket](CeedlingPacket.md))_ for the new `:project` âł `:use_backtrace` feature to control how much detail is extracted from a crashed test executable to help you find the cause.
+
+#### Test builds can now incorporate assembly code
+
+See the documentation for `:test_build` âł `:use_assembly` to understand how to incorporate assembly code into a given test executableâs build. This complementes Ceedlingâs existing ability to incorporate assembly code in a release artifact build.
+
+#### Configuration defaults and configuration set up order
+
+Ceedlingâs previous handling of defaults and configuration processing order certainly worked, but it was not as proper as it could be. To oversimplify, default values were applied in an ordering that caused complications for advanced plugins and advanced users. This has been rectified. Default settings are now processed after all user configurations and plugins.
+
+#### Documentation
+
+The Ceedling user guide, _[CeedlingPacket](CeedlingPacket.md)_, has been significantly revised and expanded. We will expand it further in future releases and eventually break it up into multiple documents or migrate it to a full documentation management system.
+
+Many of the plugins have received documentation updates as well.
+
+Thereâs more to be done, but Ceedlingâs documentation is more complete and accurate than itâs ever been.
+
+### Small Deal Highlights đ„
+
+- Effort has been invested across the project to improve error messages, exception handling, and exit code processing. Noisy backtraces have been relegated to the verbosity level of DEBUG as intended.
+- Logical ambiguity and functional bugs within `:paths` and `:files` configuration handling have been resolved along with updated documentation.
+- A variety of small improvements and fixes have been made throughout the plugin system and to many plugins.
+- The historically unwieldy `verbosity` command line task now comes in two flavors. The original recipe numeric parameterized version (e.g. `[4]`) exist as is. The new extra crispy recipe includes â funny enough â verbose task names `verbosity:silent`, `verbosity:errors`, `verbosity:complain`, `verbosity:normal`, `verbosity:obnoxious`, `verbosity:debug`.
+- This release marks the beginning of the end for Rake as a backbone of Ceedling. Over many years it has become clear that Rakeâs design assumptions hamper building the sorts of features Ceedlingâs users want, Rakeâs command line structure creates a messy user experience for a full application built around it, and Rakeâs quirks cause maintenance challenges. Particularly for test suites, much of Ceedlingâs (invisible) dependence on Rake has been removed in this release. Much more remains to be done, including replicating some of the abilities Rake offers.
+- This is the first ever release of Ceedling with proper release notes. Hello, there! Release notes will be a regular part of future Ceedling updates. If you haven't noticed already, this edition of the notes are detailed and quite lengthy. This is entirely due to how extensive the changes are in the 1.0.0 release. Future releases will have far shorter notes.
+- Optional Unicode and emoji decorators have been added for your output stream enjoyment. See the documentation for logging decorators in _[CeedlingPacket](CeedlingPacket.md)_.
+
+## đš Important Changes in Behavior to Be Aware Of
+
+- **Test suite build order đą.** Ceedling no longer builds each test executable one at a time. From the tasks you provide at the command line, Ceedling now collects up and batches all preprocessing steps, all mock generation, all test runner generation, all compilation, etc. Previously you would see each of these done for a single test executable and then repeated for the next executable and so on. Now, each build step happens to completion for all specified tests before moving on to the next build step.
+- **Logging output order đą.** When multi-threaded builds are enabled, logging output may not be what you expect. Progress statements may be all batched together or interleaved in ways that are misleading. The steps are happening in the correct order. How you are informed of them may be somewhat out of order.
+- **Files generated multiple times đ.** Now that each test is essentially a self-contained mini-project, some output may be generated multiple times. For instance, if the same mock is required by multiple tests, it will be generated multiple times. The same holds for compilation of source files into object files. A coming version of Ceedling will concentrate on optimizations to reuse any output that is truly identical across tests.
+- **Test suite plugin runs đđ».** Because build steps are run to completion across all the tests you specify at the command line (e.g. all the mocks for your tests are generated at one time) you may need to adjust how you depend on build steps.
+
+Together, these changes may cause you to think that Ceedling is running steps out of order or duplicating work. While bugs are always possible, more than likely, the output you see and the build ordering is expected.
+
+## đ©Œ Known Issues
+
+1. The new internal pipeline that allows builds to be parallelized and configured per-test-executable can mean a fair amount of duplication of steps. A header file may be mocked identically multiple times. The same source file may be compiled identically multiple times. The speed gains due to parallelization help make up for this. Future releases will concentrate on optimizing away duplication of build steps.
+1. While header file search paths are now customizable per executable, this currently only applies to the search paths the compiler uses. Distinguishing test files or header files of the same name in different directories for test runner and mock generation respectively continues to rely on educated guesses in Ceedling code.
+1. Any path for a C file specified with `TEST_SOURCE_FILE(...)` is in relation to **_project root_** â that is, from where you execute `ceedling` at the command line. If you move source files or change your directory structure, many of your `TEST_SOURCE_FILE(...)` calls may need to be updated. A more flexible and dynamic approach to path handling will come in a future update.
+1. Ceedlingâs many test preprocessing improvements are not presently able to preserve Unityâs special `TEST_CASE()` and `TEST_RANGE()` features. However, preprocessing of test files is much less frequently needed than preprocessing of mockable header files. Test preprocessing can now be configured to enable only one or the other. As such, these advanced Unity features can still be used in even sophisticated projects.
+
+## đ Background Knowledge
+
+### Parallel execution of build steps
+
+You may have heard that Ruby is actually only single-threaded or may know of its Global Interpreter Lock (GIL) that prevents parallel execution. To oversimplify a complicated subject, the Ruby implementations most commonly used to run Ceedling afford concurrency and true parallelism speedups but only in certain circumstances. It so happens that these circumstances are precisely the workload that Ceedling manages.
+
+âMainstreamâ Ruby implementations â not JRuby, for example â offer the following that Ceedling takes advantage of:
+
+#### Native thread context switching on I/O operations
+
+Since version 1.9, Ruby supports native threads and not only green threads. However, native threads are limited by the GIL to executing one at a time regardless of the number of cores in your processor. But, the GIL is ârelaxedâ for I/O operations.
+
+When a native thread blocks for I/O, Ruby allows the OS scheduler to context switch to a thread ready to execute. This is the original benefit of threads when they were first developed back when CPUs contained a single core and multi-processor systems were rare and special. Ceedling does a fair amount of file and standard stream I/O in its pure Ruby code. Thus, when multiple threads are enabled in the proejct configuration file, execution can speed up for these operations.
+
+#### Process spawning
+
+Rubyâs process spawning abilities have always mapped directly to OS capabilities. When a processor has multiple cores available, the OS tends to spread multiple child processes across those cores in true parallel execution.
+
+Much of Ceedlingâs workload is executing a tool â such as a compiler â in a child process. With multiple threads enabled, each thread can spawn a child process for a build tool used by a build step. These child processes can be spread across multiple cores in true parallel execution.
+
+
+[sourceforge]: https://sourceforge.net/projects/ceedling/ "Ceedlingâs public debut"
\ No newline at end of file
diff --git a/examples/blinky/project.yml b/examples/blinky/project.yml
deleted file mode 100644
index 75f453d3d..000000000
--- a/examples/blinky/project.yml
+++ /dev/null
@@ -1,101 +0,0 @@
----
-
-# Notes:
-# This is a fully tested project that demonstrates the use
-# of a timer ISR to blink the on board LED of an Arduino UNO
-:project:
- :use_exceptions: FALSE
- :use_test_preprocessor: TRUE
- :use_auxiliary_dependencies: TRUE
- :build_root: build
- :release_build: TRUE
- :test_file_prefix: test_
- :which_ceedling: gem
- :ceedling_version: '?'
-
-#You'll have to specify these
-:environment:
- - :mcu: atmega328p
- - :f_cpu: 16000000UL
- - :serial_port: COM8 #change this to the serial port you are using!!!
- - :objcopy: avr-objcopy
- # Uncomment these lines if you are using windows and don't have these tools in your path
- # - :path:
- # - C:\mingw\bin
- # - C:\WinAVR-20100110\bin
- # - C:\WinAVR-20100110\utils\bin
- # - #{ENV['PATH']}
-
-:extension:
- :executable: .bin
-
-:release_build:
- :output: blinky
-
-:paths:
- :test:
- - +:test/**
- - -:test/support
- :source:
- - src/**
- :support:
- - test/support
-
-:defines:
- # in order to add common defines:
- # 1) remove the trailing [] from the :common: section
- # 2) add entries to the :common: section (e.g. :test: has TEST defined)
- :common: &common_defines []
- :test:
- - *common_defines
- - TEST
- - UNITY_OUTPUT_COLOR #this is just here to make sure it gets removed by ceedling
- :test_preprocess:
- - *common_defines
- - TEST
-
-:tools:
- :release_compiler:
- :executable: avr-gcc
- :arguments:
- - ${1}
- - -DTARGET
- - -DF_CPU=#{ENV['F_CPU']}
- - -mmcu=#{ENV['MCU']}
- - -Iinclude/
- - -Wall
- - -Os
- - -c
- - -o ${2}
- :release_linker:
- :executable: avr-gcc
- :arguments:
- - -mmcu=#{ENV['MCU']}
- - ${1}
- - -o ${2}.bin
-
-:cmock:
- :mock_prefix: mock_
- :when_no_prototypes: :warn
- :enforce_strict_ordering: TRUE
- :plugins:
- - :ignore
- :treat_as:
- uint8: HEX8
- uint16: HEX16
- uint32: UINT32
- int8: INT8
- bool: UINT8
-
-#:tools:
-# Ceedling defaults to using gcc for compiling, linking, etc.
-# As [:tools] is blank, gcc will be used (so long as it's in your system path)
-# See documentation to configure a given toolchain for use
-
-:plugins:
- :load_paths:
- - "#{Ceedling.load_path}"
- :enabled:
- - stdout_pretty_tests_report
- - module_generator
-...
diff --git a/examples/blinky/rakefile.rb b/examples/blinky/rakefile.rb
deleted file mode 100644
index 37b0fe701..000000000
--- a/examples/blinky/rakefile.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require "ceedling"
-Ceedling.load_project
-
-task :default => %w[ test:all release ]
-
-# Dummy task to ensure that the SERIAL_PORT environment variable is set.
-# It can be set on the command line as follows:
-# $ rake SERIAL_PORT=[serial port name]
-task :serial_port do
- unless ENV['SERIAL_PORT']
- raise "SERIAL_PORT is not defined in the environment!"
- end
-end
-
-desc "Convert the output binary to a hex file for programming to the Arduino"
-task :convert => :release do
- bin_file = "build/release/#{RELEASE_BUILD_OUTPUT}.bin"
- hex_file = "build/release/#{RELEASE_BUILD_OUTPUT}.hex"
- cmd = "#{ENV['OBJCOPY']} -O ihex -R .eeprom #{bin_file} #{hex_file}"
- puts cmd
- sh cmd
-end
-
-desc "Program the Arduino over the serial port."
-task :program => [:convert, :serial_port] do
- hex_file = "build/release/#{RELEASE_BUILD_OUTPUT}.hex"
- cmd = "avrdude -F -V -c arduino -p #{ENV['MCU']} -P #{ENV['SERIAL_PORT']} -b 115200 -U flash:w:#{hex_file}"
- puts cmd
- sh cmd
-end
diff --git a/examples/blinky/src/BlinkTask.c b/examples/blinky/src/BlinkTask.c
deleted file mode 100644
index 7ab3e686e..000000000
--- a/examples/blinky/src/BlinkTask.c
+++ /dev/null
@@ -1,21 +0,0 @@
-// #include
-
-#include "BlinkTask.h"
-
-#ifdef TEST
- #define LOOP
- #include "stub_io.h"
-#else
- #include
- #include
- #define LOOP while(1)
-#endif // TEST
-
-
-
-void BlinkTask(void)
-{
- /* toggle the LED */
- PORTB ^= _BV(PORTB5);
-
-}
diff --git a/examples/blinky/src/BlinkTask.h b/examples/blinky/src/BlinkTask.h
deleted file mode 100644
index d9887810f..000000000
--- a/examples/blinky/src/BlinkTask.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef BlinkTask_H
-#define BlinkTask_H
-
-void BlinkTask(void);
-
-#endif
diff --git a/examples/blinky/src/Configure.c b/examples/blinky/src/Configure.c
deleted file mode 100644
index 11e506baa..000000000
--- a/examples/blinky/src/Configure.c
+++ /dev/null
@@ -1,36 +0,0 @@
-#include "Configure.h"
-#include "main.h"
-#ifdef TEST
- #include "stub_io.h"
- #include "stub_interrupt.h"
-#else
- #include
- #include
-#endif // TEST
-
-/* setup timer 0 to divide bus clock by 64.
- This results in a 1.024ms overflow interrupt
-16000000/64
- 250000
-
-0.000 004s *256
-0.001024
-*/
-void Configure(void)
-{
- /* disable interrupts */
- cli();
-
- /* Configure TIMER0 to use the CLK/64 prescaler. */
- TCCR0B = _BV(CS00) | _BV(CS01);
-
- /* enable the TIMER0 overflow interrupt */
- TIMSK0 = _BV(TOIE0);
-
- /* confiure PB5 as an output. */
- DDRB |= _BV(DDB5);
-
- /* enable interrupts. */
- sei();
-}
-
diff --git a/examples/blinky/src/Configure.h b/examples/blinky/src/Configure.h
deleted file mode 100644
index 2399d39d5..000000000
--- a/examples/blinky/src/Configure.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef Configure_H
-#define Configure_H
-
-void Configure(void);
-
-#endif // Configure_H
diff --git a/examples/blinky/src/main.c b/examples/blinky/src/main.c
deleted file mode 100644
index 6533aaae6..000000000
--- a/examples/blinky/src/main.c
+++ /dev/null
@@ -1,51 +0,0 @@
-// #include
-
-#include "main.h"
-#include "BlinkTask.h"
-#include "Configure.h"
-
-//Most OS's frown upon direct memory access.
-//So we'll have to use fake registers during testing.
-#ifdef TEST
- #define LOOP
- #include "stub_io.h"
- #include "stub_interrupt.h"
-#else
- #include
- #include
- #define LOOP while(1)
- //The target will need a main.
- //Our test runner will provide it's own and call AppMain()
- int main(void)
- {
- return AppMain();
- }
-#endif // TEST
-
-int AppMain(void)
-{
- Configure();
-
- LOOP
- {
- if(BlinkTaskReady==0x01)
- {
- BlinkTaskReady = 0x00;
- BlinkTask();
- }
- }
- return 0;
-}
-
-ISR(TIMER0_OVF_vect)
-{
- /* toggle every thousand ticks */
- if (tick >= 1000)
- {
- /* signal our periodic task. */
- BlinkTaskReady = 0x01;
- /* reset the tick */
- tick = 0;
- }
- tick++;
-}
diff --git a/examples/blinky/src/main.h b/examples/blinky/src/main.h
deleted file mode 100644
index 17c176c52..000000000
--- a/examples/blinky/src/main.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __MAIN_H__
-#define __MAIN_H__
-
-int main(void);
-int AppMain(void);
-volatile int BlinkTaskReady;
-int tick;
-
-#endif /* __MAIN_H__ */
diff --git a/examples/blinky/test/support/stub_interrupt.h b/examples/blinky/test/support/stub_interrupt.h
deleted file mode 100644
index 7410f2149..000000000
--- a/examples/blinky/test/support/stub_interrupt.h
+++ /dev/null
@@ -1,347 +0,0 @@
-/* Copyright (c) 2002,2005,2007 Marek Michalkiewicz
- Copyright (c) 2007, Dean Camera
-
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
-
- * Neither the name of the copyright holders nor the names of
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE. */
-
-/* $Id: interrupt.h,v 1.25.2.1 2008/01/05 06:33:11 dmix Exp $ */
-
-#ifndef _AVR_INTERRUPT_H_
-#define _AVR_INTERRUPT_H_
-
-// #include
-#include "stub_io.h"
-#if !defined(__DOXYGEN__) && !defined(__STRINGIFY)
-/* Auxiliary macro for ISR_ALIAS(). */
-#define __STRINGIFY(x) #x
-#endif /* !defined(__DOXYGEN__) */
-
-/**
-\file
-\@{
-*/
-
-
-/** \name Global manipulation of the interrupt flag
-
- The global interrupt flag is maintained in the I bit of the status
- register (SREG).
-*/
-
-// #if defined(__DOXYGEN__)
-/** \def sei()
- \ingroup avr_interrupts
-
- \code #include \endcode
-
- Enables interrupts by setting the global interrupt mask. This function
- actually compiles into a single line of assembly, so there is no function
- call overhead. */
-// #define sei()
-void sei(void); // Redefine the macro as a function so that it can be mocked by CMock
-// #else /* !DOXYGEN */
-// # define sei() __asm__ __volatile__ ("sei" ::)
-// #endif /* DOXYGEN */
-
-// #if defined(__DOXYGEN__)
-/** \def cli()
- \ingroup avr_interrupts
-
- \code #include \endcode
-
- Disables all interrupts by clearing the global interrupt mask. This function
- actually compiles into a single line of assembly, so there is no function
- call overhead. */
-// #define cli()
-void cli(void); // Redefine the macro as a function so that it can be mocked by CMock
-// #else /* !DOXYGEN */
-// # define cli() __asm__ __volatile__ ("cli" ::)
-// #endif /* DOXYGEN */
-
-
-/** \name Macros for writing interrupt handler functions */
-
-
-// #if defined(__DOXYGEN__)
-/** \def ISR(vector [, attributes])
- \ingroup avr_interrupts
-
- \code #include \endcode
-
- Introduces an interrupt handler function (interrupt service
- routine) that runs with global interrupts initially disabled
- by default with no attributes specified.
-
- The attributes are optional and alter the behaviour and resultant
- generated code of the interrupt routine. Multiple attributes may
- be used for a single function, with a space seperating each
- attribute.
-
- Valid attributes are ISR_BLOCK, ISR_NOBLOCK, ISR_NAKED and
- ISR_ALIASOF(vect).
-
- \c vector must be one of the interrupt vector names that are
- valid for the particular MCU type.
-*/
-// # define ISR(vector, [attributes])
-#define ISR void ISR
-// #else /* real code */
-
-// #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
-// # define __INTR_ATTRS used, externally_visible
-// #else /* GCC < 4.1 */
-// # define __INTR_ATTRS used
-// #endif
-
-// #ifdef __cplusplus
-// # define ISR(vector, ...) \
-// extern "C" void vector (void) __attribute__ ((signal,__INTR_ATTRS)) __VA_ARGS__; \
-// void vector (void)
-// #else
-// # define ISR(vector, ...) \
-// void vector (void) __attribute__ ((signal,__INTR_ATTRS)) __VA_ARGS__; \
-// void vector (void)
-// #endif
-
-// #endif /* DOXYGEN */
-
-#if defined(__DOXYGEN__)
-/** \def SIGNAL(vector)
- \ingroup avr_interrupts
-
- \code #include \endcode
-
- Introduces an interrupt handler function that runs with global interrupts
- initially disabled.
-
- This is the same as the ISR macro without optional attributes.
- \deprecated Do not use SIGNAL() in new code. Use ISR() instead.
-*/
-# define SIGNAL(vector)
-#else /* real code */
-
-#ifdef __cplusplus
-# define SIGNAL(vector) \
- extern "C" void vector(void) __attribute__ ((signal, __INTR_ATTRS)); \
- void vector (void)
-#else
-# define SIGNAL(vector) \
- void vector (void) __attribute__ ((signal, __INTR_ATTRS)); \
- void vector (void)
-#endif
-
-#endif /* DOXYGEN */
-
-#if defined(__DOXYGEN__)
-/** \def EMPTY_INTERRUPT(vector)
- \ingroup avr_interrupts
-
- \code #include \endcode
-
- Defines an empty interrupt handler function. This will not generate
- any prolog or epilog code and will only return from the ISR. Do not
- define a function body as this will define it for you.
- Example:
- \code EMPTY_INTERRUPT(ADC_vect);\endcode */
-# define EMPTY_INTERRUPT(vector)
-#else /* real code */
-
-#ifdef __cplusplus
-# define EMPTY_INTERRUPT(vector) \
- extern "C" void vector(void) __attribute__ ((signal,naked,__INTR_ATTRS)); \
- void vector (void) { __asm__ __volatile__ ("reti" ::); }
-#else
-# define EMPTY_INTERRUPT(vector) \
- void vector (void) __attribute__ ((signal,naked,__INTR_ATTRS)); \
- void vector (void) { __asm__ __volatile__ ("reti" ::); }
-#endif
-
-#endif /* DOXYGEN */
-
-#if defined(__DOXYGEN__)
-/** \def ISR_ALIAS(vector, target_vector)
- \ingroup avr_interrupts
-
- \code #include \endcode
-
- Aliases a given vector to another one in the same manner as the
- ISR_ALIASOF attribute for the ISR() macro. Unlike the ISR_ALIASOF
- attribute macro however, this is compatible for all versions of
- GCC rather than just GCC version 4.2 onwards.
-
- \note This macro creates a trampoline function for the aliased
- macro. This will result in a two cycle penalty for the aliased
- vector compared to the ISR the vector is aliased to, due to the
- JMP/RJMP opcode used.
-
- \deprecated
- For new code, the use of ISR(..., ISR_ALIASOF(...)) is
- recommended.
-
- Example:
- \code
- ISR(INT0_vect)
- {
- PORTB = 42;
- }
-
- ISR_ALIAS(INT1_vect, INT0_vect);
- \endcode
-*/
-# define ISR_ALIAS(vector, target_vector)
-#else /* real code */
-
-#ifdef __cplusplus
-# if defined(__AVR_MEGA__) && __AVR_MEGA__
-# define ISR_ALIAS(vector, tgt) extern "C" void vector (void) \
- __attribute__((signal, naked, __INTR_ATTRS)); \
- void vector (void) { asm volatile ("jmp " __STRINGIFY(tgt) ::); }
-# else /* !__AVR_MEGA */
-# define ISR_ALIAS(vector, tgt) extern "C" void vector (void) \
- __attribute__((signal, naked, __INTR_ATTRS)); \
- void vector (void) { asm volatile ("rjmp " __STRINGIFY(tgt) ::); }
-# endif /* __AVR_MEGA__ */
-#else /* !__cplusplus */
-# if defined(__AVR_MEGA__) && __AVR_MEGA__
-# define ISR_ALIAS(vector, tgt) void vector (void) \
- __attribute__((signal, naked, __INTR_ATTRS)); \
- void vector (void) { asm volatile ("jmp " __STRINGIFY(tgt) ::); }
-# else /* !__AVR_MEGA */
-# define ISR_ALIAS(vector, tgt) void vector (void) \
- __attribute__((signal, naked, __INTR_ATTRS)); \
- void vector (void) { asm volatile ("rjmp " __STRINGIFY(tgt) ::); }
-# endif /* __AVR_MEGA__ */
-#endif /* __cplusplus */
-
-#endif /* DOXYGEN */
-
-#if defined(__DOXYGEN__)
-/** \def reti()
- \ingroup avr_interrupts
-
- \code #include \endcode
-
- Returns from an interrupt routine, enabling global interrupts. This should
- be the last command executed before leaving an ISR defined with the ISR_NAKED
- attribute.
-
- This macro actually compiles into a single line of assembly, so there is
- no function call overhead.
-*/
-# define reti()
-#else /* !DOXYGEN */
-# define reti() __asm__ __volatile__ ("reti" ::)
-#endif /* DOXYGEN */
-
-#if defined(__DOXYGEN__)
-/** \def BADISR_vect
- \ingroup avr_interrupts
-
- \code #include \endcode
-
- This is a vector which is aliased to __vector_default, the vector
- executed when an ISR fires with no accompanying ISR handler. This
- may be used along with the ISR() macro to create a catch-all for
- undefined but used ISRs for debugging purposes.
-*/
-# define BADISR_vect
-#else /* !DOXYGEN */
-# define BADISR_vect __vector_default
-#endif /* DOXYGEN */
-
-/** \name ISR attributes */
-
-#if defined(__DOXYGEN__)
-/** \def ISR_BLOCK
- \ingroup avr_interrupts
-
- \code# include \endcode
-
- Identical to an ISR with no attributes specified. Global
- interrupts are initially disabled by the AVR hardware when
- entering the ISR, without the compiler modifying this state.
-
- Use this attribute in the attributes parameter of the ISR macro.
-*/
-# define ISR_BLOCK
-
-/** \def ISR_NOBLOCK
- \ingroup avr_interrupts
-
- \code# include \endcode
-
- ISR runs with global interrupts initially enabled. The interrupt
- enable flag is activated by the compiler as early as possible
- within the ISR to ensure minimal processing delay for nested
- interrupts.
-
- This may be used to create nested ISRs, however care should be
- taken to avoid stack overflows, or to avoid infinitely entering
- the ISR for those cases where the AVR hardware does not clear the
- respective interrupt flag before entering the ISR.
-
- Use this attribute in the attributes parameter of the ISR macro.
-*/
-# define ISR_NOBLOCK
-
-/** \def ISR_NAKED
- \ingroup avr_interrupts
-
- \code# include \endcode
-
- ISR is created with no prologue or epilogue code. The user code is
- responsible for preservation of the machine state including the
- SREG register, as well as placing a reti() at the end of the
- interrupt routine.
-
- Use this attribute in the attributes parameter of the ISR macro.
-*/
-# define ISR_NAKED
-
-/** \def ISR_ALIASOF(target_vector)
- \ingroup avr_interrupts
-
- \code#include \endcode
-
- The ISR is linked to another ISR, specified by the vect parameter.
- This is compatible with GCC 4.2 and greater only.
-
- Use this attribute in the attributes parameter of the ISR macro.
-*/
-# define ISR_ALIASOF(target_vector)
-#else /* !DOXYGEN */
-# define ISR_BLOCK
-# define ISR_NOBLOCK __attribute__((interrupt))
-# define ISR_NAKED __attribute__((naked))
-# define ISR_ALIASOF(v) __attribute__((alias(__STRINGIFY(v))))
-#endif /* DOXYGEN */
-
-/* \@} */
-
-#endif
diff --git a/examples/blinky/test/support/stub_io.h b/examples/blinky/test/support/stub_io.h
deleted file mode 100644
index e9646daf6..000000000
--- a/examples/blinky/test/support/stub_io.h
+++ /dev/null
@@ -1,421 +0,0 @@
-/* Copyright (c) 2002,2003,2005,2006,2007 Marek Michalkiewicz, Joerg Wunsch
- Copyright (c) 2007 Eric B. Weddington
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
-
- * Neither the name of the copyright holders nor the names of
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE. */
-
-/* $Id: io.h,v 1.52.2.28 2009/12/20 17:02:53 arcanum Exp $ */
-
-/** \file */
-/** \defgroup avr_io : AVR device-specific IO definitions
- \code #include \endcode
-
- This header file includes the apropriate IO definitions for the
- device that has been specified by the -mmcu= compiler
- command-line switch. This is done by diverting to the appropriate
- file <avr/io XXXX .h> which should
- never be included directly. Some register names common to all
- AVR devices are defined directly within <avr/common.h> ,
- which is included in <avr/io.h> ,
- but most of the details come from the respective include file.
-
- Note that this file always includes the following files:
- \code
- #include
- #include
- #include
- #include
- \endcode
- See \ref avr_sfr for more details about that header file.
-
- Included are definitions of the IO register set and their
- respective bit values as specified in the Atmel documentation.
- Note that inconsistencies in naming conventions,
- so even identical functions sometimes get different names on
- different devices.
-
- Also included are the specific names useable for interrupt
- function definitions as documented
- \ref avr_signames "here".
-
- Finally, the following macros are defined:
-
- - \b RAMEND
-
- The last on-chip RAM address.
-
- - \b XRAMEND
-
- The last possible RAM location that is addressable. This is equal to
- RAMEND for devices that do not allow for external RAM. For devices
- that allow external RAM, this will be larger than RAMEND.
-
- - \b E2END
-
- The last EEPROM address.
-
- - \b FLASHEND
-
- The last byte address in the Flash program space.
-
- - \b SPM_PAGESIZE
-
- For devices with bootloader support, the flash pagesize
- (in bytes) to be used for the \c SPM instruction.
- - \b E2PAGESIZE
-
- The size of the EEPROM page.
-
-*/
-
-#ifndef _AVR_IO_H_
-#define _AVR_IO_H_
-
-// #include
-#include "stub_sfr_defs.h"
-// #if defined (__AVR_AT94K__)
-// # include
-// #elif defined (__AVR_AT43USB320__)
-// # include
-// #elif defined (__AVR_AT43USB355__)
-// # include
-// #elif defined (__AVR_AT76C711__)
-// # include
-// #elif defined (__AVR_AT86RF401__)
-// # include
-// #elif defined (__AVR_AT90PWM1__)
-// # include
-// #elif defined (__AVR_AT90PWM2__)
-// # include
-// #elif defined (__AVR_AT90PWM2B__)
-// # include
-// #elif defined (__AVR_AT90PWM3__)
-// # include
-// #elif defined (__AVR_AT90PWM3B__)
-// # include
-// #elif defined (__AVR_AT90PWM216__)
-// # include
-// #elif defined (__AVR_AT90PWM316__)
-// # include
-// #elif defined (__AVR_AT90PWM81__)
-// # include
-// #elif defined (__AVR_ATmega8U2__)
-// # include
-// #elif defined (__AVR_ATmega16M1__)
-// # include
-// #elif defined (__AVR_ATmega16U2__)
-// # include
-// #elif defined (__AVR_ATmega16U4__)
-// # include
-// #elif defined (__AVR_ATmega32C1__)
-// # include
-// #elif defined (__AVR_ATmega32M1__)
-// # include
-// #elif defined (__AVR_ATmega32U2__)
-// # include
-// #elif defined (__AVR_ATmega32U4__)
-// # include
-// #elif defined (__AVR_ATmega32U6__)
-// # include
-// #elif defined (__AVR_ATmega64C1__)
-// # include
-// #elif defined (__AVR_ATmega64M1__)
-// # include
-// #elif defined (__AVR_ATmega128__)
-// # include
-// #elif defined (__AVR_ATmega1280__)
-// # include
-// #elif defined (__AVR_ATmega1281__)
-// # include
-// #elif defined (__AVR_ATmega1284P__)
-// # include
-// #elif defined (__AVR_ATmega128RFA1__)
-// # include
-// #elif defined (__AVR_ATmega2560__)
-// # include
-// #elif defined (__AVR_ATmega2561__)
-// # include
-// #elif defined (__AVR_AT90CAN32__)
-// # include
-// #elif defined (__AVR_AT90CAN64__)
-// # include
-// #elif defined (__AVR_AT90CAN128__)
-// # include
-// #elif defined (__AVR_AT90USB82__)
-// # include
-// #elif defined (__AVR_AT90USB162__)
-// # include
-// #elif defined (__AVR_AT90USB646__)
-// # include
-// #elif defined (__AVR_AT90USB647__)
-// # include
-// #elif defined (__AVR_AT90USB1286__)
-// # include