EV printing makes unit test fail in INET/OmNET++ - c++

I have a component I am testing:
namespace myproj {
class MyComp {
public:
void doSome();
};
}
using namespace myproj;
void MyComp::doSome() {
// Some code...
// And in the end, for debugging purposes, I print in one of the streams
EV_DEBUG << "Some debugging info" << endl;
}
My unit test
My test is an ordinary OmNET++ Unit Test using the opp_test tool:
%description:
Tests my component
%includes:
#include "myproj/MyComp.h"
%global:
using namespace ::inet::test::myproj;
%activity:
MyCompTest test = MyCompTest();
test.testDoSome();
EV << ".\n";
%contains: stdout
my test out
Of course a class MyCompTest is using MyComp in order to run some logic which will eventually invoke MyComp::doSome.
Note that testDoSome will cause the string "my test out" to be printed.
The problem
The issue is that, because of that EV_DEBUG (same happens if I change it into EV_INFO, EV_DETAIL and all other EVs) in my original class (source/simulation code), the test output is poisoned and the final output is:
Some debugging info
my test out
Which makes the test fail. If I comment out EV_DEBUG << ... then the test is fine.
How to solve this problem? Do I really have to remove all EV printouts in my original code?

You can turn off printing by EV_DEBUG by adding these lines in %activity section:
#undef EV_DEBUG
#define EV_DEBUG true ? EV : EV

Related

View cout in terminal in PlatformIO tests

I'm new to C++, and am developing for Arduino with PlatformIO & VS Code on MacOS 11.6.5.
Following the PlatformIO docs I have set up a simple test like this:
#include <unity.h>
#include <iostream>
void test_something()
{
std::cout << "Test running..." << std::endl;
TEST_ASSERT_TRUE(true);
}
int main(int argc, char **argv)
{
UNITY_BEGIN();
RUN_TEST(test_something);
UNITY_END();
}
When I run platformio test --environment local I see the test results in the terminal, but not the output of std::cout.
(I found an example of printing to cout from tests when not using PlatformIO, and the PlatformIO repo has lots of test examples, but none of these seem to involve cout.)
Also VS Code IntelliSense complains 'cannot open source file "iostream"', but I'm guessing this is unrelated as PlatformIO seems to have no problems compiling it.
Any pointers appreciated!
Ok, thanks to #Ulrich Eckhardt's help it turns out I just needed to specify --verbose mode for Unity i.e.:
platformio test --environment local --verbose
Then there are a whole bunch of ways to write to the terminal:
cout << "Hello" << endl;
cout << "Hello\n";
fprintf(stdout, "Hello");
putchar('a');
There are also Unity print methods, not sure of the pros & cons of these:
UnityPrint("Hello");
UnityPrintLen("Print this, but not this", 10);
UNITY_OUTPUT_CHAR('a');

std::cout not showing on screen

This is a fairly simple problem I can't get my head around. It was working before and suddenly now that I'm using std::cout, in the Visual Studio 2013 output window I do not see the output, but I see a bunch of background executions happening. I feel I have messed up something. This is App Game Kit project using C++.
Here's the simple code to output:
#include "template.h"
#include <iostream>
using namespace AGK;
app App;
void app::Begin(void)
{
agk::SetVirtualResolution (1024, 768);
agk::SetClearColor( 151,170,204 );
agk::SetSyncRate(60,0);
agk::SetScissor(0,0,0,0);
std::cout << "Hello"; // SIMPLE PRINT
}
void app::Loop (void)
{
agk::Print( agk::ScreenFPS() );
agk::Sync();
// std::cout << "Hello"; // TRIED HERE TOO (works like update() in Unity3D)
}
This is what my debug window is showing, instead of printing "Hello":
FYI, the program is working perfectly without any errors. Am I looking at the wrong window? where can find my output?
for logging, i write my entries to a file. here is the Contents of my log method in cpp:
void MyFileUtils::log(string msg)
{
ofstream log("logfile.txt", ios_base::app | ios_base::out);
log << msg << endl;
return;
}
i then just call this whenever i want to log something. i have it as a singleton. Then i just look in my media subfolder to see the contents of logfile.txt
Try using this before you return from the method:
log.flush();
log.close();

Process management code behaves different on Linux and Windows - Why?

