I'm using boost test framework 1.47 and I'm having difficulties testing my exceptions
Here is my exception class
class VideoCaptureException : public std::exception
{
std::string m_Description;
public:
VideoCaptureException(const char* description)
{
m_Description = std::string(description);
}
VideoCaptureException(const std::string& description)
{
m_Description = description;
}
virtual ~VideoCaptureException() throw() {}
virtual const char* what() const throw()
{
return m_Description.c_str();
}
}
I'm trying to test code that simply throws this exception
BOOST_CHECK_THROW( source.StopCapture(), VideoCaptureException )
For some reason it doesn't work.
unknown location(0): fatal error in "testVideoCaptureSource": unknown type
testVideoCaptureSource.cpp(28): last checkpoint
What is it that I'm doing wrong?
After encountering this error myself, I have tracked it down to a silly, but easy-to-make mistake:
throw new VideoCaptureException( "uh-oh" );
will fail with that error message, while:
throw VideoCaptureException( "uh-oh" );
will succeed.
The new variant causes a pointer to an exception to be caught, rather than the exception itself. The boost library doesn't know what to do with this, so it just says "unknown type".
It would be nice if the library explained the situation properly, but hopefully anybody else hitting "fatal error: unknown type" will find this page and see how to fix it!
Related
I'm trying to create a program that, on execution, zips a given directory. Most of my errors have been resolved and I am hopefully getting to the end of this, but I still have the issue of an exception being thrown and a question regarding the program. I code in C++20 and on Visual Studio 2019.
I've come across this exact error when debugging the program:
Exception thrown at 0x76820B42 in aixLogger.exe: Microsoft C++ exception: bit7z::BitException at memory location 0x001AF440.
I already checked with a breakpoint what code is giving me this error:
catch (const BitException& ex) {
ex.what(); //<-
}
The code runs otherwise and isn't giving me any error messages, the breakpoint activates on the line I marked with an arrow (not actually part of my code).
To eliminate further possible edits I will add the rest of my code as well:
main.cpp
#include <QCoreApplication>
#include <string>
#include <iostream>
#include <filesystem>
#include <bit7z.hpp>
#include "main.h"
#include <bitcompressor.hpp>
namespace fs = std::filesystem;
using namespace bit7z;
using namespace std;
int main(int argc, char* argv[])
{
QCoreApplication a(argc, argv);
try {
Bit7zLibrary lib{ L"7z.dll" };
BitCompressor compressor{ lib, BitFormat::Zip };
//vector< wstring > files = { L"aretz/Downloads/test" };
wstring dir = { L"D: / local / aretz / Programmierung / git - workplace / aixLogger / test /" } ;
wstring zip = { L"zippedtest.zip" };
compressor.compressDirectory(dir, zip);
}
catch (const BitException& ex) {
ex.what();
}
return a.exec();
}
void AIXLogger::CompressDir() {
/*try {
Bit7zLibrary lib{ L"7z.dll" };
BitCompressor compressor{ lib, BitFormat::Zip };
vector< wstring > files = { L"C:/Users/aretz/Downloads/test" };
wstring zip = { L"zippedtest.zip" };
compressor.compressFiles(files, zip);
}
catch (const BitException& ex) {
ex;
}*/
}
main.h
#pragma once
#include <qwidget.h>
#include <qobject.h>
#include <bit7z.hpp>
class AIXLogger : public QWidget
{
Q_OBJECT
public slots:
public:
void CompressDir();
};
I've currently commented out the function CompressDir() as I can't call it in my main since it gives me either a syntax error or tells me the identifier is undefined.
Syntax Error:
AIXLogger.CompressDir(); the dot is marked as the error
identifier is undefined:
CompressDir();
I don't know what exactly is causing the catch to thrown an exception. From other posts I suspected that my paths for the files and directories are at fault, but changing them or moving my test directory didn't help at all. Removing the try and catch lines from my codeblock only adds the same error message where Exception Thrown is being replaced by Unhandled Exception. Thanks to anyone who can help.
I already checked with a breakpoint what code is giving me this error:
catch (const BitException& ex) {
ex.what(); //<-
}
The code runs otherwise and isn't giving me any error messages
The code isn't giving you any error message since you're not doing anything with the information provided by the thrown exception.
You're simply calling ex.what() without, for example, printing the error message string it returns, e.g., via std::cout.
the breakpoint activates on the line I marked with an arrow (not actually
part of my code).
I don't know what exactly is causing the catch to thrown an exception. From other posts I suspected that my paths for the files and directories are at fault, but changing them or moving my test directory didn't help at all.
The ex.what() error message should give you more details about the actual issue you're having.
By the way, I'm the author of the bit7z library, and from my experience and looking at the code you posted, I can think of some possible causes (the most common ones):
The program could not find the 7z.dll library.
Please ensure that the DLL is in the same directory as the executable or in one of the default DLL search paths of Windows.
The program could not find the directory path to be compressed.
As before, make sure that the path exists.
I use pcl 1.7 tracking code and In some cases this method:
tracker_->compute ();
Gives me these errors:
[pcl::ApproxNearestPairPointCloudCoherence::initCompute] PointCloudCoherence::Init failed.
[pcl::ApproxNearestPairPointCloudCoherence::compute] Init failed.
I now know that error is thrown and I would like to catch exactly this error to tell the program what to do if this error occurs. I tried like this:
try
{
tracker_->compute ();
}
catch (...)
{
std::cout<<"inside the exception"<<std::endl;
}
To catch all the errors but it did not work..... And also with
catch(pcl::ApproxNearestPairPointCloudCoherenceException &e)
my program did not even compile....
So any ideas what I do wrong?
I browsed the source in order to look for the location where the error is raised, and found out that in your specific case it is raised by
if (!PointCloudCoherence<PointInT>::initCompute ())
{
PCL_ERROR ("[pcl::%s::initCompute] PointCloudCoherence::Init failed.\n", getClassName().c_str());
return (false);
}
so you see, there is no throw xxx here but only a macro which hides the actual error handling from us.
To find out what exactly was happening, I then searched for a definition of PCL_ERROR and the search yielded that it is defined in the file print.h as
#define PCL_ERROR(...) pcl::console::print (pcl::console::L_ERROR, __VA_ARGS__)
with pcl::console::print being a function simply printing the error, not throwing an exception.
So, you cannot catch the error because it is not an exception, but rather only plain text written to the console.
I have a test on a code part that needs to throw an exception, but using BOOST_CHECK_THROW still crashes the test. Here is the test:
#include <boost/test/unit_test.hpp>
#include "tools/CQueueMessage.hpp"
class TestMessage
{
public:
std::string m_message1;
std::string m_message2;
std::string m_messageEmpty;
std::string m_messageEmptyJson;
TestMessage()
: m_message1("{\"photo\":{\"name\":\"pic\",\"extension\":\"jpg\"}}"),
m_message2("{\"photo\":{\"name\":\"pic\",\"extension\":\"png\"}}"),
m_messageEmpty(""), m_messageEmptyJson("{}") {}
~TestMessage() {}
};
BOOST_FIXTURE_TEST_CASE(message2send, TestMessage)
{
QueueMessage qmsg1(m_message1);
BOOST_CHECK_EQUAL(qmsg1.messageToBeSent(), "{\"photo\":{\"name\":\"pic\",\"extension\":\"jpg\"}}");
QueueMessage qmsg2(m_message2);
BOOST_CHECK_EQUAL(qmsg2.messageToBeSent(), "{\"photo\":{\"name\":\"pic\",\"extension\":\"png\"}}");
BOOST_CHECK_THROW(QueueMessage qmsg3(m_messageEmpty), QueueMessageException)
// QueueMessage qmsg4(m_messageEmptyJson);
}
The QueueMessage class constructor is throwing a QueueMessageException if the message is empty or if it is an empty json. My problem is that this test is printing:
Running 1 test case...
unknown location(0): fatal error in "message2send": std::exception: Bad message format
*** 1 failure detected in test suite "main"
*** Exited with return code: 201 ***
How can I verify that the exception is thrown?
This is the constructor:
QueueMessage(CString& messageIn)
{
std::stringstream ss;
ss << messageIn;
PTree pt;
json::read_json(ss, pt);
std::string photo = pt.get< std::string >("photo");
if (photo.empty())
{
throw QueueMessageException("Bad message format"); // in debugging it arrives here
}
}
My psychic debugging powers tell me that your constructor is NOT in fact throwing QueueMessageException. It looks like it (through the function message2send) is throwing std::exception or a different child of it.
I get this exception:
Unhandled exception at 0x75374B32 (KernelBase.dll) in
LogLoaderUnmanaged.exe: 0xE0434352 (parameters: 0x80070002,
0x00000000, 0x00000000, 0x00000000, 0x74040000).
When I call my CLR project using this code (part of an Application .exe type project):
int _tmain(int argc, _TCHAR* argv[])
{
_tprintf_s(_T("Press enter to start logging messages."));
_getch();
std::string app("Application");
std::string domain("Domain");
std::string message("Message");
UnmanagedLoggerClient::LogError(Debug, app.c_str(), domain.c_str(), message.c_str());
_tprintf_s(_T("Done."));
}
The error is at the call to LogError, which is defined in my CLR DLL's header as follows:
#ifdef UNMANAGEDLOGGERCLIENT_EXPORTS
#define WIN32PROJECT_API __declspec(dllexport)
#else
#define WIN32PROJECT_API __declspec(dllimport)
#endif
enum UnmanagedLogLevel
{
Debug = 0,
Error = 1
};
static class WIN32PROJECT_API UnmanagedLoggerClient
{
public:
static void LogError (UnmanagedLogLevel level, const char* app, const char* domain, const char* message);
};
In the implementation the method is pretty straightforward:
void UnmanagedLoggerClient::LogError(UnmanagedLogLevel level, const char* app, const char* domain, const char* message)
{
LoggerClient::LogLevel logLevel = static_cast<LoggerClient::LogLevel>(level);
LoggerClient::Logger::LogError(logLevel, gcnew String(app), gcnew String(domain), gcnew String(message), DateTime::Now);
}
Any ideas why this happens? I'm not really much of a C++ guy and I haven't found any useful information searching for this problem online. Many thanks for any input!
You are using a very brittle way to get the CLR initialized, diagnostics are therefore poor. There's a "File not found" error code visible in your exception diagnostic, error code 0x80070002.
You managed to start the CLR, the exception code is a managed exception, but it could not find a file. Make sure all executables are present in the same directory as your EXE. Use SysInternals' ProcMon if that doesn't help, you'll see it searching for a file and not finding it.
Situation
I want to create a Python language binding for a C++ API using SWIG. Some of the API functions may throw exceptions. The C++ application has a hierarchy of self-defined exceptions, like this example:
std::exception
-> API::Exception
-> API::NetworkException
-> API::TimeoutException
-> API::UnreachableException
-> API::InvalidAddressException
The desired behavior is as follows:
All exception types should have a matching Python class as wrapper. These wrapper classes should be valid Python exceptions.
When an API call throws a C++ exception, it should be caught. The corresponding Python exception (i.e. the wrapper class of the caught C++ exception) should be thrown.
This should be a dynamic process: the Python exception type is decided at runtime, only based on the runtime type of the caught C++ exception. This way, there is no need to describe the complete exception hierarchy in the SWIG interface file.
Problems and questions
Wrapper classes are no Python exceptions.
While SWIG creates wrapper classes for all self-defined exceptions (like for any other class), these classes are not Python exceptions. The wrapper of the base exception (API::Exception in the example) extends Object instead of BaseException, the Python class of which all exceptions in Python should be derived.
Furthermore, it doesn't seem possible to let SWIG add a parent class manually. Note this is possible when using SWIG with Java through the usage of %typemap(javabase) (see SWIG documentation for details).
How can the Python C API throw a user-defined exception?
The most common way to throw a Python exception from the Python C API is by calling PyErr_SetString [reference]. This is also shown in the demo application below.
But this is only trivial with the standard (built-in) exceptions of Python, because references to them are stored in global variables [reference] in the Python C API.
I know there is a method PyErr_NewException [reference] to get references to self-defined exceptions, but I didn't got this working.
How can the Python C API evaluate the C++ type at runtime and then find the corresponding Python wrapper class by name?
I assume a Python class can be searched by name at runtime, through the reflection part of the Python C API. Is this the way to go? And how is it done in practice?
Demo application
To experiment with this problem, I created a tiny C++ API with a single function that calculates the factorial of a number. It has a minimal self-defined exception hierarchy, consisting of only one class TooBigException.
Note this exception acts as the base exception in the general problem and the application should work with any subclass of it. This means the solution may only use the dynamic (i.e. runtime) type of the caught exception to rethrow it in Python (see below).
The full source code of the demo application is as follows:
// File: numbers.h
namespace numbers {
int fact(int n);
}
// File: numbers.cpp
#include "TooBigException.h"
namespace numbers {
int fact(int n) {
if (n > 10) throw TooBigException("Value too big", n);
else if (n <= 1) return 1;
else return n*fact(n-1);
}
}
// File: TooBigException.h
namespace numbers {
class TooBigException: public std::exception {
public:
explicit TooBigException(const std::string & inMessage,
const int inValue);
virtual ~TooBigException() throw() {}
virtual const char* what() const throw();
const std::string & message() const;
const int value() const;
private:
std::string mMessage;
int mValue;
};
}
// File: TooBigException.cpp
#include "TooBigException.h"
namespace numbers {
TooBigException::TooBigException(const std::string & inMessage, const int inValue):
std::exception(),
mMessage(inMessage),
mValue(inValue)
{
}
const char* TooBigException::what() const throw(){
return mMessage.c_str();
}
const std::string & TooBigException::message() const {
return mMessage;
}
const int TooBigException::value() const {
return mValue;
}
}
To get the Python binding I use the following SWIG interface file:
// File: numbers.i
%module numbers
%include "stl.i"
%include "exception.i"
%{
#define SWIG_FILE_WITH_INIT
#include "TooBigException.h"
#include "numbers.h"
%}
%exception {
try {
$action
}
catch (const numbers::TooBigException & e) {
// This catches any self-defined exception in the exception hierarchy,
// because they all derive from this base class.
<TODO>
}
catch (const std::exception & e)
{
SWIG_exception(SWIG_RuntimeError, (std::string("C++ std::exception: ") + e.what()).c_str());
}
catch (...)
{
SWIG_exception(SWIG_UnknownError, "C++ anonymous exception");
}
}
%include "TooBigException.h"
%include "numbers.h"
So every call to the API is wrapped by a try-catch block. First exceptions of our base type are caught and handled. Then all other exceptions are caught and rethrown using the SWIG exception library.
Note any subclass of numbers::TooBigException is caught and the wrappers of their dynamic (i.e. runtime) type should be thrown, not the wrapper of their static (i.e. compile time) type, which is always TooBigException!
The project can be built easily by executing the following commands on a Linux machine:
$ swig -c++ -python numbers.i
$ g++ -fPIC -shared TooBigException.cpp numbers.cpp numbers_wrap.cxx \
-I/usr/include/python2.7 -o _numbers.so
Current implementation
My current implementation still (successfully) throws a fixed standard Python exception. The code <TODO> above is then replaced by:
PyErr_SetString(PyExc_Exception, (std::string("C++ self-defined exception ") + e.what()).c_str());
return NULL;
Which gives the following (expected) behavior in Python:
>>> import numbers
>>> fact(11)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception: C++ self-defined exception Value too big
It looks like someone has answered your basic question over on the swig-user list...
%exception {
try {
$action
} catch (MyException &_e) {
SWIG_Python_Raise(SWIG_NewPointerObj(
(new MyException(static_cast<const MyException& >(_e))),
SWIGTYPE_p_MyException,SWIG_POINTER_OWN),
"MyException", SWIGTYPE_p_MyException);
SWIG_fail;
}
}
This does assume you have generated wrappers for your exception classes, I believe.
Example for your hierarchy
std::exception
-> API::Exception
-> API::NetworkException
-> API::TimeoutException
-> API::UnreachableException
-> API::InvalidAddressException
example.i:
%module example
%include "stl.i"
%include "exception.i"
%{
#define SWIG_FILE_WITH_INIT
#include "example.cpp"
%}
%{
#define CATCH_PE(Namespace,Exception) \
catch(const Namespace::Exception &e) \
{ \
SWIG_Python_Raise(SWIG_NewPointerObj(new Namespace::Exception(e), \
SWIGTYPE_p_##Namespace##__##Exception,SWIG_POINTER_OWN), \
#Exception, SWIGTYPE_p_##Namespace##__##Exception); \
SWIG_fail; \
} \
/**/
// should be in "derived first" order
#define FOR_EACH_EXCEPTION(ACTION) \
ACTION(API,UnreachableException) \
ACTION(API,TimeoutException) \
ACTION(API,InvalidAddressException) \
ACTION(API,NetworkException) \
ACTION(API,Exception) \
/**/
// In order to remove macros, need traits:
// http://swig.10945.n7.nabble.com/traits-based-access-to-swig-type-info-td12315.html
%}
%exception {
try {
$action
}
FOR_EACH_EXCEPTION(CATCH_PE)
catch (const std::exception & e)
{
SWIG_exception(SWIG_RuntimeError, (std::string("C++ std::exception: ") + e.what()).c_str());
}
catch (...)
{
SWIG_exception(SWIG_UnknownError, "C++ anonymous exception");
}
}
%include "example.cpp"
example.cpp:
#include <exception>
#include <stdexcept>
namespace API
{
struct Exception: std::exception
{
virtual const char* what() const throw()
{
return "It is API::Exception";
}
};
struct NetworkException: Exception
{
virtual const char* what() const throw()
{
return "It is API::NetworkException";
}
};
struct TimeoutException: NetworkException
{
virtual const char* what() const throw()
{
return "It is API::TimeoutException";
}
};
struct UnreachableException: NetworkException
{
virtual const char* what() const throw()
{
return "It is API::UnreachableException";
}
};
struct InvalidAddressException: Exception
{
virtual const char* what() const throw()
{
return "It is API::InvalidAddressException";
}
};
inline void select(int i)
{
switch(i)
{
case 0: throw Exception();
case 1: throw NetworkException();
case 2: throw TimeoutException();
case 3: throw UnreachableException();
case 4: throw InvalidAddressException();
default: throw std::runtime_error("It is std::runtime_error");
}
}
}
Build:
swig -c++ -python example.i &&
g++ -fPIC -shared -lpython2.7 example.cpp example_wrap.cxx -I/usr/include/python2.7 -o _example.so
test.py:
#!/usr/bin/env python2.7
from exceptions import BaseException
from example import *
def catch(i):
try:
select(i)
except UnreachableException as e:
print "Caught UnreachableException"
print e.what()
print e
except TimeoutException as e:
print "Caught TimeoutException"
print e.what()
print e
except InvalidAddressException as e:
print "Caught InvalidAddressException"
print e.what()
print e
except NetworkException as e:
print "Caught NetworkException"
print e.what()
print e
except Exception as e:
print "Caught Exception"
print e.what()
print e
except BaseException as e:
print "Caught BaseException"
print str(e)
print "_"*16
for i in xrange(6):
catch(i)
Output is:
Caught Exception
It is API::Exception
<example.Exception; proxy of <Swig Object of type 'API::Exception *' at 0x7f9f54a02120> >
________________
Caught NetworkException
It is API::NetworkException
<example.NetworkException; proxy of <Swig Object of type 'API::NetworkException *' at 0x7f9f54a02120> >
________________
Caught TimeoutException
It is API::TimeoutException
<example.TimeoutException; proxy of <Swig Object of type 'API::TimeoutException *' at 0x7f9f54a02120> >
________________
Caught UnreachableException
It is API::UnreachableException
<example.UnreachableException; proxy of <Swig Object of type 'API::UnreachableException *' at 0x7f9f54a02120> >
________________
Caught InvalidAddressException
It is API::InvalidAddressException
<example.InvalidAddressException; proxy of <Swig Object of type 'API::InvalidAddressException *' at 0x7f9f54a02120> >
________________
Caught BaseException
C++ std::exception: It is std::runtime_error
________________
Based on answer in maillist.