DUnit on older C++Builder versions? - testing

We are currently migrating our sources who were developed under C++Builder 5 to the newer Embarcadero's XE5. Thinking ahead, we would like to write our unit tests under C++Builder5 which, ideally, would be fully functional after the migration with few maintenance to none.
My question is simple, though. Is it possible to use the same DUnit framework Embarcadero has on C++Builder 5? If so, can you please provide us with any hints?
Thank you.

DUnit can indeed be used on CppBuilder5.
To do so:
Get the source code for DUnit from here : http://sourceforge.net/projects/dunit/files/latest/download
Build DUNITRTL.lib using the following command lines, or you can make a .bat file and execute it from /dunit/src folder :
SET NDC6=C:\PROGRA~2\Borland\CBUILD~1
%NDC6%\bin\dcc32.exe Dunit.dpr /O..\objs /DBCB /M /H /W /JPHN -$d-l-n+p+r-s-t-w-y- %2 %3 %4
%NDC6%\bin\tlib.exe DUNITRTL.lib /P32 -+dunit.obj -+DunitAbout.obj -+DUnitMainForm.obj -+GUITestRunner.obj -+TestExtensions.obj -+TestFramework.obj -+TestModules.obj -+TextTestRunner.obj
Once done, making a test project becomes easy:
Create a VCL Form application.
Remove Unit1.cpp along its form from the project.
Add DUNITRTL.lib file we built into the project (Project > Add to Project).
Add /dunit/src paths to both library and include paths. (Project > Options > Folder/Conditions).
Go to Project1.cpp file and make sure it looks like this:
#include <vcl.h>
#pragma hdrstop
#include <GUITestRunner.hpp>
USERES("Project1.res");
USELIB("DUNITRTL.lib");
//---------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
Application->Initialize();
Guitestrunner::RunRegisteredTests();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
return 0;
}
Add a new unit to the project which will be used as a TestSuite.
MyTestCase.h
//---------------------------------------------------------------------------
#ifndef __TMYTESTCASE_H__
#define __TMYTESTCASE_H__
//---------------------------------------------------------------------------
#include <TestFramework.hpp>
class TMyTestCase : public TTestCase
{
public:
__fastcall virtual TMyTestCase(AnsiString name) : TTestCase(name) {}
virtual void __fastcall SetUp();
virtual void __fastcall TearDown();
__published:
void __fastcall MySuccessfulTest();
void __fastcall MyFailedTest();
};
#endif
MyTestCase.cpp
#include <vcl.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#include "TMyTestCase.h"
//---------------------------------------------------------------------------
void __fastcall TMyTestCase::SetUp()
{}
void __fastcall TMyTestCase::TearDown()
{}
void __fastcall TMyTestCase::MySuccessfulTest()
{
int a = 1;
a = a + 1;
CheckEquals(2,a,"test adding");
}
void __fastcall TMyTestCase::MyFailedTest()
{
int a = 1;
a = a + 2;
CheckEquals(2,a,"test adding");
}
static void registerTests()
{
_di_ITestSuite iSuite;
TTestSuite* testSuite = new TTestSuite("Testing TMyTestCase.h");
if (testSuite->GetInterface(__uuidof(ITestSuite), &iSuite))
{
testSuite->AddTests(__classid(TMyTestCase));
Testframework::RegisterTest(iSuite);
}
else
{
delete testSuite;
}
}
#pragma startup registerTests 33
#pragma package(smart_init)
The project can be compiled and ran. The tests should be executed without a hitch.

Related

cpp/cli interop dll breaks in visual studio 2015

I've been assigned the task of upgrading an old interop dll into visualstudio2015 with the v140 toolset.
I'm getting an odd access violation now.
Exception thrown at 0x000007fef7d3d95c (mscoreei.dll) in HostApp.exe:
0xC0000005: Access violation reading location 0xffffffffffffffff
Did anything change in cpp/cli from v110 to v140?
I can tell the error occurs when the methods are defined in a separate cpp instead of inline in the Foo.h. This work-around isn't possible since this is where I need to call managed objects.
Here is my attempt at reconstructing the outline of the code:
shared header IFoo.h
#ifdef DLL_EXPORTS
#define __API__ __declspec(dllexport)
#else
#define __API__ __declspec(dllimport)
#endif
class IFoo
{
public:
__API__ static IFoo* Create();
virtual void DoSomething()=0;
};
Foo.h
#include IFoo.h
class Foo : public IFoo
{
public:
Foo() { } // if inline no crash
void DoSomething();
};
Foo.cpp
#include ManagedStuff.h
#include Foo.h
// Foo::Foo() { } // AV if not inline.
void Foo::DoSomething()
{
gcroot<ManagedClass^> stuff = gcnew ManagedClass();
.....
}
FooImpl.cpp
#include Foo.h
IFoo* IFoo::Create()
{
IFoo* f = new Foo(); // CRASH if ctor is NOT inline.
f->DoSomething(); //CRASH
return f;
}

