Where to put implementation when using Doctest alongside code - c++

I'm using doctest for the tests in my C++ project.
I would like to put the test code alongside my implementations, as the library says is possible, but I can't seem to figure out what to do with the doctest implementation code.
I have a doctest.cpp file that looks like this:
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"
A main.cpp that looks like this:
#include "thing.h"
int main(int argc, const char *argv[]) {
do_thing();
}
thing.h is self-explanatory, but thing.cpp looks like this:
do_thing() {}
TEST_CASE("Test thing") {
CHECK(1 == 1);
}
CMake is used to create two executables, a Tests executable and a Main executable.
If I don't include doctest.cpp in my project sources for Main, I get undefined reference errors because it can't find a definition for all the testing stuff in doctest.
However, if I do include it I get errors because there are multiple main() functions in one target.
I can't find any info on this in the doctest documentation.
How are you meant to get around this?

The author of the library gave a good response in this issue:
DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN implements the test runner and also defines a main() function.
DOCTEST_CONFIG_IMPLEMENT implements ONLY the test runner.
If you define your own main() then you should use DOCTEST_CONFIG_IMPLEMENT - have a look at the relevant docs.
You will need the test runner implemented in your main executable (that means doctest.cpp) since you are writing your tests alongside your production code.
You can also define DOCTEST_CONFIG_DISABLE when building the main executable so tests are written in the production code but aren't compiled (you will still need doctest.cpp so it all links). This way you won't need to #ifdef the tests.
You could also entirely remove the test executable and use the main executable for running the tests - docs.
I went with the first option of writing my own main() function.

I encountered the same problem and one workaround is to add -DDOCTEST_CONFIG_DISABLE to the compiler flags when you compile Main.

Related

C++Builder11: How to unit test with googletest?