(Context) I'm developing a cross-platform (Windows and Linux) application for distributing files among computers, based on BitTorrent Sync. I've made it in C# already, and am now porting to C++ as an exercise.
BTSync can be started in API mode, and for such, one must start the 'btsync' executable passing the name and location of a config file as arguments.
At this point, my greatest problem is getting my application to deal with the executable. I've come to found Boost.Process when searching for a cross-platform process management library, and decided to give it a try. It seems that v0.5 is it's latest working release, as some evidence suggests, and it can be infered there's a number of people using it.
I implemented the library as follows (relevant code only):
File: test.hpp
namespace testingBoostProcess
{
class Test
{
void StartSyncing();
};
}
File: Test.cpp
#include <string>
#include <vector>
#include <iostream>
#include <boost/process.hpp>
#include <boost/process/mitigate.hpp>
#include "test.hpp"
using namespace std;
using namespace testingBoostProcess;
namespace bpr = ::boost::process;
#ifdef _WIN32
const vector<wstring> EXE_NAME_ARGS = { L"btsync.exe", L"/config", L"conf.json" };
#else
const vector<string> EXE_NAME_ARGS = { "btsync", "--config", "conf.json" };
#endif
void Test::StartSyncing()
{
cout << "Starting Server...";
try
{
bpr::child exeServer = bpr::execute(bpr::initializers::set_args(EXE_NAME_ARGS),
bpr::initializers::throw_on_error(), bpr::initializers::inherit_env());
auto exitStatus = bpr::wait_for_exit(exeServer); // type will be either DWORD or int
int exitCode = BOOST_PROCESS_EXITSTATUS(exitStatus);
cout << " ok" << "\tstatus: " << exitCode << "\n";
}
catch (const exception& excStartExeServer)
{
cout << "\n" << "Error: " << excStartExeServer.what() << "\n";
}
}
(Problem) On Windows, the above code will start btsync and wait (block) until the process is terminated (either by using Task Manager or by the API's shutdown method), just like desired.
But on Linux, it finishes execution immediately after starting the process, as if wait_for_exit() isn't there at all, though the btsync process isn't terminated.
In an attempt to see if that has something to do with the btsync executable itself, I replaced it by this simple program:
File: Fake-Btsync.cpp
#include <cstdio>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define SLEEP Sleep(20000)
#include <Windows.h>
#else
#include <unistd.h>
#define SLEEP sleep(20)
#endif
using namespace std;
int main(int argc, char* argv[])
{
for (int i = 0; i < argc; i++)
{
printf(argv[i]);
printf("\n");
}
SLEEP;
return 0;
}
When used with this program, instead of the original btsync downloaded from the official website, my application works as desired. It will block for 20 seconds and then exit.
Question: What is the reason for the described behavior? The only thing I can think of is that btsync restarts itself on Linux. But how to confirm that? Or what else could it be?
Update: All I needed to do was to know about what forking is and how it works, as pointed in sehe's answer (thanks!).
Question 2: If I use the System Monitor to send an End command to the child process 'Fake-Btsync' while my main application is blocked, wait_for_exit() will throw an exception saying:
waitpid(2) failed: No child processes
Which is a different behavior than on Windows, where it simply says "ok" and terminates with status 0.
Update 2: sehe's answer is great, but didn't quite address Question 2 in a way I could actually understand. I'll write a new question about that and post the link here.
The problem is your assumption about btsync. Let's start it:
./btsync
By using this application, you agree to our Privacy Policy, Terms of Use and End User License Agreement.
http://www.bittorrent.com/legal/privacy
http://www.bittorrent.com/legal/terms-of-use
http://www.bittorrent.com/legal/eula
BitTorrent Sync forked to background. pid = 24325. default port = 8888
So, that's the whole story right there: BitTorrent Sync forked to background. Nothing more. Nothing less. If you want to, btsync --help tells you to pass --nodaemon.
Testing Process Termination
Let's pass --nodaemon run btsync using the test program. In a separate subshell, let's kill the child btsync process after 5 seconds:
sehe#desktop:/tmp$ (./test; echo exit code $?) & (sleep 5; killall btsync)& time wait
[1] 24553
[2] 24554
By using this application, you agree to our Privacy Policy, Terms of Use and End User License Agreement.
http://www.bittorrent.com/legal/privacy
http://www.bittorrent.com/legal/terms-of-use
http://www.bittorrent.com/legal/eula
[20141029 10:51:16.344] total physical memory 536870912 max disk cache 2097152
[20141029 10:51:16.344] Using IP address 192.168.2.136
[20141029 10:51:16.346] Loading config file version 1.4.93
[20141029 10:51:17.389] UPnP: Device error "http://192.168.2.1:49000/l2tpv3.xml": (-2)
[20141029 10:51:17.407] UPnP: ERROR mapping TCP port 43564 -> 192.168.2.136:43564. Deleting mapping and trying again: (403) Unknown result code (UPnP protocol violation?)
[20141029 10:51:17.415] UPnP: ERROR removing TCP port 43564: (403) Unknown result code (UPnP protocol violation?)
[20141029 10:51:17.423] UPnP: ERROR mapping TCP port 43564 -> 192.168.2.136:43564: (403) Unknown result code (UPnP protocol violation?)
[20141029 10:51:21.428] Received shutdown request via signal 15
[20141029 10:51:21.428] Shutdown. Saving config sync.dat
Starting Server... ok status: 0
exit code 0
[1]- Done ( ./test; echo exit code $? )
[2]+ Done ( sleep 5; killall btsync )
real 0m6.093s
user 0m0.003s
sys 0m0.026s
No problem!
A Better Fake Btsync
This should still be portable and be (much) better behaved when killed/terminated/interrupted:
#include <boost/asio/signal_set.hpp>
#include <boost/asio.hpp>
#include <iostream>
int main(int argc, char* argv[])
{
boost::asio::io_service is;
boost::asio::signal_set ss(is);
boost::asio::deadline_timer timer(is, boost::posix_time::seconds(20));
ss.add(SIGINT);
ss.add(SIGTERM);
auto stop = [&]{
ss.cancel(); // one of these will be redundant
timer.cancel();
};
ss.async_wait([=](boost::system::error_code ec, int sig){
std::cout << "Signal received: " << sig << " (ec: '" << ec.message() << "')\n";
stop();
});
timer.async_wait([&](boost::system::error_code ec){
std::cout << "Timer: '" << ec.message() << "'\n";
stop();
});
std::copy(argv, argv+argc, std::ostream_iterator<std::string>(std::cout, "\n"));
is.run();
return 0;
}
You can test whether it is well-behaved
(./btsync --nodaemon; echo exit code $?) & (sleep 5; killall btsync)& time wait
The same test can be run with "official" btsync and "fake" btsync. Output on my linux box:
sehe#desktop:/tmp$ (./btsync --nodaemon; echo exit code $?) & (sleep 5; killall btsync)& time wait
[1] 24654
[2] 24655
./btsync
--nodaemon
Signal received: 15 (ec: 'Success')
Timer: 'Operation canceled'
exit code 0
[1]- Done ( ./btsync --nodaemon; echo exit code $? )
[2]+ Done ( sleep 5; killall btsync )
real 0m5.014s
user 0m0.001s
sys 0m0.014s

getting all boost test suites / test cases

As the title says, I want to get all test suites or test cases (name) from a test application, ether in the console or as xml output.
Test framework is the boost test library.
Is there an option to achieve this? I did not found anything useful in the documentation.
There is simply the --list_content command line option, exactly for that purpose.
This can be done without much intrusion using a global fixture. Assuming you have a translation unit (cpp file) that contains main explicitly or auto generated, you can intercept test execution when a certain command line argument is provided. Then you can traverse the test tree using a customized visitor, which lists all available tests. Here is a small working example, which creates a test runner by compiling and linking files main_test.cpp, a.cpp and b.cpp:
main_test.cpp
#include <string>
#include <iostream>
// --- Boost Includes ---
#define BOOST_TEST_MODULE MyTestSuite
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
using namespace boost::unit_test;
struct Visitor : test_tree_visitor
{
size_t level = 0;
void visit( test_case const& test )
{
std::string indentation( level, '.' );
std::cout << indentation << test.p_name << std::endl;
}
bool test_suite_start( test_suite const& suite )
{
std::string indentation( level, '.' );
level++;
std::cout << indentation << "Suite: " << suite.p_name << std::endl;
return true;
}
void test_suite_finish( test_suite const& suite )
{
level--;
}
};
struct GlobalFixture
{
GlobalFixture( )
{
int argc = framework::master_test_suite( ).argc;
for ( int i = 0; i < argc; i++ )
{
std::string argument( framework::master_test_suite( ).argv[i] );
if ( argument == "list" )
{
Visitor visitor;
traverse_test_tree( framework::master_test_suite( ), visitor );
exit( EXIT_SUCCESS );
}
}
}
};
BOOST_GLOBAL_FIXTURE( GlobalFixture )
a.cpp
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_SUITE ( TestA )
BOOST_AUTO_TEST_CASE ( TestFoo )
{
BOOST_CHECK(true);
}
BOOST_AUTO_TEST_CASE ( TestBar )
{
BOOST_CHECK(true);
}
BOOST_AUTO_TEST_SUITE_END() // TestA
b.cpp
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_SUITE ( TestB )
BOOST_AUTO_TEST_CASE ( TestFoo )
{
BOOST_CHECK(true);
}
BOOST_AUTO_TEST_CASE ( TestBar )
{
BOOST_CHECK(true);
}
BOOST_AUTO_TEST_SUITE_END() // TestA
Invoking the runner without any arguments results in
./somelib_testrunner1
Running 4 test cases...
*** No errors detected
Passing the argument list used in the fixture defined above results in
Suite: MyTestSuite
.Suite: TestA
..TestFoo
..TestBar
.Suite: TestB
..TestFoo
..TestBar
I am afraid there is no easy way to do this without actually running the tests.
And even then the only thing coming to my mind without touching the code would be --log_level=test_suite and some sort of parsing script that finds the "Entering test suite", "Leaving test suite" and "Entering test case" messages (or parsing the xml given when you also put --log_format=XML, if you have a xml parser at hand).
But even that spoils the log with your added BOOST_TEST_MESSAGEs and of course encountered errors and warnings.
Seeing how the boost test framework is not much more than a bunch of macros, defined in the header, you could of course add the functionality yourself, probably easiest by adding another log format just listing the suites and tests, assuming you are fine with running the tests while finding the list.

C++ Builder console application that calls a webservice (hello world)

I am trying write a "Hello World" example using C++Builder. This is my first project so I have probably made a simple mistake.
I want to create a console application that calls a calculator web service.
I open C++Builder 2007 and I create a Console Application. A cpp file called File1.cpp appears. Here it is the content:
//---------------------------------------------------------------------------
#include <iostream.h>
#include <vcl.h>
#pragma hdrstop
#include "calculator.h"
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double a, b;
cout << "Enter the values to sum\n";
cout << "A: ";
cin >> a;
cout << "B: ";
cin >> b;
cout << "\nA+B:";
cout << GetCalculatorSoap()->Add(1,2);
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
Additionally I added the soap proxy going into New->Other->WebService->WSDL Importer.
Using the WSDL http://www.dneonline.com/calculator.asmx?WSDL
This action added calculator.cpp:
// ************************************************************************ //
// The types declared in this file were generated from data read from the
// WSDL File described below:
// WSDL : http://www.dneonline.com/calculator.asmx?WSDL
// >Import : http://www.dneonline.com/calculator.asmx?WSDL:0
// Encoding : utf-8
// Version : 1.0
// (21/02/2012 19:48:31 - - $Rev: 10138 $)
// ************************************************************************ //
#include <vcl.h>
#pragma hdrstop
#if !defined(calculatorH)
#include "calculator.h"
#endif
namespace NS_calculator {
_di_CalculatorSoap GetCalculatorSoap(bool useWSDL,
AnsiString addr, THTTPRIO* HTTPRIO)
{
static const char* defWSDL= "http://www.dneonline.com/calculator.asmx?WSDL";
static const char* defURL = "http://www.dneonline.com/calculator.asmx";
static const char* defSvc = "Calculator";
static const char* defPrt = "CalculatorSoap";
if (addr=="")
addr = useWSDL ? defWSDL : defURL;
THTTPRIO* rio = HTTPRIO ? HTTPRIO : new THTTPRIO(0);
if (useWSDL) {
rio->WSDLLocation = addr;
rio->Service = defSvc;
rio->Port = defPrt;
} else {
rio->URL = addr;
}
_di_CalculatorSoap service;
rio->QueryInterface(service);
if (!service && !HTTPRIO)
delete rio;
return service;
}
// ************************************************************************ //
// This routine registers the interfaces and types exposed by the WebService.
// ************************************************************************ //
static void RegTypes()
{
/* CalculatorSoap */
InvRegistry()->RegisterInterface(__interfaceTypeinfo(CalculatorSoap),
L"http://tempuri.org/", L"utf-8");
InvRegistry()->RegisterDefaultSOAPAction(__interfaceTypeinfo(CalculatorSoap),
L"http://tempuri.org/%operationName%");
InvRegistry()->RegisterInvokeOptions(__interfaceTypeinfo(CalculatorSoap),
ioDocument);
}
#pragma startup RegTypes 32
}; // NS_calculator
When I run the application it raises an exception when calling GetCalculatorSoap()->Add(1,2):
---------------------------
Debugger Exception Notification
---------------------------
Project Test.exe raised exception class EOleSysError
with message 'CoInitialize has not been called'.
---------------------------
Break Continue Help
---------------------------
Debugging it seems the GetCalculatorSoap() executes ok, but just before calling the Add method the exception is thrown...
Any ideas what is wrong? Thanks!
The error message tells you what the problem is - CoInitialize has not been called. (Actually, it's preferable to call CoInitializeEx instead, but either will work.)
Your SOAP code is using COM methods, and therefore COM has to be initialized first. This is done on a per-thread basis.
You can fix it by calling CoInitialize(NULL);' at the beginning of your main function. Don't forget to call CoUnitialize(); at the end of main as well.
In Delphi, CoInitialize/CoUninitialize are declared in the ActiveX unit. In C++Builder, it seems to be in OBJBASE.H (a quick search found it there, and that's also what's indicated in the MSDN documentation.
(If you're used to writing VCL form based apps, you won't have seen this before; the VCL initializes COM for you automatically. You're seeing it now because you're writing a console app.)