Creating Fixtures in cmocka - c

I'm working on a project that's using the cmocka framework. The cmocka homepage states
Test fixtures are setup and teardown functions that can be shared across multiple test cases to provide common functions that prepare the test environment and destroy it afterwards.
However, none of the docs I've read explain how the fixture system works.
If I'm running my tests with code that looks like this
int main(void) {
const struct CMUnitTest license_tests[] = {
cmocka_unit_test(test_setup),
cmocka_unit_test(test_null_app),
cmocka_unit_test(test_null_name),
};
return cmocka_run_group_tests(license_tests, NULL, NULL);
}
How/where can I instruct cmocka to run setup/tear down fixtures and what features (if any) does cmocka have for letting me access things created in said fixtures?

Here is a template unit testing file that you can reuse in your project. It tackles all your requirements
#include <stdio.h>
#include <cmocka.h>
#include "mylib.h"
// Include here all your mocked functions, see below
#include "testmocks.c"
typedef struct {
mylibobj_t* mylibobj;
} teststate_t;
/**
* This is run once before all group tests
*/
static int groupSetup (void** state) {
teststate_t* teststate = calloc(1, sizeof(teststate_t));
*state = teststate;
return 0;
}
/**
* This is run once after all group tests
*/
static int groupTeardown (void** state) {
teststate_t* teststate = *state;
free(teststate);
return 0;
}
/**
* This is run once before one given test
*/
static int testSetup (void** state) {
teststate_t* teststate = *state;
//Maybe instantiate mylibobj?
return 0;
}
/**
* This is run once after one given test
*/
static int testTeardown (void** state) {
return 0;
}
/**
* This test will success with these options
*/
void mylib_setTime_s0 (void** state) {
teststate_t* teststate = *state;
// Do your testing stuff
}
/**
* This test will fail with these options
*/
void mylib_setTime_f0 (void** state) {
teststate_t* teststate = *state;
// Do your testing stuff
}
int main (void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(mylib_setTime_s0, testSetup, testTeardown),
cmocka_unit_test_setup_teardown(mylib_setTime_f0, testSetup, testTeardown),
};
return cmocka_run_group_tests(tests, groupSetup, groupTeardown);
}
The testmocks.c exists just for code organization, and may hold 0 to N pairs of mocked functions as
#define MOCKBYPASS -7337
mylib_status_t __real_inner_function (char* id);
mylib_status_t __wrap_inner_function (char* id) {
int mock = mock();
if(mock == MOCKBYPASS)
return __real_inner_function(id);
else
return mock;
}
...
Remember that gcc compilation tricks are a must for these mocks to work correctly