Until recently I've used C++Builder 10.2 for a project, and I had begun to use DUnitX to add some unit tests for the project.
Now I have upgraded to C++Builder 11.2, and found that DunitX is no longer supported for C++Builder when using this version. Instead, Embarcadero recommends to use DUnit or Googletest.
On further research, it seems that Googletest cannot be used with the classic compiler (but I'm not actually interested in using the pre-C++11 classic compiler), but also that DUnit cannot be used when targeting the Firemonkey framework, and that DUnit (1) is unmaintained and (2) does not work well with the Clang-based compiler.
I'm interested in using googletest because I have already used both, googletest and googlemock, on less niche platforms than C++Builder such as Linux/GCC, Apple/Clang and Windows/MinGW-w64. I am aware that the googletest project itself refuses to accept build files or patches for C++Builder because they do not want to spend effort to support niche compilers (see e.g. here, here, and here).
I'm happy to learn that some patched version of googletest is currently available for C++Builder through the GetIt package manager, even though it is not clear who has actually made that patch, and although I realize that Embarcadero may remove googletest from the GetIt package manager an any moment.
I've found two blog posts explaining how to install googletest in C++Builder and how to use it, however, I cannot successfully follow the second blog post when it comes to point 6, which reads
In your project group create a new windows64 bit VCL console application. Set this to use the debug settings (this allows you to debug code that doesn’t pass a unit test).As well as the files you want to test and the files containing the testing code you need to add to the project the library file …GT2021.09\cbuilder\lib\Win64\Debug\gtest.a.
I'm not sure how I am supposed to "add to the project the library file". I've tried to
copy the gtest.a and gmock.a files into the project directory and then
right-click on the project name in the "Projects" view of the IDE and select "Add...", then change file type to "static libraries", then select gtest.a and repeat with gmock.a.
Here I've gone ahead and have already added gmock.a because I have experience with googlemock and envision that its additional matchers and mock class generators will help me writing tests.
When I compile a simple test project that does not actually perform any tests, everything compiles and links fine, but when I execute the resulting command line program, then it fails with exit code (errorlevel) -1073741819 and produces no output. This does not happen if I comment all usages of googletest out.
The simple test project which fails during execution consists only of
#include <gtest/gtest.h>
#include <vcl.h>
#include <tchar.h>
int _tmain(int argc, _TCHAR* argv[])
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
which should cause googletest to print that 0 tests were executed, but instead it crashes as described. When replacing the two lines in main with a simple printf, which does not use googletest, but leaving all includes unaltered and without altering the project with regard to libraries, it works fine (the new printf prints something) but of course cannot perform any tests.
How to fix this?
One more observation: When adding the static libraries to the project as described above, I get a notification message box from the IDE, saying "One or multiple lines were too long and have been truncated". I have no idea how this message could make sense with regard to adding a static library to the project. It seems however, that this is not an error, and the linker actually uses the static libraries when linking.
The main problem here was the inclusion of the gmock.a library as it was compiled by the GetIt googletest package. This gmock project and basically all other gmock projects in the GetIt package are broken and need to be repaired before using them. I may post more details about this in a future topic. The gmock.cbproj project as distributed by GetIt, e.g., includes the unrelated source file googletest\samples\sample8_unittest.cc, among other errors.
A simple method to use googletest with C++Builder 11.2, which is based on the blog posts by Cigol, but which does not require to copy include files and library files:
When installing googletest with the getit package manager, the IDE automatically opens a group project Googletest.groupproj and compiles two of the contained projects (gtest and gtest_main) for the Windows 64 bit platform in "Release" mode. Furthermore, all other project files in the Googletest project group are modified probably because they have been updated from an earlier C++Builder version and want to be saved when closing the IDE.
There is no need to compile googletest in "Debug" mode, one would need that only for debugging the unit testing framework itself.
Next, create a new VCL Windows 64 bit console application to start using googletest:
File -> New -> "Console Application - C++Builder"
Source Type: C++, Target Framework: Visual Component Library, [OK]
Add Target Platform Windows 64-Bit in the "Projects" view (right-click on Target Platforms).
Delete Target Platform Windows 32-Bit.
Save all in a dedicated directory:
File -> Save All
Create a new folder, e.g. MyUnitTests.
Place project file as e.g. MyUnitTests.cbproj into that folder.
Rename File1.cpp to MyTestsMain.cpp and store in that folder
This creates a C++ source file MyTestsMain.cpp with some includes and an empty main function:
#include <vcl.h>
#include <tchar.h>
int _tmain(int argc, _TCHAR* argv[])
{
}
For convenience, googletest provides a library gtest_main.a which only contains a main function that one can use to execute all unit tests compiled into an executable. By linking against the gtest_main.a library, users can avoid writing their own main function and concentrate on only writing test code. But since the C++Builder wizard has already created a main function, one can as well fill the generated main function with the necessary boilerplate code (only two lines are required, compare against the googletest main function in C:\Users\yourLogin\Documents\Embarcadero\Studio\22.0\CatalogRepository\GoogleTest-2021.09\googletest\src\gtest_main.cc) and add the gtest.h include directive:
#include <gtest/gtest.h>
#include <vcl.h>
#include <tchar.h>
int _tmain(int argc, _TCHAR* argv[])
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Trying to build this project fails because the gtest/gtest.h include file is not found. This can be fixed in Project -> "Options..." -> Building -> C++ Shared Options -> "Include path": After selecting "All configurations - All platforms" in the drop-down list "Target", add the following entry to "Include path":
$(BDSCatalogRepository)\GoogleTest-2021.09\googletest\include
Using the variable $(BDSCatalogRepository) avoids machine- and developer-specific absolute PATHs. Save the changed project settings with File -> "Save all". Trying again to build this project now fails because of different errors, which is progress! The errors now are "Unresolved external"s, which means we have to tell the project to link against gtest.a and where to find it. Linking against gtest.a can be done by adding a pragma to the top of the file containing the main function:
#pragma comment(lib,"gtest")
#include <gtest/gtest.h>
#include <vcl.h>
#include <tchar.h>
int _tmain(int argc, _TCHAR* argv[])
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Where to find the library can be configured in Project -> "Options..." -> Building -> C++ Shared Options -> "Library path": Again first select "All configurations - All Platforms", then add the following entry to "Library path":
$(BDSCatalogRepository)\GoogleTest-2021.09\cbuilder\lib\$(Platform)\Release
After File -> "Save All", a new, clean build generates different "Unresolved external"s, progress! This time, symbols from the standard C++ library are missing, which can be fixed via Project -> "Options..." -> Building -> C++ Linker, again for Target "All configurations - All platforms", check the checkbox "Link with Dynamic RTL, Windows...". After another File -> "Save All", a clean build succeeds and executing the generated Win64\Debug\MyUnitTests.exe generates this output:
[==========] Running 0 tests from 0 test suites.
[==========] 0 tests from 0 test suites ran. (0 ms total)
[ PASSED ] 0 tests.
One can now add tests to the test project. Tests can be added to the source file which contains the main function or to different, topic-specific source files. I'll add two tests in new files for demonstration:
In the "Projects" view, right click on the current project, which is confusingly named "MyUnitTest.exe" in the project view with an ".exe" extension instead of a project file extension, then select "Add new..." -> Unit in the popup menu. "Unit" here is C++Builder's language for a pair of one source and one header file, and is not necessarily related to unit testing.
The new files are initially named "Unit1.cpp" and "Unit1.h" but can be renamed when doing File -> "Save All". I name this first test file to "SelfContainedTest.cpp" because its test will be self-contained. Add the following code to the .cpp file after the IDE-Generated boilerplate:
#include <gtest/gtest.h>
TEST(SelfContained, Addition) {
EXPECT_EQ(3, 1+2);
EXPECT_GT(3, 2+2);
}
Rebuilding succeeds, execution reveals that the second EXPECT fails as it should, the number 3 is in fact not greater than the sum 2+2. Fix if you like.
In a second test, I want to test non-GUI methods of an existing VCL form. In a real-world scenario, the GUI project and my test project would be part of the same project group and live in the same directory or below the same parent directory, and I would add the VCL form's .cpp file also to the test project with (Project View) -> right click -> "Add..." -> C++Builder unit (*.cpp). My form TAdderForm that I'm using here is a simple form with two VCL TEdit fields for entering numbers and a VCL TLabel to display the sum of the two numbers. The sum is computed in a method
int TAdderForm::add(int num1, int num2)
{
return num1 + num2;
}
which I want to test here. To write the test, I add a new "Unit" to the test project as before, naming the source file "VCLTest.cpp" this time. After the IDE-generated boilerplate, I add this code to the .cpp file:
#include "adderFormx.h"
#include <gtest/gtest.h>
TEST(VCL, Addition) {
// Have to instantiate VCL form before calling its method.
Application->CreateForm(__classid(TAdderForm), &AdderForm);
EXPECT_EQ(3, AdderForm->add(1,2));
EXPECT_GT(3, AdderForm->add(2,2));
delete AdderForm; // Delete no longer used form.
AdderForm = nullptr; // clear pointer, another test may allocate new instance
}
This is basically the same test as before. The second expectation will fail again and needs to be fixed because 3>4 is a wrong expectation. The test uses the global instance pointer "AdderForm" from the form's source file for simplicity, this can be modified if required. If multiple tests want to instantiate the same form, a fixture should be used and the setup and teardown done here inside the test should be moved to the fixture's respective methods, but this is no longer C++Builder specific.
Note that Application->Run() is never called, and no GUI elements actually appear on the screen when executing the tests. I'm restricting tests to non-GUI methods of the GUI classes.

Dealing with multiple projects in visual studios

I am trying to figure out how to deal with multiple projects under the banner of a single solution and how to correctly link projects in order to make things work in conjunction.
I began by making two projects in one solution - for simplicity's sake, ProjA and ProjB. ProjB is set as the StartUp project. Furthermore, ProjA is configured to be built as a .dll file which I am to link with ProjB, which in turn is configured to be built as a .exe file. So far I've linked ProjA to ProjB by adding a dependency to ProjB via referencing (RMB>Add>Reference).
With all that out of the way, I wanted to test whether the setup worked as intended. So I did the following. In ProjA, I wrote the following Test code:
Test.h
#pragma once
namespace ProjA {
_declspec(dllexport) void Print();
}
Test.cpp
#include "Test.h"
#include <stdio.h>
namespace ProjA {
void Print()
{
printf("Testing\n");
}
}
And in ProjB:
TestEntry.cpp
#include <stdio.h>
namespace ProjA {
_declspec(dllimport) void Print();
}
void main()
{
ProjA::Print(); //breakpoint1
printf("Testing (2)\n"); //breakpoint2
}
I set two breakpoints at the commented lines for debugging, built the projects and ran the program. At breakpoint1, I expected the console to print "Testing" and proceed to the next line, followed by breakpoint2 printing "Testing (2)" and proceeding to the next line before exiting. However, the console was blank at breakpoint1. It only printed the line from the main function at breakpoint2.
So what am I doing wrong here? Is there something wrong with the way I included the projects? Was there a linking procedure I skipped? Is there a specific way I need to set up Visual Studios 2017 in order for it to work? Are there other plugins/APIs I should be installing?
To test it out further, I commented out everything in ProjA. This time I expected a linking error when building the projects, but everything ran in the exact same manner. This confused me even more. It's as if I didn't even link the projects and the main function is not identifying the Test codes via the include. That's the only thing I could deduce so far.
As suggested by SoronelHaetir, I redid the whole thing using #defines and namespaces. It's working as intended now. In conclusion, the crude method was a bad idea from the getgo.

Eclipse CDT Including Unreferenced Files in Automatically Generated Build

I'm new to cpp in eclipse and trying to mess with simple builds. I have made a basic project which automatically generates build info (no user-defined makefile).
Simple (Working) Case
I made a "Hello World" project called Test (not an empty project). It has one file - Test.cpp with a main() in => builds and runs fine.
Test.cpp
int main() {
// output some stuff
}
Slightly More Complex (Working) Case
I make a new file called Main.cpp. Move the main() function into Main.cpp and make a decleration of a function in main too - void test();
The test() function lives in Test.cpp, which is where I provide the function definition.
Main.cpp
#include <iostream>
void test();
int main() {
// Use test()
}
Test.cpp
#include <iostream>
void test() {
// output some stuff
}
Build it, there are now two .o files in the Debug directory - Test.o and Main.o. This runs fine.
The Problem
Now I try to introduce a third file - Limits.cpp.
Limits.cpp
#include <iostream>
void printLimits() {
// Print out limits for different integer sizes
}
Again I provide a deceleration of this function in Main.cpp.
Main.cpp
#include <iostream>
void test();
void printLimits();
int main() {
// Use printLimits()
}
This time there is no object file created for Limits in the Debug folder => the build fails.
Main.cpp:*line* undefined reference to `getLimits()'
It just looks like the autogenerated build config for the project is duff. I've tried looking around the project properties but I have had no luck. I've tried including the path/file in Include Paths/Include files, other objects, and I've checked just about every other property I can see. This has been frustrating me for two days.
The strange thing about this is case 2. It looks like because Test.cpp was the first file made it always includes this in the build? (even if it is not imported). Where as because Limits.cpp is new and not imported it doesn't generate an object file so it can't link the function.
I could me making an error by needing to include the files but my understanding is if all the object files make it to the linker then all will be well (ie I just need the function declarations when making the object files which is what I have here).
With a "Blank project" it seems to compile all the cpp files even if they are never used so my case above works. (Although, it doesn't work for files in subfolders of src). Looks like its a "feature" of the "Hello world" project type but it's going to drive me crazy knowing there must be a way to get it to do this.
If anyone knows if it is possible to include this file without writing my own makefile (I'm not a makefile guru (yet!)), or let me know if this is not possible with autogen CDT that would be great.
Using MinGW GCC toolchain.
Thanks

Heap error with Google mock test framework

If you download the latest version of Google Mock (1.7.0) there are project files for VS2005 and 2010! The project to test is written in VS2008,so I opened the VS2005 file and converted it for VS2008 and compiled with
Multi-threaded Debug (/MTd)
Dynamic Library (.dll)
In the test solution:
Project to test:
Configuration type: Dynamic Library (.dll)
Runtime library: Multi-threaded Debug (/MTd)
UnitTest project:
#include <iostream>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
int main(int argc, char **argv)
{
::testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}
Additional Library Directories: ..\..\gmock\msvc\2005\Debug
Additional Dependencies: gmock.lib gmock_main.lib
Runtime library: Multi-threaded Debug (/MTd)
If I run the UnitTest project I get following error:
Windows has triggered a breakpoint in Program_UnitTests.exe.
This may be due to a corruption of the heap, which indicates a bug in Program_UnitTests.exe or any of the DLLs it has loaded.
in xmtx.c:
_RELIABILITY_CONTRACT
void __CLRCALL_PURE_OR_CDECL _Mtxunlock(_Rmtx *_Mtx)
{ /* unlock mutex */
LeaveCriticalSection(_Mtx);
#ifdef _M_CEE
System::Threading::Thread::EndThreadAffinity();
#endif
} // <------- STOPPED HERE
#endif /* !_MULTI_THREAD */
What is wrong here? Thank you for any help!
Super-short answer: compile googlemock as a static library instead of a dll; that might fix your problem.
Much longer answer:
Problems like this are typically the result of mismatched compiler settings. These kinds of problems are a pain to diagnose, which is a large part of the reason for the following guidance given in the googletest FAQ:
If you compile Google Test and your test code using different compiler flags, they may see different definitions of the same class/function/variable (e.g. due to the use of #if in Google Test). Therefore, for your sanity, we recommend to avoid installing pre-compiled Google Test libraries. Instead, each project should compile Google Test itself such that it can be sure that the same flags are used for both Google Test and the tests.
This applies equally to googlemock. Basically, they're suggesting that you compile the googletest & googlemock source code alongside your own code to avoid this problem. They also make this quite easy: check out the fused-src directory of the gmock distribution for a voltron .cc file and the corresponding headers, gmock.h and gtest.h.
If you'd like to continue linking against a completely separate library, you'll need to verify that all of the compiler settings match in the VS project. Basically you'll need to check every single configuration in the properties dialog, paying special attention to the toolset, exceptions, preprocessor definitions, RTTI, etc.

GMock doesn't compile - GTEST_EXCLUSIVE_LOCK_REQUIRED seems to not be defined

I'm trying to build a simple mocked class
#include "interpolation.hpp"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
class MockInterp1D : public Interp1DBase {
public:
MOCK_METHOD1(evaluateAt, double(double));
MOCK_METHOD2(evaluateAt, double(double, int));
};
based on the following base class
class Interp1DBase {
public:
virtual double evaluateAt(double) const = 0;
virtual double evaluateAt(double, int) const = 0;
virtual ~Interp1DBase() { };
};
using Google Mocks. When I try to compile the tests where this mock is used, I get the following error:
In file included from /usr/include/gmock/gmock-generated-function-mockers.h:43:0,
from /usr/include/gmock/gmock.h:61,
from /home/tlycken/exjobb/Code/alpha-orbit-follower/test/interpolation/interpolation-mocks.hpp:4,
from /home/tlycken/exjobb/Code/alpha-orbit-follower/test/physics/B-field-tests.hpp:6,
from /home/tlycken/exjobb/Code/alpha-orbit-follower/test/physics/B-field-tests.cpp:2:
/usr/include/gmock/gmock-spec-builders.h:134:41: error: expected ‘;’ at end of member declaration
bool VerifyAndClearExpectationsLocked()
^
and then literally hundreds of similar syntax or definition errors all pointing to files within GMock.
I took a look at gmock-spec-builder.h:134, and found the following (in some context):
// Verifies that all expectations on this mock function have been
// satisfied. Reports one or more Google Test non-fatal failures
// and returns false if not.
bool VerifyAndClearExpectationsLocked()
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex);
which led me to believe that GTEST_EXCLUSIVE_LOCK_REQUIRED_ might be a macro that for some reason wasn't defined. And indeed, after digging through all header files included from either gmock/gmock.h or gtest/gtest.h I still haven't found the definition of that macro.
What am I doing wrong here?
UPDATE:
I've been able to produce an even simple minimal example:
// in file mock-test.cpp
#include <gmock/gmock.h>
// Yeah, that's the only content
Compile with
g++ -o mock-test.o -c mock-test.cpp
Causes the same error.
I've installed GMock through sudo apt-get install google-mock, which gave me a folder under /usr/src where I could run cmake . followed by make to generate library files which I copied to /usr/lib. The header files were already in /usr/include so I didn't do anything about them manually.
I got the same error when I tried to compile using gmock 1.7 with gtest 1.6. Make sure you are using the same version of gtest.
I don't know how to use g-mock in gcc.
But basically we use in windows like this.
Your class definitions are right.
Did you use those functions like
EXPECT_CALL(classobj, exact functionname as it looks in definition).AtLeast(Times(0)).Return(0);
then
classobj.exact functionname as it looks in definition()
Try this I think it should work. If you want it in detail, just let me know I will expand the same with some typical example.
There are the appropriate sources & headers in the /usr/src/gmock folder.
Your job is only overwrite the whole content of folders:
/usr/src/gmock/gtest/src -> /usr/src/gtest/src
/usr/src/gmock/gtest/cmake -> /usr/src/gtest/cmake
/usr/src/gmock/gtest/CMakeLists.txt-> /usr/src/gtest/CMakeLists.txt
/usr/src/gmock/gtest/include/gtest -> /usr/include/gtest/