Qt5 QNetworkAccessManager finished signal never emits

I have a very confusing problem.
I had a simple project that was downloading files from some ftp servers. It worked very good.
Then, I tried implementing that same code into a larger project (first one was a Console App, and the second one is GUI, but I don't think that changes anything..).
After doing some debugging it seems to me that finished() signal from QNetworkAccessManager somehow never gets emitted (or received).
Again, the exact same lines of code work as a separate project.
downloader.h
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QFile>
#include <QDebug>
class Downloader : public QObject
{
Q_OBJECT
public:
explicit Downloader(QObject *parent = 0);
signals:
void dloadend();
void printed();
public slots:
void replyFinished (QNetworkReply *reply);
void doDownload(QUrl url);
void printDLend();
private:
QNetworkAccessManager *manager;
};
#endif // DOWNLOADER_H
downloader.cpp
#include "downloader.h"
Downloader::Downloader(QObject *parent) :
QObject(parent)
{
}
void Downloader::doDownload(QUrl url)
{
qDebug()<<"entry: doDownload\n";
QNetworkRequest req(url);
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),this,SLOT(printDLend()));//SLOT(replyFinished(QNetworkReply*)));
manager -> get(req);
qDebug()<<"exit: doDownload\n";
}
void Downloader::replyFinished (QNetworkReply *reply)
{
qDebug()<<"entry: reply\n";
if(reply->error()) {
qDebug() << "ERROR!";
qDebug() << reply->errorString();
}
else
{
qDebug() << "Download finished!";
QFile *file = new QFile("C:/users/jelicicm/Desktop/test1.hex");
if(file->open(QFile::Append))
{
file->write(reply->readAll());
file->flush(); file->close();
qDebug() <<"Downloaded file size:" <<file->size() <<"Bytes";
qDebug() <<"File name: "<< file->fileName();
;
}
delete file;
}
reply->deleteLater();
manager->deleteLater();
emit dloadend();
}
mainwindow.cpp (important part)
void MainWindow::on_actionDownloadFirmwareImage_triggered()
{
Downloader d;
QUrl url("ftp://ftp.xenbase.org/pub/Genomics/JGI/Xenla6.0/Xenla_6.0_JGI_Gene_Models.fasta.tgz");
qDebug() << "url, debug";
ui->plainTextEdit->appendPlainText(url.toDisplayString());
d.doDownload(url);
QObject::connect(&d,SIGNAL(dloadend()),this, SLOT(printDLend()));
}
Can't get my head around this.
Any help is welcome,
Thanks!
EDIT> More info:
Debugger posts this>
url, debug
entry: doDownload
exit: doDownload
You create object Downloader on stack and it is deleted right after your function exits. You must create object using new, and provide MainWindow object as parent, so after you close MainWindow, the object will be destroyed.
If the download finish, you still need to destroy the object, so simply connect the dloadend() signal to deleteLater() slot, Qt loop will delete your object right after all signal are processed.
void MainWindow::on_actionDownloadFirmwareImage_triggered()
{
Downloader *d = new Downloader(this);
QUrl url("ftp://example.com/some.file.tgz");
qDebug() << "url, debug";
ui->plainTextEdit->appendPlainText(url.toDisplayString());
d->doDownload(url);
QObject::connect(d,SIGNAL(dloadend()),this, SLOT(printDLend()));
QObject::connect(d,SIGNAL(dloadend()), d, SLOT(deleteLater()));
}

Immediate Access Violation when debugging Windows.Devices.Sensors project in Windows 7

