How to pretty-print QString with GoogleTest framework? - qt

I am using the GoogleTest (GTest) framework in conjunction with a Qt5 application.
Whenever a test fails using a QString argument, the framework tries to print all the involved values. However, it cannot automatically handle foreign types (Qt5's QString in this case).
QString test = "Test";
ASSERT_EQ(test, "Value");
How can I get GoogleTest to pretty print QStrings automatically (= without having to manually convert them each time)?

The GoogleTest Guide explains how you can in general teach the framework to handle custom types.
In the end, the following code snippet is all that needs to be added for GoogleTest being able to work with QStrings:
QT_BEGIN_NAMESPACE
inline void PrintTo(const QString &qString, ::std::ostream *os)
{
*os << qUtf8Printable(qString);
}
QT_END_NAMESPACE
This code MUST NOT be in the namespace of your test fixtures, but must be in the Qt namespace (or in general in the namespace where the type that should be pretty-printed is defined in).
This code MUST also be viewable from all translation units where you call a GoogleTest assertion on that particular type, otherwise it will not get used (see comments).
As a result GoogleTest now pretty prints QStrings:
You can of course also add some quotation marks to make it clearer that it comes from a QString:
*os << "\"" << qUtf8Printable(qString) << "\"";
Source: Webinar ICS Qt Test-Driven Development Using Google Test and Google Mock by Justin Noel, Senior Consulting Engineer

Related

How to get the same application instance handle from QT and WinApi

My QT application uses WinApi library.
Now I have the following code:
//main.cpp
qDebug() << "main::instance = " << qApp; //0x29fe18
//lib.cpp
qDebug() << "library::instance = " << GetModuleHandle(NULL); // 0x400000
As you see, I'm getting different handles while my app has only one thread flow.
What's wrong?
Edit:
Yes, I guessed that those are kind of different things.
Question is: how do I get thread handle from both places (if code running from the same thread - I should get the same handle value, if there's 2 threads - I should get 2 different thread handles)?
We don't know what qApp is. Presumably it's a pointer to the global instance of QApplication. That's a C++ object instance in your process.
On the other hand GetModuleHandle(NULL) is the base address of your executable module.
These two things are completely different. You should not expect them to be the same.
According to your edit you aren't interested in either of these things and actually want to identify threads. For Win32 code you use GetCurrentThreadId. For Qt use QThread::currentThreadId().

QPluginLoader.instance() - how does it really work?

I am currently working on a Qt project where dynamic plugin loading is central. I am loading DLLs by using Qt's QPluginLoader. The different plugins are accessed through CameraPluginStructs, defined as follows:
struct CameraPluginStruct
{
QString name;
QString filePath;
CameraPluginInterface* plugin;
QPluginLoader* pluginLoader;
CameraPluginStruct(QString filePath=nullptr, QString name=nullptr):
filePath(filepath), name(name), plugin(nullptr), pluginLoader(nullptr){}
};
To load a plugin, the following function is called:
void loadPlugin(CameraPluginStruct& p)
{
p.pluginLoader = new QPluginLoader(p.filePath);
p.pluginLoader->load();
QObject* possiblePlugin = p.pluginLoader->instance(); //QPluginLoader.instance();
if(possiblePlugin)
{
// cast from QObject to correct type:
p.plugin = qobjectcast<CameraPluginInterface>(possiblePlugin);
}
}
And to unload a plugin, I use this function:
void unloadPlugin(CameraPluginStruct& p)
{
p.pluginLoader->unload(); // QPluginLoader.unload();
p.pluginLoader->~QPluginLoader();
p.pluginLoader = nullptr;
p.plugin = nullptr;
}
I have made a few, simple test plugins that write messages to the console when the constructor is called. For simplicity, let's say that I have two test plugins, DLL A and DLL B. When I load A by using the loadPlugin() function, the constructor in the plugin is called, and the corresponding message is written in the console. I can do the same thing with B, and everything seems to work – B's constructor message is written to the console, and the other functions seem to work as well.
Now, the problem occurs when I try to create another CameraPluginStruct connected to either A or B. No message is written to the console, which leads me to think that the constructor is not called. Even though, I am able to call the other test functions in the plugin with success (DoSomething(), see below). If I unload all CameraPlugins connected to A or B, and then load the DLL again, the constructor is called again on the first load.
The QPluginLoader.instance() call is described as follows in the documentation:
"Returns the root component object of the plugin. (...) The component object is a QObject. Use qobject_cast() to access interfaces you are
interested in." http://doc.qt.io/qt-5/qpluginloader.html#instance
Wouldn't it then be natural that the constructor in the DLL would be called each time, and not only the first time?
As I've understood, a DLL is only loaded once for any program. Therefore I have also tried to use only one QPluginLoader per DLL file, with the same result. Qt also says that:
"Multiple instances of QPluginLoader can be used to access the same physical plugin." http://doc.qt.io/qt-5/qpluginloader.html#details
Therefore I can't see how this can be a source to the problem anyway.
I would really appreciate if anyone could clarify how the QPluginLoader.instance() really works. Why is the constructor – at least how it seems – only called the first time I use the instance() call?
Thank you!
Here is the code found in the DLLs (the output texts differ in A and B):
TestDLL::TestDLL()
{
std::cout << "This is written from the constructor in A \n";
}
QString TestDLL::Name() const
{
return "Hello, writing from Name() \n";
}
void TestDLL::DoSomething() const
{
qDebug() << "Hello, this text comes from DoSomething()"\n;
}
When your plugin is loaded (i.e. the first time QPluginLoader::instance() is called), then a single instance of it is created - this is your root instance. The root instance is the only instance QPluginLoader will ever create for you.
If you want more, then you create a createInstance() or clone() method for your plugin class, so that new instances can be created from the root instance. Or more conventionally, make your plugin class a factory for the class type you wish to expose.

cannot convert cont char* to LPCWSTR

I am stuck with an error in QT compiler however it works fine with VS2010. the error states that
I have seen other posts related to the same error but non has resolved my problem in QT. I have tried _T,L or TEXT but still not working
bq. error: C2664: 'HANDLE
LoadImageW(HINSTANCE,LPCWSTR,UINT,int,int,UINT)' : cannot convert
argument 2 from 'const char *' to 'LPCWSTR' Types pointed to are
unrelated; conversion requires reinterpret_cast, C-style cast or
function-style cast
my code is as below
Bitmap::Bitmap(std::string const& file_name) {
bitmap_ = static_cast<HBITMAP>(::LoadImage(0, file_name.c_str(), IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION));
}
please share if you have any idea to resolve this
Qt does not include a compiler. On Windows you're probably either compiling with mingw or Visual C++. Either way, the issue is that you're calling a function that expects a wide character string but you're trying to hand it an 8-bit character string.
For compatibility reasons, Win32 uses a different set of API functions if you have _UNICODE defined. In your case, you do have _UNICODE defined. You can continue using the 8-bit std::string but simply change the method from LoadImage() to LoadImageA(). Or if you don't mind changing your Bitmap class, you could switch from std::string to std::wstring to take advantage of Windows' Unicode features.
But perhaps the larger question is why use Win32 to load bitmaps and std::string if you're using Qt? Qt's QImage class and QString class provide a full-featured, cross-platform strings and image loaders. Like any comprehensive framework, Qt works best if you only use external features on an as-needed basis.
I'm not sure if this method is the best, but I've used them on my projects and it works fine, see:
char *source = "Hello world";
WCHAR target[size];
MultiByteToWideChar(CP_ACP, 0, source, -1, target, size);
LPCWSTR final = target;
MessageBox(0, final, TEXT("title"), 0); //Sample usage

qt QTranslator reuse

I noticed that the Qt documentation is not very verbose on some of the aspects of the translations. I was fooling around with it trying to figure out their behaviour using trial & error. The ultimate goal is to get the translation changed on runtime but I am very confused as to what extent the QTranslator object can be re-used.
Consider this (where 'a' is the main instance of the application):
QTranslator translator;
translator.load("mytranslation_cz");
a.installTranslation(&translator);
(...)
a.removeTranslation(&translator)
Now the translator was removed from the application but what happened to the translator object?
In my tests when above code was followed by this again
translator.load("mytranslation_fr");
a.installTranslation(&translator);
it did not do anything in main() and it crashed the application when called from one of the widgets (using pointer to main app).
Therefore I am suspecting that I would need to create one QTranslator object per translation I want to load in the application and that I cannot reuse the QTranslator object. Am I right in this assumption?
And as a side question. Assuming the QTranslator object is untouched by the removeTranslation(), is it possible to simply install it later again like this?
QTranslator translator;
QTranslator translator1;
translator.load("mytranslation_cz");
translator1.load("mytranslation_fr");
a.installTranslation(&translator);
(...)
a.removeTranslation(&translator);
a.installTranslation(&translator1);
(...)
a.removeTranslation(&translator1);
a.installTranslation(&trasnlator); //Will this work?
Thanks for any clarification as I am somewhat confused as to what happens to the QTranslation objects when installing and removing translations from the application and especially if the QTranslation object can be reused for multiple translations somehow on runtime?
QTranslator::load basically in simple sense can be considered as a function that opens a given .qm file, reads in all the translated values and loads it in for a specific language.
Now in general operation you would not want to reuse this for many languages as by "reusing" (even if its allowed) your adding the overhead of parsing this given .qm file for every language every time you switch your UI language, which is just basically an overhead you don't need.
Your assumption of creating a QTranslator for each language is correct. As for your side question, Yes you can also re-use it. Thats the benefit of having individual QTranslator objects per translation. Just call qApp->removeTranslator() with the current translation and then qApp->installTranslator() with the new one. This way you are reusing the loaded translations as and when you please.
The way we structure this is by sub-classing QApplication and adding 2 functions
void Application::CreateTranslators() {
// translators_ is a QMap<QString, QTranslator*>
if (!translators_.isEmpty())
return;
QStringList languages;
languages << "en" << "ar" << "zh";
foreach(QString language, languages) {
QTranslator* translator = new QTranslator(instance());
translator->load(language);
translators_.insert(language, translator);
}
}
Now this function is called at the very start of the application.
2nd function is as following
void Application::SwitchLanguage(QString language) {
// current_translator_ is a QTranslator*
if (current_translator_)
removeTranslator(current_translator_);
current_translator_ = translators_.value(language, nullptr);
if (current_translator_)
installTranslator(current_translator_);
}
That's it. Using the second function you can switch your language at run-time as you please.
Couple things you'll also need to be aware of is changing QTranslator at run-time will update all translations from your .ui file strings marked as translatable automatically, however those set from code will not be. To get that you will have to override QWidget::changeEvent() and then check if the event is of type QEvent::LanguageChange and then set the required strings for that QWidget accordingly (Don't forget the tr() while doing so)

QTextCodec subclass - how to register my codec

I need to create my own codec, i.e. subclass of QTextCodec. And I'd like to use it via QTextCodec::codecForName("myname");
However, just subclass is not enough. QTextCodec::availableCodecs() does not contain my codec name.
QTextCodec documentation does not cover the area of proper registration of a custom codec:
Creating Your Own Codec Class
Support for new text encodings can be
added to Qt by creating QTextCodec
subclasses.
The pure virtual functions describe
the encoder to the system and the
coder is used as required in the
different text file formats supported
by QTextStream, and under X11, for the
locale-specific character input and
output.
To add support for another encoding to
Qt, make a subclass of QTextCodec and
implement the functions listed in the
table below.
name()
aliases()
mibEnum()
convertToUnicode()
convertFromUnicode()
You may find it more convenient to
make your codec class available as a
plugin; see How to Create Qt Plugins
for details.
So, I've tried to dig a little into plugins' direction. But I don't want to have a separate project with plugin. Is it possible to declare plugin within the same project?
Or is there a direct way to register my codec into QTextCodec? This is preferable.
according to qtextcodex.cpp any new codec is added to the collection of registered codecs (*static QList all) by its own constructor. So creating an instance of your codec class should do the trick; code below worked fine for me:
QMyCodec myCodec;
foreach (QByteArray codecName, QTextCodec::availableCodecs())
{
QString codecNameStr(codecName);
qDebug() << codecNameStr;
}
QTextCodec* codec = QTextCodec::codecForName("MyNewCodec");
if (codec)
{
qDebug() << "found ";
qDebug() << codec->name() << '\n';
}
QTextCodec::availableCodecs returned:
"MyNewCodec"
"System"
"roman8"
"hp-roman8"
"csHPRoman8" ...
QTextCodec::codecForName returned a pointer to my codec class
hope this helps, regards

Resources