Those two NULL's you are passing to cmocka_run_group_tests function should, be group_setup and group_teardown functions, both type CMFixtureFunction - if You want to utilize
setup and teardown functions that can be shared across multiple test cases
in cmocka called test fixtures. As documentation for this function states.
Then shared (void** state) is accessible in each test. It can be used as in example below:
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <cmocka.h>
#define GREETINGS "one string to rule them all, One string to find them, "\
"one string to bring them all and in the darkness bind them"
#define PRECIOUSS_T1 "Three strings for the Elven-kings under the sky,"
#define PRECIOUSS_T2 "even for the Dwarf-lords in halls of stone,"
#define PRECIOUSS_T3 "Nine for Mortal Men, doomed to die,"
#define PRECIOUSS_T4 "One for the Dark Lord on his dark throne"
#define PRECIOUSS_T5 "In the Land of Mordor where the Shadows lie."
#define PRECIOUSS_T6 "One string to rule them all, One Ring to find them,"
#define PRECIOUSS_T7 "One string to bring them all and in the darkness bind them."
#define PRECIOUSS_T8 "In the Land of Mordor where the Shadows lie."
#define OOPS "Not quite what I expected"
#define T(X) PRECIOUSS_T##X
#define FOO(X) case X: strncpy(lots->memory, T(X), sizeof(T(X))); break;
#define SPR_FOO(X) case X: assert_string_equal(T(X), lots->memory); break;
typedef struct {
int line;
char * memory;
} lord_of_the_strings_t;
static int gr_setup(void **state) {
/* this is run once before all group tests */
lord_of_the_strings_t *book = malloc(sizeof(*book));
if (book == NULL)
return -1;
book->memory = malloc(sizeof(GREETINGS));
if (book->memory == NULL) {
return -1;
}
strncpy(book->memory, GREETINGS, sizeof(GREETINGS));
assert_string_equal(book->memory, GREETINGS);
*state = book;
return 0;
}
static int gr_teardown(void **state) {
/* this is run once after all group tests */
lord_of_the_strings_t *lots = *state;
free(lots->memory);
free(lots);
return 0;
}
static int ve_teardown(void **state) {
/* this is run before some single tests */
lord_of_the_strings_t *lots = *state;
lots->line = 42;
return 0;
}
static int ve_setup(void **state) {
/* this is run after some single tests */
static int setup_counter = 0;
lord_of_the_strings_t *lots = *state;
lots->line = ++setup_counter;
switch (setup_counter) {
FOO(1)
FOO(2)
FOO(3)
FOO(4)
FOO(5)
FOO(6)
FOO(7)
FOO(8)
default:
strncpy(lots->memory, OOPS, sizeof(OOPS));
};
return 0;
}
static void failing_test(void **state) {
assert_false("Sorry");
}
static void line_aware_test(void **state) {
lord_of_the_strings_t *lots = *state;
printf(" (shared) between tests, line=%d memory=%s\n", lots->line, lots->memory);
}
static void passing_test(void **state) {
}
static void string_recite_test(void **state) {
static int line_counter = 0;
lord_of_the_strings_t *lots = *state;
if (lots->line < 9)
assert_true(line_counter+1 == lots->line);
switch (++line_counter) {
SPR_FOO(1)
SPR_FOO(2)
SPR_FOO(3)
SPR_FOO(4)
SPR_FOO(5)
SPR_FOO(6)
SPR_FOO(7)
SPR_FOO(8)
default:
line_counter = 0;
}
}
int main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(passing_test),
cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
cmocka_unit_test(line_aware_test),
cmocka_unit_test(line_aware_test),
cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
cmocka_unit_test(line_aware_test),
cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
cmocka_unit_test(line_aware_test),
cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
cmocka_unit_test(failing_test),
};
return cmocka_run_group_tests(tests, gr_setup, gr_teardown);
}
Which should yield output like
[==========] Running 21 test(s).
[ RUN ] passing_test
[ OK ] passing_test
[ RUN ] string_recite_test
[ OK ] string_recite_test
[ RUN ] string_recite_test
[ OK ] string_recite_test
[ RUN ] string_recite_test
[ OK ] string_recite_test
[ RUN ] line_aware_test
(shared) between tests, line=42 memory=Nine for Mortal Men, doomed to die,
[ OK ] line_aware_test
[ RUN ] line_aware_test
(shared) between tests, line=42 memory=Nine for Mortal Men, doomed to die,
[ OK ] line_aware_test
[ RUN ] string_recite_test
[ OK ] string_recite_test
[ RUN ] string_recite_test
[ OK ] string_recite_test
[ RUN ] string_recite_test
[ OK ] string_recite_test
[ RUN ] line_aware_test
(shared) between tests, line=42 memory=One string to rule them all, One Ring to find them,
[ OK ] line_aware_test
[ RUN ] string_recite_test
[ OK ] string_recite_test
[ RUN ] string_recite_test
[ OK ] string_recite_test
[ RUN ] string_recite_test
[ OK ] string_recite_test
[ RUN ] string_recite_test
[ ERROR ] --- "Three strings for the Elven-kings under the sky," != "Not quite what I expected"
[ LINE ] --- aa.c:100: error: Failure!
[ FAILED ] string_recite_test
[ RUN ] string_recite_test
[ ERROR ] --- "even for the Dwarf-lords in halls of stone," != "Not quite what I expected"
[ LINE ] --- aa.c:101: error: Failure!
[ FAILED ] string_recite_test
[ RUN ] line_aware_test
(shared) between tests, line=42 memory=Not quite what I expected
[ OK ] line_aware_test
[ RUN ] string_recite_test
[ ERROR ] --- "Nine for Mortal Men, doomed to die," != "Not quite what I expected"
[ LINE ] --- aa.c:102: error: Failure!
[ FAILED ] string_recite_test
[ RUN ] string_recite_test
[ ERROR ] --- "One for the Dark Lord on his dark throne" != "Not quite what I expected"
[ LINE ] --- aa.c:103: error: Failure!
[ FAILED ] string_recite_test
[ RUN ] string_recite_test
[ ERROR ] --- "In the Land of Mordor where the Shadows lie." != "Not quite what I expected"
[ LINE ] --- aa.c:104: error: Failure!
[ FAILED ] string_recite_test
[ RUN ] string_recite_test
[ ERROR ] --- "One string to rule them all, One Ring to find them," != "Not quite what I expected"
[ LINE ] --- aa.c:105: error: Failure!
[ FAILED ] string_recite_test
[ RUN ] failing_test
[ ERROR ] --- "Sorry"
[ LINE ] --- aa.c:79: error: Failure!
[ FAILED ] failing_test
[==========] 21 test(s) run.
[ PASSED ] 14 test(s).
[ FAILED ] 7 test(s), listed below:
[ FAILED ] string_recite_test
[ FAILED ] string_recite_test
[ FAILED ] string_recite_test
[ FAILED ] string_recite_test
[ FAILED ] string_recite_test
[ FAILED ] string_recite_test
[ FAILED ] failing_test
7 FAILED TEST(S)