I have a large solution with 50+ unmanaged projects in it. I have recently added a project with managed code in it to the solution. The managed code accesses Windows.Devices.Sensors in a .NET dll. This dll is eventually wrapped by unmanaged code and called from another unmanaged project.
My problem is that I get the following access violation before main() even executes.
Unhandled exception at 0x744b8ea0 in myApplication.exe: 0xC0000005: Access violation.
Managed code:
#using <Windows.winmd>
using namespace Windows::Devices::Sensors;
#include <math.h>
namespace TabletSensors
{
namespace NET
{
public ref class DotNetDllClass
{
public:
DotNetDllClass()
{
Initialization();
}
~DotNetDllClass()
{
}
float* GetQuaternion()
{
OrientationSensorReading^ reading = _orientation->GetCurrentReading();
if( reading != nullptr )
{
float* quat = new float[4];
quat[0] = reading->Quaternion->X;
quat[1] = reading->Quaternion->Y;
quat[2] = reading->Quaternion->Z;
quat[3] = reading->Quaternion->W;
return quat;
}
else
{
return NULL;
}
}
private:
void Initialization()
{
_orientation = OrientationSensor::GetDefault();
if( _orientation != nullptr )
{
_orientation->ReportInterval = 16;
}
else
{
// not good ... throw exception or something
}
}
OrientationSensor^ _orientation;
};
}
}
Wrapper header file:
namespace TabletSensors
{
namespace NETWrapper
{
class DLLEXPORT_SENSORS WrapperClass
{
public:
__stdcall WrapperClass();
__stdcall ~WrapperClass();
float* __stdcall GetQuaternion();
};
}
}
Wrapper cpp file:
#define MIXSENSORS_BUILD
#include <gcroot.h>
#include "DotNetWrapper.h"
#include "DotNetDll.h"
using namespace TabletSensors::NETWrapper;
using namespace TabletSensors::NET;
static gcroot<TabletSensors::NET::DotNetDllClass^> Sensors = nullptr;
static System::UInt16 refCount = 0;
#pragma managed
inline TabletSensors::NET::DotNetDllClass^ GetSensors(void)
{
return (TabletSensors::NET::DotNetDllClass^)Sensors;
}
void Init()
{
++refCount;
if(GetSensors() == nullptr)
{
Sensors = gcnew TabletSensors::NET::DotNetDllClass();
}
}
void CleanUp()
{
if( refCount > 0 )
{
--refCount;
}
}
float* GetQuaternion_()
{
return Sensors->GetQuaternion();
}
#pragma unmanaged
TabletSensors::NETWrapper::WrapperClass::WrapperClass()
{
Init();
}
TabletSensors::NETWrapper::WrapperClass::~WrapperClass()
{
CleanUp();
}
float* TabletSensors::NETWrapper::WrapperClass::GetQuaternion()
{
float* x = new float[4];
return GetQuaternion_();
}
#pragma managed
Unmanaged project referencing my wrapper class:
#include "DotNetWrapper.h"
.
.
.
void UnmanagedProject::Update()
{
// if this line is present, I get an access violation without hitting any breakpoints.
TabletSensors::NETWrapper::WrapperClass _tabletSensors;
.
.
.
}
Since the managed code is trying to access Tablet Sensors I understand why it doesn't work on my Windows 7 desktop. What I don't understand it why it won't even allow me to debug my code at all. No breakpoints are hit before the Access Violation occurs.
What I would really like to figure out is how to use exception handling or #ifdefs to keep this crash from happening. But I have had very little luck.
Any ideas?
The fix is to Delay Load the managed DLL. The allows the application to run until that DLL is explicitly called. Thanks to Ben Voight for his answer here: https://stackoverflow.com/a/28467701/1454861

Importing an Embarcadero C++ Builder XE3 DLL into Embarcadero C++ Builder XE3

I try to create a DLL in Embarcadero C++ Builder XE3, and use it in a test-project in the same environment.
I take example on a tutorial which code does not give a good result for me (!) : http://docwiki.embarcadero.com/RADStudio/XE3/en/Tutorial:_Using_Dynamic_Linked_Libraries_in_C%2B%2BBuilder_Applications
Here is the content of my DLL :
BaseAuth.h file :
#ifndef BaseAuthH
#define BaseAuthH
#include <System.hpp>
class TBaseAuth
{
public:
virtual void TestMessage() = 0;
};
#endif // BaseAuthH
Auth.h file :
//---------------------------------------------------------------------------
#ifndef AuthH
#define AuthH
//---------------------------------------------------------------------------
#include "BaseAuth.h"
class TAuth : public TBaseAuth
{
public:
TAuth();
~TAuth();
void TestMessage();
};
#endif
Auth.cpp file :
//---------------------------------------------------------------------------
#pragma hdrstop
#include "Auth.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
TAuth::TAuth()
{
}
TAuth::~TAuth()
{
}
void TAuth::TestMessage()
{
MessageBox(0, "Test message", "Test", MB_OK);
}
and File1.cpp :
#pragma hdrstop
#pragma argsused
#include "Auth.h"
extern "C" __declspec(dllexport) void* __stdcall GetClassInstance()
{
return static_cast<void*>(new TAuth());
}
extern "C" int _libmain(unsigned long reason)
{
return 1;
}
Now in the test application I have :
the same BaseAuth.h file
a form with a Button :
Test_DLLAuthOrga.h :
#ifndef Test_DLLAuthOrgaH
#define Test_DLLAuthOrgaH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
#include "BaseAuth.h"
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // Composants gérés par l'EDI
TButton *Button2;
void __fastcall Button2Click(TObject *Sender);
private: // Déclarations utilisateur
TBaseAuth *mpAuth;
public: // Déclarations utilisateur
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Test_DLLAuthOrga.cpp :
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Test_DLLAuthOrga.h"
#include "BaseAuth.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
const wchar_t* library = L"DLLAuthOrga.dll";
extern "C" __declspec(dllimport) void* __stdcall GetClassInstance();
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
HINSTANCE load;
try
{ load = LoadLibrary(library); }
catch(Exception &e)
{ ShowMessage(e.Message); }
if (load)
{
ShowMessage("Library Loaded!");
void *myFunc;
myFunc = (void *)GetProcAddress(load, "GetClassInstance");
mpAuth = (AuthParent*)myFunc;
}
else { ShowMessage("Library not loaded!"); }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if (mpAuth == NULL) return;
try { pRes = mpAuth->TestMessage(); }
catch(Exception &e) { ShowMessage(e.Message); return; }
}
The result is :
the pointer mpAuth has an adress.
But its methods have no adress, and when I call a simple method such as "void TestMessage()", it raises an access violation.
=> It first seemed to be a question of string compatibility (but between "C++ Builder XE3" and "C++ Builder XE3" I would expect the same string format to be used ?!) : Error calling DLL with Unicode Delphi
=> I found a similar issue but with C++ DLL into Delphi, not C++ DLL into C++ ... : Call C++ DLL in Delphi app
=> I tried using "HMODULE" instead of "HINSTANCE load;" : same result.
=> I tried without success using
mpAuth = static_cast<AuthParent*>(myFunc);
instead of :
mpAuth = (AuthParent*)myFunc;
=> I also tried replacing "__stdcall" by "__cdecl" or "" (removing) : the libray loads but GetProcAdress returns NULL.
=> What am I doing wrong in attempting to call the DLL's method "TestMessage()" ?
To correctly bind function from dll you should give it full definition, including calling convention, arguments, return type and __dllexport/__dllimport modifier. The easiest way to do it - using typedef so instead of typing (in Test_DLLAuthOrga.cpp)
void *myFunc;
myFunc = (void *)GetProcAddress(load, "GetClassInstance");
use
typedef __declspec(dllimport) void (__stdcall *MyFuncPointerType)(void);
MyFuncPointerType myFunc;
myFunc = (MyFuncPointerType)GetProcAddress(load, "GetClassInstance");
If you are using __cdecl convention you should also add underscore to the target function name
typedef __declspec(dllimport) void (__cdecl *MyFuncPointerType)(void);
MyFuncPointerType myFunc;
myFunc = (MyFuncPointerType)GetProcAddress(load, "_GetClassInstance");
you can also explicitly define AuthParent* as a return type for your factory function to get rid of uneccessary casts to void* and back to AuthParent* (in File1.cpp and Test_DLLAuthOrga.cpp) so, the final code snippet would look like this:
typedef __declspec(dllimport) AuthParent* (__cdecl *MyFuncPointerType)(void);
MyFuncPointerType myFunc;
myFunc = (MyFuncPointerType)GetProcAddress(load, "_GetClassInstance");
mpAuth = myFunc();

how to access variable from one class in another in QT mobility?

