Search code examples
gradlecunit

How to use CUnit to test a native application with multiple components


I have a gradle project for a native c application in gradle (version 2.10) made from multiple components:

components {

   component_1(NativeLibrarySpec)
   component_2(NativeLibrarySpec)
   ...
   component_n(NativeLibrarySpec)

   main_component(NativeExecutableSpec){
       sources {
            c.lib library: "component_1", linkage: "static"
            c.lib library: "component_2", linkage: "static"
            ...
            c.lib library: "component_n", linkage: "static"
        }

   }
}

The main idea of having the application in this form was to made easier to test individual components. However, I'm having two big problems:

The main_component is an application, therefore has a main function and this generates this error: multiple definition of 'main' ... gradle_cunit_main.c:(.text+0x0): first defined here. This is something to expect and is mentioned in the documentation, but I'm wondering if there's way to avoid this issue, as for instance, prevent the main component to be included in the tests. This is related to the next question

The CUnit plugin (as of version 2.10 of gradle) complains when I try to define the components to be tested as follows:

testSuites {
    component_1Test(CUnitTestSuiteSpec){
            testing $.components.component_1
        }
   }
}

gradle complains:

Cannot create 'testSuites.component_1Test' using creation rule 'component_1Test(org.gradle.nativeplatform.test.cunit.CUnitTestSuiteSpec) { ... } @ build.gradle line 68, column 9' as the rule 'CUnitPlugin.Rules#createCUnitTestSuitePerComponent > create(component_1Test)' is already registered to create this model element

In summary, I would like to instruct the cunit plugin to test only some components and prevent the main component (with the main function) to be compiled for tests. Again, please notice I'm using gradle 2.10 and cannot upgrade to a more recent version as that would brake our CI tool chain.

Thanks in advance for your comments.


Solution

  • Here is how to structure the project to allow unit testing of the components, but prevent unit testing of the main program: split the components in a sub-project and apply the cunit plugin to the subproject, as shown below:

    project(':libs'){
    apply plugin: 'c'
    apply plugin: 'cunit'
    model{
    
        repositories {
            libs(PrebuiltLibraries) {
                cunit {
                    headers.srcDir "/usr/include/"
                        binaries.withType(StaticLibraryBinary) {
                            staticLibraryFile = file("/usr/lib/x86_64-linux-gnu/libcunit.a")
                        }
                }
            }
        }
    
        components {
            component_1(NativeLibrarySpec)
            component_2(NativeLibrarySpec)
            ...
            component_n(NativeLibrarySpec)
        }
    
        binaries {
            withType(CUnitTestSuiteBinarySpec) {
                lib library: "cunit", linkage: "static"
            }
        }
    }
    }
    apply plugin: 'c'
    model {
        components{
            myprogram(NativeExecutableSpec) {
                sources.c {
                    lib project: ':libs', library: 'component_1', linkage: 'static'
                    lib project: ':libs', library: 'component_2', linkage: 'static'
                    lib project: ':libs', library: "component_n", linkage: 'static'
                    source {
                         srcDir "src/myprogram/c"
                              include "**/*.c"
                    }
                }
            }
        }
    }