Related

Copy array to another array in same collection

I want to copy items from admin to newAdmins if it does not exist in the newAdmins
Before:
[
{
_id: "60801199bf57265ed8b786bc",
admins: [
"Kenny"
"Abu"
"Raj"
],
newAdmins: [
"Kenny"
"Abu"
]
}
]
After:
[
{
_id: "60801199bf57265ed8b786bc",
admins: [
"Kenny"
"Abu"
"Raj"
],
newAdmins: [
"Kenny"
"Abu"
"Raj"
]
}
]
Searched online but could not find a simpler way to do it.
One option is:
db.collection.update({},
[
{
$set: {
newAdmins: {
$setUnion: [
"$newAdmins",
"$admins"
]
}
}
}
],
{multi: true})
See how it works on the playground example

Initialize the size of global array

I need to put the output of arr in global array because I need to use the array in main function. How can I initialize the array in global and I don't know the size of it ? any idea please?
globarr[]; // how to set the size here?
int *suma(int *output, int *arr)
{
*output = 0;
for (int i = 0; i < 100; i++) {
arr[i] = i;
*output += arr[i];
}
return arr;
}
void prose(){
int *by;
int output;
int arr[100];
by = suma(&output, arr);
for (ont i=0; i<output; i++) {
globarr[i] = n[i];
}
}
void main()
{
prose();
// here I need to use the values of globarr
}
I need to put the output of arr in global array
The only reason you might need to do that would be that some external authority you are bound to obey placed such an arbitrary, unnatural requirement.
It is possible to write conforming C code for any task, using only the C standard library, that does not rely on any global variables other than those few provided by the standard library itself.
because I need to use the array in main function. How can I initialize the array in global and I don't know the size of it ?
You cannot. The size of an array declared at file scope must be an integer constant expression, which means, among other things, that it must be computable at compile time.
any idea please?
You have two main alternatives:
Choose an upper bound on the size your program will support, and declare an array large enough for that. Make the program abort if otherwise it would try to use more elements of the array than are available.
Use a dynamically allocated space instead of a (declared) array.
Use function parameters and return values not global variables
long long suma(int **arr, size_t size)
{
long long output = 0;
*arr = malloc(size * sizeof(**arr));
if(*arr)
{
for (size_t i = 0; i < size; i++)
{
(*arr)[i] = i;
output += (*arr)[i];
}
}
return output;
}
#define SIZE 100
void main(void)
{
int *array;
long long output = suma(&array, SIZE);
printf("Sum of elements = %lld\n", output);
/* you can use the array */
if(array)
{
for(size_t i = 0; i < SIZE; i++)
{
printf("[%3zu]=%d%s", i, array[i], ((i + 1) % 10) ? ",\t" : "\n");
}
}
free(array);
}
https://godbolt.org/z/EPdxfPzoq
Output:
Sum of elements = 4950
[ 0]=0, [ 1]=1, [ 2]=2, [ 3]=3, [ 4]=4, [ 5]=5, [ 6]=6, [ 7]=7, [ 8]=8, [ 9]=9
[ 10]=10, [ 11]=11, [ 12]=12, [ 13]=13, [ 14]=14, [ 15]=15, [ 16]=16, [ 17]=17, [ 18]=18, [ 19]=19
[ 20]=20, [ 21]=21, [ 22]=22, [ 23]=23, [ 24]=24, [ 25]=25, [ 26]=26, [ 27]=27, [ 28]=28, [ 29]=29
[ 30]=30, [ 31]=31, [ 32]=32, [ 33]=33, [ 34]=34, [ 35]=35, [ 36]=36, [ 37]=37, [ 38]=38, [ 39]=39
[ 40]=40, [ 41]=41, [ 42]=42, [ 43]=43, [ 44]=44, [ 45]=45, [ 46]=46, [ 47]=47, [ 48]=48, [ 49]=49
[ 50]=50, [ 51]=51, [ 52]=52, [ 53]=53, [ 54]=54, [ 55]=55, [ 56]=56, [ 57]=57, [ 58]=58, [ 59]=59
[ 60]=60, [ 61]=61, [ 62]=62, [ 63]=63, [ 64]=64, [ 65]=65, [ 66]=66, [ 67]=67, [ 68]=68, [ 69]=69
[ 70]=70, [ 71]=71, [ 72]=72, [ 73]=73, [ 74]=74, [ 75]=75, [ 76]=76, [ 77]=77, [ 78]=78, [ 79]=79
[ 80]=80, [ 81]=81, [ 82]=82, [ 83]=83, [ 84]=84, [ 85]=85, [ 86]=86, [ 87]=87, [ 88]=88, [ 89]=89
[ 90]=90, [ 91]=91, [ 92]=92, [ 93]=93, [ 94]=94, [ 95]=95, [ 96]=96, [ 97]=97, [ 98]=98, [ 99]=99

How to remove arrays inside array if a condition is met

I have an object schema that looks like this:
{
"_id":"ObjectId(""30t00594537da2r7awe083va"")",
"balances":{
"intraday":[
[
1630939075734,
1899.09
],
[
1630939435939,
1899.32
],
[
1632306730756,
0
],
[
1632306759376,
0
],
[
1632272012916,
1372.22
]
]
}
}
I want to remove all arrays within "balances.intraday" array whose the second element is equal to 0.
so my desired array will looks like this:
{
"_id":"ObjectId(""30t00594537da2r7awe083va"")",
"balances":{
"intraday":[
[
1630939075734,
1899.09
],
[
1630939435939,
1899.32
],
[
1632272012916,
1372.22
]
]
}
}
I tried to use the $pull command but it only removes the index and not the whole array.
======================= Edit =======================
Thanks to Tom Slabbaert the solution is as follows :
db._get_collection().update_many(
{},
[
{
"$set": {
"balances.intraday": {
"$filter": {
"input": "$balances.intraday",
"cond": {
"$ne": [
{
"$arrayElemAt": [
"$$this",
1
]
},
0
]
}
}
}
}
}
])
You should use pipelined updates for this, like so:
db.collection.updateMany(
{},
[
{
$set: {
"balances.intraday": {
$filter: {
input: "$balances.intraday",
cond: {
$ne: [
{
$arrayElemAt: [
"$$this",
1
]
},
0
]
}
}
}
}
}
])
Mongo Playground

Why does Chutzpah only see the tests if they listed under "References" section and doesn't if they under "Tests"

