CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/googletest-embedded-arm

Author and run GoogleTest 1.17+ for embedded C++ on ARM targets - TEST() / TEST_F() / TEST_P() / TYPED_TEST(), EXPECT_* vs ASSERT_* assertions, fixtures with SetUp() / TearDown(), value-parameterised tests, GoogleMock when paired, cross-compile with arm-none-eabi-g++, run on host or under QEMU via the qemu-system-test-runner skill, --gtest_filter / --gtest_output=xml:results.xml / --gtest_shuffle / --gtest_repeat command-line flags, and XML / JSON output parsing for CI. Use when the unit-under-test is C++ (modern C++17+) and the team wants the de-facto C++ test framework instead of the C-only Unity. For C use unity-test-framework-c; for pure C mocks see the CMock reference in ceedling-build-runner.

72

Quality

90%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

cross-compile-and-ci.mdreferences/

GoogleTest cross-compile, output parsing, and CI for embedded ARM

Deep reference for the googletest-embedded-arm SKILL.md. Consult when wiring the full toolchain (host CMake, Cortex-M / Cortex-A cross-compile), reading the XML / JSON output schema, or gating CI.

Host build (fast inner loop)

CMake:

include(FetchContent)
FetchContent_Declare(googletest
    GIT_REPOSITORY https://github.com/google/googletest.git
    GIT_TAG v1.17.0)
FetchContent_MakeAvailable(googletest)

add_executable(ringbuffer_test test/ringbuffer_test.cpp)
target_link_libraries(ringbuffer_test PRIVATE gtest_main)
enable_testing()
add_test(NAME ringbuffer_test COMMAND ringbuffer_test)

gtest_main provides a main() that calls testing::InitGoogleTest(&argc, argv) then RUN_ALL_TESTS() - which "returns 0 on success, 1 on failure" and per google.github.io/googletest/primer.html "You must not ignore the return value of RUN_ALL_TESTS()".

Cortex-M cross-compile (under QEMU)

The standard recipe - uses arm-none-eabi-g++ for the toolchain, --specs=rdimon.specs to pull in the librdimon semihosting library so stdout reaches QEMU:

arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard \
    -O0 -g -std=c++17 \
    -DGTEST_HAS_PTHREAD=0 -DGTEST_OS_LINUX=0 -DGTEST_LANG_CXX11=1 \
    --specs=rdimon.specs \
    -I/path/to/googletest/googletest/include \
    test/ringbuffer_test.cpp /path/to/googletest/googletest/src/gtest-all.cc \
    -o ringbuffer_test.elf -lrdimon

-DGTEST_HAS_PTHREAD=0 is critical - bare-metal targets have no pthreads; the build fails without it. (The flag is documented in GoogleTest's port.h.) For Cortex-A Linux targets, use the standard arm-linux-gnueabihf-g++ and drop the --specs flag.

Build invariants

InvariantWhy
-O0 -g for coverage buildsgcov / llvm-cov measure post-optimisation flow; see embedded-coverage-strategy-reference
-Wno-psabi on ARMSuppresses noisy ABI warnings on cross-compile
-fno-exceptions -fno-rtti if MCU build doesMatch the production firmware's flags so virtual dispatch matches
Link with -Wl,--gc-sections + compile with -ffunction-sections -fdata-sectionsKeeps the .elf small enough for low-RAM Cortex-M0 simulation

Command-line flags (full set)

Per the Advanced Guide:

FlagEffect
--gtest_filter=Pattern"a :-separated list of wildcard patterns" - supports *, ?, and negative - patterns
--gtest_repeat=NRepeats all tests N times (use -1 for infinite - useful for flake hunting)
--gtest_shuffleRandom order each run - "reveal bad dependencies between tests"
--gtest_output=xml:results.xml / json:results.jsonMachine-readable report (the value is "xml:path" or "json:path")
--gtest_break_on_failureDrops into debugger on first failure
--gtest_catch_exceptions=0Disables exception handling - lets debugger catch the throw
--gtest_color=yes|no|autoColoured terminal output
--gtest_brief=1Only failures shown
--gtest_list_testsList without running

Parsing results

XML output schema

Per the Advanced Guide, the XML follows a hierarchical structure with <testsuites> / <testsuite> / <testcase> elements, with <failure> nodes nested under failing <testcase> entries:

<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="7" failures="1" time="0.012">
  <testsuite name="RingbufferTest" tests="2" failures="0" time="0.001">
    <testcase name="EmptyOnInit" status="run" time="0.000"/>
    <testcase name="PushIncrementsSize" status="run" time="0.001"/>
  </testsuite>
  <testsuite name="WrapTest" tests="5" failures="1" time="0.011">
    <testcase name="WrapAtCapacity/4" status="run" time="0.002">
      <failure message="Expected: 5, actual: 4"/>
    </testcase>
  </testsuite>
</testsuites>

JUnit-compatible - feeds straight into GitHub Actions actions/upload-artifact + mikepenz/action-junit-report.

JSON output schema

Per the Advanced Guide: a "Proto3-compatible structure with UnitTest -> TestCase -> TestInfo -> Failure hierarchy, including timestamps and durations". Prefer JSON for custom dashboards; XML for the JUnit ecosystem.

Parsing pattern

./ringbuffer_test --gtest_output=xml:results.xml
xmlstarlet sel -t -v "count(//testcase[failure])" results.xml
# Number of failing testcases - gate on this

CI integration

jobs:
  embedded-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - name: Install ARM toolchain
        run: sudo apt-get install -y gcc-arm-none-eabi qemu-system-arm
      - name: Configure (host build)
        run: cmake -S . -B build-host -DCMAKE_BUILD_TYPE=Coverage
      - name: Build + run on host
        run: |
          cmake --build build-host
          ./build-host/ringbuffer_test \
            --gtest_output=xml:build-host/host-results.xml \
            --gtest_shuffle
      - name: Cross-compile + run under QEMU
        run: |
          arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -O0 -g -std=c++17 \
            -DGTEST_HAS_PTHREAD=0 --specs=rdimon.specs \
            -I ext/googletest/googletest/include \
            test/ringbuffer_test.cpp ext/googletest/googletest/src/gtest-all.cc \
            -o build-arm/ringbuffer_test.elf -lrdimon
          qemu-system-arm -M mps2-an385 -cpu cortex-m4 \
            -nographic -semihosting-config enable=on,target=native \
            -kernel build-arm/ringbuffer_test.elf
      - name: Publish JUnit
        uses: mikepenz/action-junit-report@v4
        with:
          report_paths: 'build-host/*-results.xml'

The host build gates on the JUnit XML; the QEMU build gates on QEMU's exit code (semihosting exit(RUN_ALL_TESTS()) propagates the gtest return value through QEMU).

SKILL.md

tile.json