Skip to content

Additional test source files not being included if they are nested in a different folder #1124

@rolandsfr

Description

@rolandsfr

Description:
Necessary source file is not being linked (and compiled for that matter) for a test file whose source file use other source file which is nested deeper in the project tree. To illustrate this, I have provided a minimal example.

Project stcture:

├── compile_commands.json
├── include
│   └── parent.h
├── project.yml
├── src
│   └── parent
│       ├── child
│       │   ├── child.c
│       │   ├── child.h
│       │   └── child.test.c
│       ├── parent.c
│       └── parent.test.c
└── tests_build
    ├── artifacts
    │   └── test
    ├── logs
    ├── test
    │   ├── cache
    │   ├── dependencies
    │   │   ├── child_runner.d
    │   │   ├── child.d
    │   │   ├── child.test_runner.d
    │   │   ├── child.test.d
    │   │   ├── parent_runner.d
    │   │   ├── parent.d
    │   │   ├── parent.test_runner.d
    │   │   ├── parent.test.d
    │   │   └── unity.d
    │   ├── mocks
    │   │   ├── child
    │   │   ├── child.test
    │   │   ├── parent
    │   │   └── parent.test
    │   ├── out
    │   │   ├── child
    │   │   │   ├── child_runner.o
    │   │   │   ├── child.o
    │   │   │   ├── child.out
    │   │   │   └── unity.o
    │   │   ├── child.test
    │   │   │   ├── child.o
    │   │   │   ├── child.test_runner.o
    │   │   │   ├── child.test.o
    │   │   │   ├── child.test.out
    │   │   │   └── unity.o
    │   │   ├── parent
    │   │   │   ├── parent_runner.o
    │   │   │   ├── parent.o
    │   │   │   └── unity.o
    │   │   └── parent.test
    │   │       ├── child.o
    │   │       ├── parent.o
    │   │       ├── parent.test_runner.o
    │   │       ├── parent.test.o
    │   │       ├── parent.test.out
    │   │       └── unity.o
    │   ├── results
    │   └── runners
    │       ├── child_runner.c
    │       ├── child.test_runner.c
    │       ├── parent_runner.c
    │       └── parent.test_runner.c
    └── vendor
        ├── cmock
        │   └── src
        │       ├── cmock_internals.h
        │       ├── cmock.c
        │       ├── cmock.h
        │       └── meson.build
        └── unity
            └── src
                ├── meson.build
                ├── unity_internals.h
                ├── unity.c
                └── unity.h

child.c:

int mul(int a, int b) {
    return a * b;
}

child.test.c

#include "unity.h"
#include "child.h"

void test_mul(void)
{
    TEST_ASSERT_EQUAL_INT(6, mul(3,2));
}

child.h

int mul(int a, int b);

parent.c

T

int sum(int a, int b) {
    return a + b;
}

int square(int n) {
    return mul(n,2);
}

parent.test.c

#include "unity.h"
#include "parent.h"

TEST_SOURCE_FILE("child/child.c");

void test_sum(void)
{
    TEST_ASSERT_EQUAL_INT(5, sum(3,2));
}

include/parent.h

int sum(int a, int b);
int square(int n);

Output from running ceedling test in root:

🚧 Loaded project configuration from working directory.
 > Using: <dir>/project.yml
 > Working directory: <dir>

Ceedling set up completed in 56 milliseconds

👟 Preparing Build Paths...

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

👟 Ingesting Test Configurations
--------------------------------
Collecting search paths, flags, and defines parent.c...
Collecting search paths, flags, and defines parent.test.c...
Collecting search paths, flags, and defines child.c...
Collecting search paths, flags, and defines child.test.c...

👟 Determining Files to be Generated...

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

👟 Test Runners
---------------
Generating runner for parent.c...
Generating runner for parent.test.c...
Generating runner for child.c...
Generating runner for child.test.c...

👟 Determining Artifacts to Be Built...