I have a quite big solution with a few web module projects (they are kind of modules and they are copied into a common project which is the SPA). I started to write jasmine-typescript tests against my angular 1.5.8 code. In order to spare copying time I need to set up Chutzpah for every web project so I can test every module code.
I have the chutzpah.json below and this way when I select "Open in Browser" then I can see the tests.
{
"Framework": "jasmine",
"FrameworkVersion": "2",
"Compile": {"Mode": "External"},
"References": [
{
"Path": "../../where_angular_and_other_scripts_are_placed/",
"Includes": [ "*.js" ]
},
{
"Path": "../../where_angular-mocks_are_placed/",
"Includes": [ "*.js" ]
},
{
"Path": "../../CommonLibrary/",
"Includes": [ "*.js" ],
"Excludes": [ "*.Spec.js" ]
},
{
"Path": "app/modules/Framework/",
"Includes": [ "*.Spec.js" ]
}
]
}
If I change the file like below then there are no tests. I don't understand why. Chutzpah cannot manage that a solution has more than one chutzpah.json in different directories? According to the documentation it shouldn't be problem.
{
"Framework": "jasmine",
"FrameworkVersion": "2",
"Compile": {"Mode": "External"},
"References": [
{
"Path": "../../where_angular_and_other_scripts_are_placed/",
"Includes": [ "angular.js", "*.js" ]
},
{
"Path": "../../where_angular-mocks_are_placed/",
"Includes": [ "*.js" ]
},
{
"Path": "../../CommonLibrary/",
"Includes": [ "*.js" ],
"Excludes": [ "*.Spec.js" ]
}
],
"Tests": [
{
"Path": "app/modules/Framework/",
"Includes": [ "*.Spec.js" ]
}
]
}
Another issue with Chutzpah setup is that, it always says that angular is not defined. I have the code below and when I run it it says angular is not defined. If I remove the inject part then it runs. But, I need to mock things. I have the bad feeling the above configuration issue and the stuff below somehow connected.
describe("getActiveModules method", (): void =>
{
var RestangularMock: any;
var angularCommonCheckerService:AngularCommonCheckerService;
var dilibModuleService: IDiLibModuleService;
var $q: ng.IQService;
var allReturnObject: any;
beforeEach((): void =>
{
//#region Arrange
angular.mock.inject(($injector): void => {
$q = $injector.get("$q");
});
RestangularMock = jasmine.createSpyObj("Restangular", ["all", "post"]);
angularCommonCheckerService = new AngularCommonCheckerService();
dilibModuleService = new DilibModuleService(RestangularMock, angularCommonCheckerService);
var returnList: IModuleContract[] = [
<IModuleContract>{ id: 100, isActive: 1 },
<IModuleContract>{ id: 101, isActive: 1 },
];
var allReturnObject = <any>{
getList: (): IModuleContract[]> => {
var deferred = $q.defer();
deferred.resolve(returnList);
return deferred.promise;
}
};
spyOn(allReturnObject, "getList");
//#endregion
});
it("should call Restangular resource with given string", (): void =>
{
RestangularMock.all.and.returnValue(allReturnObject);
dilibModuleService.getActiveModules();
expect(RestangularMock.all).toHaveBeenCalledWith("FrameworkApp/Module/GetActiveModules");
expect(allReturnObject.getList).toHaveBeenCalledTimes(1);
});
Questions:
Why Chutzpah doesn't list tests when the test references listed under "Test"? Did I do something wrong?
Is the issue around inject connected to the configuration issue?
how can I debug Chutzpah and see what is included from the references and tests? It is enough to check the source of the generated html file?

spring-mongo Given DBObject must be a BasicDBObject

I have a odd error happening when I upgraded spring-data-mongo from 1.3.2.RELEASE to 1.5.2.RELEASE
I have an object that looks something like this:
#Document(collection = "foos")
public class Foo {
#Id
private String id;
private GeoPoint[] tracks;
}
public class GeoPoint {
GeoPointValue[] points;
}
public class GeoPointValue {
#Field(value = "0")
double lon;
#Field(value = "1")
double lat;
#Field(value = "2")
double value;
}
I have a test tat creates one of these objects, saves it, then reloads it. When it saves it looks like this:
{
"_class" : "com.Foo",
"_id" : ObjectId("53f6630df91f68368b17da91"),
"tracks" : [
{
"points" : [
[
0,
0,
999.9000244140625
],
[
1.8605,
-7.6815,
1
],
[
1.0885,
-0.0001,
1
]
]
},
{
"points" : [
[
-0.0001581075944187447,
-0.003384031509668049,
999.9000244140625
],
[
-0.0003763519887295627,
-0.003578620265780311,
1
],
[
-0.0006024558351500737,
-0.003581886877337006,
1
]
]
}
],
"version" : 0
}
but when it reloads I get the following exception which I have traced to the points array:
java.lang.IllegalArgumentException: Given DBObject must be a BasicDBObject! Object of class [com.mongodb.BasicDBList] must be an instance of class com.mongodb.BasicDBObject
at org.springframework.util.Assert.isInstanceOf(Assert.java:337)
at org.springframework.data.mongodb.core.convert.DBObjectAccessor.<init>(DBObjectAccessor.java:47)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.<init>(MappingMongoConverter.java:1046)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.getParameterProvider(MappingMongoConverter.java:230)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:242)
For spring-data-mongodb, GeoPointValue is a Map structure, so what it expects is BasicDBObject type - BasicDBList is for List structure, this is the reason for the exception, I think.
You can try to change values of #Field in GeoPointValue from "0", "1", "2" to "a", "b", "c", maybe the exception will disappear.
I feel weird that "points" value is [ [ ],[ ],[ ] ], it should be [ { }, { }, { } ]. You can revert the mongo-java-driver from 2.12.3 to 2.11.3, if the points value is [ { }, { }, { } ] after saving, then maybe the driver make some special treatment for Number Key but spring-data-mongodb hasn't caught it up yet.
I had The Same Problem
and I Solved it By Adding #DBRef to the field

Resources