I have two classes: first generate position data (latitude and longitude), how I can access this data (variables latitude and longitute) in second class? becouse in second class I get crazy number(
Here are headers and classes:
first header:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QGeoPositionInfoSource>
#include <QGeoPositionInfo>
#include <QtCore/QPointer>
#include <QGeoSatelliteInfo>
#include <QGeoSatelliteInfoSource>
#include "gpsform.h"
QTM_USE_NAMESPACE
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
double latitude;
double longitude;
double altitude;
double speed;
public slots:
void positionUpdated(QGeoPositionInfo geoPositionInfo);
private:
Ui::MainWindow *ui;
QPointer<QGeoPositionInfoSource> locationDataSource;
private slots:
void on_pushButton_2_clicked();
void on_pushButton_4_clicked();
void startGPS();
void on_pushButton_clicked();
signals:
void updated();
};
#endif // MAINWINDOW_H
first class
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "quitdiallog.h"
#include <QGeoCoordinate>
#include <QDebug>
#include <QtGui/QMessageBox>
#include <QList>
#include "gpsform.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
setWindowTitle("Мой кОмпаС");
ui->setupUi(this);
startGPS();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::startGPS()
{
// Obtain the location data source if it is not obtained already
if (!locationDataSource)
{
locationDataSource =
QGeoPositionInfoSource::createDefaultSource(this);
if (locationDataSource)
{
// Whenever the location data source signals that the current
// position is updated, the positionUpdated function is called.
QObject::connect(locationDataSource,
SIGNAL(positionUpdated(QGeoPositionInfo)),
this,
SLOT(positionUpdated(QGeoPositionInfo)));
// Start listening for position updates
locationDataSource->setUpdateInterval(100);
locationDataSource->setPreferredPositioningMethods(QGeoPositionInfoSource::SatellitePositioningMethods);
locationDataSource->startUpdates();
} else {
// Not able to obtain the location data source
// TODO: Error handling
}
} else {
// Start listening for position updates
locationDataSource->setUpdateInterval(5000);
locationDataSource->startUpdates();
}
}
void MainWindow::positionUpdated(QGeoPositionInfo geoPositionInfo)
{
//gpsform *gpf=new gpsform;
if (geoPositionInfo.isValid())
{
//locationDataSource->stopUpdates();
QGeoCoordinate geoCoordinate = geoPositionInfo.coordinate();
latitude = geoCoordinate.latitude();
longitude = geoCoordinate.longitude();
altitude=geoCoordinate.altitude();
ui->label->setNum(latitude);
ui->label_2->setNum(longitude);
/*if(QGeoPositionInfo::GroundSpeed)
{
speed=QGeoPositionInfo::GroundSpeed;
ui->label_4->setNum(speed);
}*/
emit updated();
//gpf->latitude=this->latitude;
//gpsform *gpf=new gpsform;
//gpf->show();
//gpf->latitude=latitude;
}
}
void MainWindow::on_pushButton_clicked()
{
/*ui->label_3->setNum(latitude);
qDebug()<<latitude<<" "<<longitude<<" "<<altitude;*/
gpsform *gps=new gpsform;
this->hide();
gps->show();
}
void MainWindow::on_pushButton_4_clicked()
{
QuitDiallog *qi=new QuitDiallog;
this->hide();
qi->show();
}
void MainWindow::on_pushButton_2_clicked()
{
ui->label_3->setNum(latitude);
}
second header
#ifndef GPSFORM_H
#define GPSFORM_H
#include <QWidget>
#include "mainwindow.h"
QTM_USE_NAMESPACE
namespace Ui {
class gpsform;
}
class gpsform : public QWidget
{
Q_OBJECT
public:
explicit gpsform(QWidget *parent = 0);
~gpsform();
double latitude;
private:
Ui::gpsform *ui;
private slots:
void on_pushButton_clicked();
void updatedata();
};
#endif // GPSFORM_H
second class:
#include "gpsform.h"
#include "ui_gpsform.h"
#include "mainwindow.h"
#include <QTimer>
#include <QDebug>
gpsform::gpsform(QWidget *parent) :
QWidget(parent),
ui(new Ui::gpsform)
{
ui->setupUi(this);
/*ui->label->setNum(mw->latitude);*/
/* QTimer * timer = new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(update()));
timer->start(50);*/
/* MainWindow *mw = new MainWindow;
QObject::connect(mw,SIGNAL(updated()),this,SLOT(updatedata()));*/
}
gpsform::~gpsform()
{
delete ui;
}
void gpsform::updatedata()
{
/* MainWindow *mw = new MainWindow;
this->latitude=mw->latitude;
ui->label->setNum(mw->latitude);*/
}
void gpsform::on_pushButton_clicked()
{
MainWindow *mw = new MainWindow;
//latitude=mw->latitude;
qDebug()<<mw->latitude;
ui->label->setNum(latitude);
}
For example I want to see latitude in second class, by pressing button. In future I'll do this by Signal/slot to generate label text every time, the position is updated. But now I'll get crazy number. Help me please
MainWindow *mw = new MainWindow;
//latitude=mw->latitude;
qDebug()<<mw->latitude;
You create a new instance of MainWindow and directly access its latitude member. But was it initialized? I see the only place writing into this member in MainWindow is positionUpdated. Are you sure this method gets invoked before you access mw->latitude? You could easily verify that with another qDebug printout from positionUpdated, or by using the debugger.
To comment on the code style in general - it's not good practice to directly access members of other classes like this. One of the problems (as you've just encountered!) with this approach is that the class has no way to actually control the validity of its member. Even the most basic solution - having an accessor method instead of raw member access could do wonders for you here, because the accessor method could potentially check if the value has been computed (or even compute it lazily).