👟 Building Objects
-------------------
Compiling parent.c...
Compiling parent::parent_runner.c...
Compiling parent::unity.c...
Compiling parent.test.c...
Compiling parent.test::child.c...
Compiling parent.test::parent.c...
Compiling parent.test::parent.test_runner.c...
Compiling parent.test::unity.c...
Compiling child.c...
Compiling child::child_runner.c...
Compiling child::unity.c...
Compiling child.test.c...
Compiling child.test::child.c...
Compiling child.test::child.test_runner.c...
Compiling child.test::unity.c...

👟 Building Test Executables
----------------------------
Linking parent.out...
ℹ️ NOTICE: If the linker reports missing symbols, the following may be to blame:
  1. This test lacks #include statements corresponding to needed source files (see note below).
  2. Project file paths omit source files corresponding to #include statements in this test.
  3. Complex macros, #ifdefs, etc. have obscured correct #include statements in this test.
  4. Your project is attempting to mix C++ and C file extensions (not supported).
  5. This test does not #include needed mocks (that triggers their generation).

NOTE: A test file directs the build of a test executable with #include statemetns:
  * By convention, Ceedling assumes header filenames correspond to source filenames.
  * Which code files to compile and link are determined by #include statements.
  * An #include statement convention directs the generation of mocks from header files.

OPTIONS:
  1. Doublecheck this test's #include statements.
  2. Simplify complex macros or fully specify symbols for this test in :project ↳ :defines.
  3. If no header file corresponds to the needed source file, use the TEST_SOURCE_FILE()
     build diective macro in this test to inject a source file into the build.

See the docs on conventions, paths, preprocessing, compilation symbols, and build directive macros.

🧨 EXCEPTION: 'Default Test Linker' (gcc) terminated with exit code [1] and output >>
Undefined symbols for architecture arm64:
  "_mul", referenced from:
      _square in parent.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
🌱 Ceedling could not complete operations because of errors

As you can see, parent.test.c file misses source from child.c

Please notice that I do not expect solutions in form "change your project structure" because I desire flexibility and freedom in my projects.
Theoretically TEST_SOURCE_FILE("child/child.c") should have done the thing but it didnt

project.yml:

:defines:
  :common: &common_defines []
  :test:
    - *common_defines
    - TEST
    - UNITY_INCLUDE_DOUBLE # Add it here without D prefix

:paths:
  :source:
    - src/**
  :include:
    - include
    - src
  :test:
    - src/** # unit tests live next to code

:flags:
  :preprocess:
    :compile: []

:project:
  # how to use ceedling. If you're not sure, leave this as `gem` and `?`

  :ceedling_version: 1.0.1

  # optional features. If you don't need them, keep them turned off for performance
  :use_mocks: TRUE
  :use_decorators: :auto # decorate Ceedling's output text. options are :auto, :all, or :none

  # tweak the way ceedling handles automatic tasks
  :build_root: tests_build
  :test_file_prefix: ""
  :test_file_suffix: ".test.c"
  :default_tasks:
    - test:all

  :release_build: FALSE

:plugins:
  :load_paths: []
  :enabled:
    - module_generator # handy for quickly creating source, header, and test templates
    - report_tests_pretty_stdout

:extension:
  :executable: .out

---
# Configuration Options specific to CMock. See CMock docs for details
# ====
# ====
# ====

:cmock:
  :mock_path: test/support/mocks
  :stub_path: test/support/stubs
  :mock_prefix: mock_
  :when_no_prototypes: :warn
  :enforce_strict_ordering: TRUE
  :plugins:
    :enabled:
      - :ignore
      - :callback
      - stdout_pretty_tests_report
      - module_generator
  :treat_as:
    uint8: HEX8
    uint16: HEX16
    uint32: UINT32
    int8: INT8
    bool: UINT8

################################################################
# PLUGIN CONFIGURATION
################################################################

#clang 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
  :gcovr:
    :html_medium_threshold: 75
    :html_high_threshold: 90

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions