I'm using CUnit for my project unit testing.
I need to test whether I call libc functions with the right parameters & whether I treat their return values the right way.
for example: if I call the bind(...) function - I would like to check which af param I pass & assert if this is the wrong one, and also I would like to emulate it's return value & assert if I check it the right way.
For these purposes I would expect the CUnit environment to have a built-in mechanism to let me call a 'mocked' bind() function while testing and a real bind() function when running the code - but I can't find anything like this.
Can you please tell me if I'm missing something in CUnit, or maybe suggest a way to implement this.
Thanks,
Jo.
Unfortunately, you can't mock functions in C with CUnit.
But you can implement your own mock functions by using and abusing of defines :
Assuming you define UNITTEST when compiling for tests, you can in the tested file (or in a include) define something like this :
#ifdef UNITTEST
#define bind mock_bind
#endif
In a mock_helper.c file that you will compile in test mode :
static int mock_bind_return; // maybe a more complete struct would be usefull here
static int mock_bind_sockfd;
int mock_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
CU_ASSERT_EQUAL(sockfd, mock_bind_sockfd);
return mock_bind_return;
}
Then, in your test file :
extern int mock_bind_return;
extern int mock_bind_sockfd;
void test_function_with_bind(void)
{
mock_bind_return = 0;
mock_bind_sockfd = 5;
function_using_bind(mock_bind_sockfd);
}
glibcmock is a solution of mocking libc function with Google Test. for example:
#include "got_hook.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <sys/socket.h>
#include <mutex>
#include <memory>
struct MockBind {
MOCK_METHOD3(Bind, int(int, const struct sockaddr*, socklen_t));
};
static MockBind *g_mock{nullptr};
static int Bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
return g_mock->Bind(sockfd, addr, addrlen);
}
static std::mutex g_test_mutex;
TEST(BindTest, MockSample) {
std::lock_guard<std::mutex> lock(g_test_mutex);
std::unique_ptr<MockBind> mock(g_mock = new MockBind());
testing::GotHook got_hook;
ASSERT_NO_FATAL_FAILURE(got_hook.MockFunction("bind", (void*)&Bind));
// ... do your test here, for example:
struct sockaddr* addr = nullptr;
EXPECT_CALL(*g_mock, Bind(1, addr, 20)).WillOnce(testing::Return(0));
EXPECT_EQ(0, bind(1, addr, 20));
}
Related
(Not sure whether this is exclusively a C/C++ issue)
I’m currently fragmenting elements of a large Arduino project into reusable libraries - so far soo good.
However, a number of methods in the libraries return special structs which are declared in a data-types.h file contained in each library. The problem I have now is I'm unable to import/utilise these structs in my main sketch. I've tried declaring a variable of the DataTypes class in the main library header file and accessing the structs through it, but I get error error: invalid use of 'struct DataTypes::_theStructNameHere_t'
How would I go about accessing these structs from the library in my main sketch to declare as a variable type? I don't want to have to copy the header file which contains the structs from the library into my sketch, and I also don't want to have to create a separate library just for this single header file of structs!
Here's a quick example of what I mean:
Main.cpp:
#include <Arduino.h>
#include <MyLibrary.h>
MyLibrary myLib;
void setup() {
(This is declared in the library) myLib.dataTypes._theStructNameHere_t response = myLib.getASpecialValueWhichIsOfType_theStructNameHere_t()// Gives "error: invalid use of 'struct DataTypes::_theStructNameHere_t'""
// Example usage of the struct:
Serial.print("\n Loop Card Status: ");Serial.print(response.loop_status, HEX);
if (response.number_allocated > 0) {
Serial.print("\n Devices Allocated: ");Serial.print(response.number_allocated, HEX);
} else {
if (response.loop_status != 0x123) {
// Some condition
} else {
// Something else
}
}
}
void loop() {
...
}
Library Structure:
src/
- /data-types/
- - data-types.h
- MyLibrary.cpp
- MyLibrary.h
Library Header MyLibrary.h:
#ifndef _MYLIBRARY_H_
#define _MYLIBRARY_H_
#include <Arduino.h>
#include "./helpers/helpers.h"
...
#include "./data-types/data-types.h"
class MyLibrary {
public:
Uart *_commPort;
Helpers helpers;
...
DataTypes dataTypes;
DataTypes::_theStructNameHere_t getASpecialValueWhichIsOfType_theStructNameHere_t();
...
protected:
private:
};
#endif // _MYLIBRARY_H_
DataTypes Class data-types.h:
#ifndef _RESPONSE_TYPES_H
#define _RESPONSE_TYPES_H
class DataTypes
{
public:
struct _theStructNameHere_t
{
bool successful;
uint8_t loop_status;
uint8_t number_allocated;
uint8_t highest_address;
uint8_t number_inputs;
uint8_t number_outputs;
}
..even more..
private:
}
#endif // _RESPONSE_TYPES_H
I was able to obtain a MCVE from your example:
class DataTypes
{
public:
struct _theStructNameHere_t
{
};
};
class Library
{
public:
DataTypes dataTypes;
DataTypes::_theStructNameHere_t getMyDataType();
};
int main(int argc, char *argv[])
{
Library myLib;
myLib.dataTypes._theStructNameHere_t response;
}
which gives a similar error as your code:
~$ g++ test.cpp
test.cpp: In function 'int main(int, char**)':
test.cpp:20:21: error: invalid use of 'struct DataTypes::_theStructNameHere_t'
myLib.dataTypes._theStructNameHere_t response;
The problem is that you use an instance to access the struct type/name. To fix it, replace
myLib.dataTypes._theStructNameHere_t response = ...;
with
DataTypes::_theStructNameHere_t response = ...;
Notes:
Instead of using classes to create separate namespaces, please consider using namespaces directly. This is a feature of C++ which is available under Arduino.
namespace Library {
namespace DataTypes {
struct _theStructNameHere_t
{
...
};
...
} /*** namespace Library::DataTypes ***/
} /*** namespace Library ***/
Please read StackOverflow guidelines concerning how to ask a good question, in particular the section about Mininimal, Complete and Verifiable Example.
Sooner or later someone will tell you that there is no such thing as C/C++; C is C and C++ is C++; Arduino lives in its own world, even if is based on C++. Thus, you might want to remove C and C++ tags from your question.
I wanted to give the aRest library
a function to expose to the api.
But I am importing a customlibrary,
I wanted to give the aRest instance a function in that library.
This is my code
#include <ESP8266mDNS.h>
#include <ESP8266WiFi.h>
#include <aREST.h>
#include <EEPROM.h>
#include <WiFiClient.h>
//My Custom Made C/C++ Libraries
#include <DeviceEeprom.h>
#include <DeviceRoute.h>
//Creating my customLib instances
DeviceEeprom deviceEeprom = DeviceEeprom();
DeviceRoute deviceRoute = DeviceRoute();
// Create aREST instance
aREST rest = aREST();
int myFunction();
void setup()
{
Serial.begin(115200);
rest.set_id("1");
rest.set_name("esp8266");
rest.function("myFunction" &myFunction);
}
void loop()
{
}
int myFunction()
{
return 1;
}
I wanted to go from this.
rest.set_function("myFunction" &myFunction);
To this.
rest.set_function("myFunction" deviceRoute.myFunction());
UPDATE
I found the rest.function() code
This is the code
void function(char * function_name, int (*f)(String)){
functions_names[functions_index] = function_name;
functions[functions_index] = f;
functions_index++;
}
Mayby this helps out?
There's no way to pass a pointer to a non-static member function directly to aREST::function.
Non-static member functions are different than static member functions and freestanding functions. They require an object to work on. That means that &DeviceRoute::myFunction is not compatible with the type int(*)(String). Instead it's a int (DeviceRoute::*)(String).
To make this work, you need a static or freestanding wrapper function that calls the member function you want. Since aREST::function doesn't accept any sort of context pointer, your only real option is to use a global variable:
//Creating my customLib instances
DeviceEeprom deviceEeprom;
DeviceRoute deviceRoute;
// Create aREST instance
aREST rest;
int myFunction(String s)
{
return deviceRoute.myFunction(s);
}
void setup()
{
Serial.begin(115200);
rest.set_id("1");
rest.set_name("esp8266");
rest.function("myFunction" &myFunction);
}
void loop()
{
}
#include <netlink/socket.h>
#include <netlink/netlink.h>
struct nl_sock *sock;
sock = nl_socket_alloc();
The above code always fails to compile with the following error:
/home/micah/Documents/C++/Socket_fun/Socket_fun/src/main.cpp|5|error: ‘sock’ does not name a type
I got this from the libnl example, and as it doesn't work, I am wondering, what is the correct way to do this?
That code has to be in a function, you can't just start calling functions outside the context of a function:
int main()
{
struct nl_sock *sock;
sock = nl_socket_alloc();
}
Also, what are you compiling with? I would recommend compiling it as C, not C++.
I am attempting to make an AIR Native Extension and after successful compilation of all components, Flash Builder 4.6 logs "Error #3500: The extension context does not have a method with the name...".
Here's the C++ code for the native DLL:
#include "stdafx.h"
#include "TestANE.h"
#include "FlashRuntimeExtensions.h"
#include <string>
#include <iostream>
#include <iomanip>
#include <algorithm>
using namespace std;
FREObject isSupported(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]) {
FREObject result;
uint32_t isSupportedSwitch = 1;
FRENewObjectFromBool(isSupportedSwitch, &result);
return result;
}
FREObject getString(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]) {
FREObject result;
const char *testString = "Hello World from C++!";
FRENewObjectFromUTF8(strlen(testString)+1, (const uint8_t *) testString, &result);
return result;
}
void taneContextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctions, const FRENamedFunction** functions) {
*numFunctions = 2;
FRENamedFunction* func = (FRENamedFunction*) malloc(sizeof(FRENamedFunction) * (*numFunctions));
func[0].name = (const uint8_t*) "isSupported";
func[0].functionData = NULL;
func[0].function = &isSupported;
func[1].name = (const uint8_t*) "getString";
func[1].functionData = NULL;
func[1].function = &getString;
*functions = func;
}
void taneContextFinalizer(FREContext ctx) {
return;
}
void taneInitializer(void** extData, FREContextInitializer* ctxInitializer, FREContextFinalizer* ctxFinalizer) {
*ctxInitializer = &taneContextInitializer;
*ctxFinalizer = &taneContextFinalizer;
}
void taneFinalizer(void* extData) {
return;
}
Here's the code for the ActionScript 3 interface:
package com.tests.TestANE {
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.external.ExtensionContext;
public class TestANE extends EventDispatcher {
private var _ExtensionContext:ExtensionContext;
public function TestANE(target:IEventDispatcher=null) {
this._ExtensionContext = ExtensionContext.createExtensionContext("com.tests.TestANE", null);
super(target);
}
public function isSupported():Boolean {
return _ExtensionContext.call("isSupported") as Boolean;
}
public function getString():String {
return _ExtensionContext.call("getString") as String;
}
public function dispose():void {
this._ExtensionContext.dispose();
}
}
}
Any help in solving this issue would be appreciated.
Please see before here: http://forums.adobe.com/thread/923158
If you got this error when you have more than one extension inside the same project, please be careful: EVERY initializer end finalizer methods MUST have different and unique names between ALL the extensions.
NB. Not only the methods specified in extension.xml but also the ones you delagate to initialize the context. To be clear: NOT only the extension initializer but also the context initializer inside the project MUST have unique names between ALL the extensions.
Eg.:
void UNIQUE_NAME_ExtInitializer(void** extDataToSet, FREContextInitializer* ctxInitializerToSet,
FREContextFinalizer* ctxFinalizerToSet) {
NSLog(#"Entering ExtInitializer()");
*extDataToSet = NULL;
*ctxInitializerToSet = &UNIQUE_NAME_ContextInitializer;
*ctxFinalizerToSet = &UNIQUE_NAME_ContextFinalizer;
NSLog(#"Exiting ExtInitializer()");
}
void UNIQUE_NAME_ContextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx,
uint32_t* numFunctionsToTest, const FRENamedFunction** functionsToSet)
{
*numFunctionsToTest = 1;
FRENamedFunction* func = (FRENamedFunction*) malloc(sizeof(FRENamedFunction) * 1);
func[0].name = (const uint8_t*) "scan";
func[0].functionData = NULL;
func[0].function = &scan;
*functionsToSet = func;
}
And the same for the finalizer.
I hope this helps.
To resolve symbol name conflicts between ANEs, there is a new ADT option in AIR 3.4 i.e. hideANELibSymbols
Refer: http://help.adobe.com/en_US/air/build/WS901d38e593cd1bac1e63e3d128cdca935b-8000.html
Also, to ease the process of getting started with writing an ANE for iOS, I've written an xcode ANE template.
Refer: https://github.com/divijkumar/xcode-template-ane
Do read the instructions on the github wiki page before getting started.
Had the same issue but on concrete machine (others work just fine) and nothing help until i rebuild my dll with release flag. It seems like debug version request some addination dll's installed on user pc, so make sure you build with release flag!
It appears that the C++ function "getString" has required arguments. So when you are calling _ExtensionContext.call("getString") as String;
C++ does not have a getString() method. It wants you to pass through arguments also. Add these to teh call method like so:
_ExtensionContext.call("getString", arg, arg1, arg2) as String;
The arguments you pass must be of the appropriate type specified by the c++ getString method.
See the reference:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/external/ExtensionContext.html#call()
I've solved this problem. I am not completely certain how as I started with another ANE project and built from there. I suspect however that the problem had to do with wrong package names in the ActionScript part of the code and the extension descriptor.
This question is old, but there is no solid answer. I ran into the same issue with an Android ANE. In your FREExtension function/class, you must return a new instance of FREContext and in that instance of FREContext, you must return the function map. I made the mistake of not returning the map and running around like a chicken with its head cut off trying to figure out what was going on. Hopefully that will help someone in the future.
I had this same issue and none of the other answers here solved it for me. I was trying to create a simple c++ ANE for the Blackberry Playbook and would get an error #3500 any time I tried to run it. The same exact code worked fine in C. It turns out the c++ compiler was doing method name mangling so it could not find the method I was calling. I solved it by wrapping my function definitions in extern "C" like this:
extern "C" {
void ExtensionInitializer(void** extDataToSet,
FREContextInitializer* ctxInitializerToSet,
FREContextFinalizer* ctxFinalizerToSet);
void ExtensionFinalizer();
void ContextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx,
uint32_t* numFunctionsToSet, const FRENamedFunction** functionsToSet);
void ContextFinalizer(FREContext ctx);
FREObject myMethod(FREContext ctx, void* functionData, uint32_t argc,
FREObject argv[]);
}
I have succesfully using dyld -macosx- to interpose standard C functions to a third party application, getting important information about the workarounds it does. But what I really need is to replace a certain function of a certain class.
The function I want to override is QString::append(..., ..., ...), so each time a string is appended to another -the whole application uses qstring-, i find out.
Is there a way? Here's the code I already have.
// libinterposers.c
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdarg.h>
#include <dlfcn.h>
#include <stdlib.h>
typedef struct interpose_s {
void *new_func;
void *orig_func;
} interpose_t;
int my_open(const char *, int, mode_t);
int my_close(int);
void* my_malloc(size_t);
static const interpose_t interposers[] \
__attribute__ ((section("__DATA, __interpose"))) = {
{ (void *)my_open, (void *)open },
{ (void *)my_close, (void *)close },
{ (void *)my_malloc, (void *)malloc },
};
int
my_open(const char *path, int flags, mode_t mode)
{
int ret = open(path, flags, mode);
printf("--> %d = open(%s, %x, %x)\n", ret, path, flags, mode);
return ret;
}
int
my_close(int d)
{
int ret = close(d);
printf("--> %d = close(%d)\n", ret, d);
return ret;
}
void*
my_malloc(size_t size)
{
void *ret = malloc(size);
//fprintf(stderr, "Reserva de memoria");
return ret;
}
Thank you very much
C++ does name mangling. This means member function QString::mid() looks something like __ZNK7QString3midEii to the linker. Run the nm(1) command on the library you are interposing on to see the symbols.
It is going to be much easier that this. QString uses memcpy to concatenate and work with Strings, and I can easily override memcpy, and apply a regular expression to the result, logging only the strings I want. Piece of cake. No need for magic voodo-hoodo :)