summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2017-10-11 15:28:40 +0200
committerThiago Macieira <thiago.macieira@intel.com>2017-11-11 08:11:00 +0000
commitaf456842e13ab83cfeb44f3638b62652b201281c (patch)
treeb745ec099e586804e0cbb28aa73333310f778e20 /tests
parent4502999ff054f16aab1fdd99fbd9256b22ecadf9 (diff)
Change QRandomGenerator to have a deterministic mode
Now only QRandomGenerator::system() will access the system-wide RNG, which we document to be cryptographically-safe and possibly backed by a true HWRNG. Everything else just wraps a Mersenne Twister. Change-Id: I0a103569c81b4711a649fffd14ec8cd3469425df Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp334
1 files changed, 253 insertions, 81 deletions
diff --git a/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp b/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp
index e583766f21..f9b3ce5390 100644
--- a/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp
+++ b/tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp
@@ -43,8 +43,8 @@
#define COMMA ,
#define QVERIFY_3TIMES(statement) \
do {\
- if (!QTest::qVerify(static_cast<bool>(statement), #statement, "1st try", __FILE__, __LINE__))\
- if (!QTest::qVerify(static_cast<bool>(statement), #statement, "2nd try", __FILE__, __LINE__))\
+ if (!static_cast<bool>(statement))\
+ if (!static_cast<bool>(statement))\
if (!QTest::qVerify(static_cast<bool>(statement), #statement, "3rd try", __FILE__, __LINE__))\
return;\
} while (0)
@@ -71,6 +71,13 @@ public slots:
void cleanup() { setRNGControl(0); }
private slots:
+ void basics();
+ void knownSequence();
+ void copying();
+ void copyingGlobal();
+ void copyingSystem();
+ void systemRng();
+
void generate32_data();
void generate32();
void generate64_data() { generate32_data(); }
@@ -110,18 +117,154 @@ private slots:
void stdRandomDistributions();
};
+// The first 20 results of the sequence:
+static const quint32 defaultRngResults[] = {
+ 853323747U, 2396352728U, 3025954838U, 2985633182U, 2815751046U,
+ 340588426U, 3587208406U, 298087538U, 2912478009U, 3642122814U,
+ 3202916223U, 799257577U, 1872145992U, 639469699U, 3201121432U,
+ 2388658094U, 1735523408U, 2215232359U, 668106566U, 2554687763U
+};
+
+
using namespace std;
QT_WARNING_DISABLE_GCC("-Wfloat-equal")
QT_WARNING_DISABLE_CLANG("-Wfloat-equal")
+struct RandomGenerator : public QRandomGenerator
+{
+ RandomGenerator(uint control)
+ : QRandomGenerator(control ?
+ QRandomGenerator(control & RandomDataMask) :
+ *QRandomGenerator::global())
+ {
+ setRNGControl(control);
+ }
+};
+
+void tst_QRandomGenerator::basics()
+{
+ // default constructible
+ QRandomGenerator rng;
+
+ // copyable && movable
+ rng = rng;
+ rng = std::move(rng);
+
+ // 64-bit
+ QRandomGenerator64 rng64;
+ rng64 = rng64;
+ rng64 = std::move(rng64);
+
+ // 32- and 64-bit should be interchangeable:
+ rng = rng64;
+ rng64 = rng;
+ rng = std::move(rng64);
+ rng64 = std::move(rng);
+
+ // access global
+ QRandomGenerator *global = QRandomGenerator::global();
+ QRandomGenerator globalCopy = *global;
+ globalCopy = *global;
+ QRandomGenerator64 *global64 = QRandomGenerator64::global();
+ QRandomGenerator64 globalCopy64 = *global64;
+ globalCopy64 = *global64;
+
+ // access system
+ QRandomGenerator *system = QRandomGenerator::system();
+ QRandomGenerator systemRng = *system;
+ systemRng = *system;
+
+ QRandomGenerator64 *system64 = QRandomGenerator64::system();
+ QRandomGenerator64 systemRng64 = *system64;
+ systemRng64 = *system64;
+
+ Q_STATIC_ASSERT(std::is_same<decltype(rng64.generate()) COMMA quint64>::value);
+ Q_STATIC_ASSERT(std::is_same<decltype(system64->generate()) COMMA quint64>::value);
+}
+
+void tst_QRandomGenerator::knownSequence()
+{
+ QRandomGenerator rng;
+ for (quint32 x : defaultRngResults)
+ QCOMPARE(rng(), x);
+}
+
+void tst_QRandomGenerator::copying()
+{
+ QRandomGenerator rng1;
+ QRandomGenerator rng2 = rng1;
+
+ quint32 samples[20];
+ rng1.fillRange(samples);
+
+ // should produce the same sequence, whichever it was
+ for (quint32 x : samples)
+ QCOMPARE(rng2(), x);
+}
+
+void tst_QRandomGenerator::copyingGlobal()
+{
+ QRandomGenerator &global = *QRandomGenerator::global();
+ QRandomGenerator copy = global;
+
+ quint32 samples[20];
+ global.fillRange(samples);
+
+ // should produce the same sequence, whichever it was
+ for (quint32 x : samples)
+ QCOMPARE(copy(), x);
+}
+
+void tst_QRandomGenerator::copyingSystem()
+{
+ QRandomGenerator &system = *QRandomGenerator::system();
+ QRandomGenerator copy = system;
+ QRandomGenerator copy2 = copy;
+ copy2 = copy;
+
+ quint32 samples[20];
+ copy2.fillRange(samples);
+
+ // should NOT produce the same sequence, whichever it was
+ int sameCount = 0;
+ for (quint32 x : samples)
+ sameCount += (copy() == x);
+ QVERIFY(sameCount < 20);
+}
+
+void tst_QRandomGenerator::systemRng()
+{
+ QRandomGenerator *rng = QRandomGenerator::system();
+ rng->generate();
+ rng->generate64();
+ rng->generateDouble();
+ rng->bounded(100);
+ rng->bounded(100U);
+
+#ifdef QT_BUILD_INTERNAL
+ quint32 setpoint = std::numeric_limits<int>::max();
+ ++setpoint;
+ quint64 setpoint64 = quint64(setpoint) << 32 | setpoint;
+ setRNGControl(SetRandomData | setpoint);
+
+ QCOMPARE(rng->generate(), setpoint);
+ QCOMPARE(rng->generate64(), setpoint64);
+ QCOMPARE(rng->generateDouble(), ldexp(setpoint64, -64));
+ QCOMPARE(rng->bounded(100), 50);
+#endif
+}
+
void tst_QRandomGenerator::generate32_data()
{
QTest::addColumn<uint>("control");
- QTest::newRow("default") << 0U;
+ QTest::newRow("fixed") << (RandomValue32 & RandomDataMask);
+ QTest::newRow("global") << 0U;
#ifdef QT_BUILD_INTERNAL
- QTest::newRow("system") << uint(SkipHWRNG);
+ if (qt_has_hwrng())
+ QTest::newRow("hwrng") << uint(UseSystemRNG);
+ QTest::newRow("system") << uint(UseSystemRNG | SkipHWRNG);
# ifdef HAVE_FALLBACK_ENGINE
- QTest::newRow("fallback") << uint(SkipHWRNG | SkipSystemRNG);
+ QTest::newRow("system-fallback") << uint(UseSystemRNG | SkipHWRNG | SkipSystemRNG);
# endif
#endif
}
@@ -129,39 +272,40 @@ void tst_QRandomGenerator::generate32_data()
void tst_QRandomGenerator::generate32()
{
QFETCH(uint, control);
- setRNGControl(control);
+ RandomGenerator rng(control);
for (int i = 0; i < 4; ++i) {
- QVERIFY_3TIMES([] {
- quint32 value = QRandomGenerator::generate();
+ QVERIFY_3TIMES([&] {
+ quint32 value = rng.generate();
return value != 0 && value != RandomValue32;
}());
}
// and should hopefully be different from repeated calls
for (int i = 0; i < 4; ++i)
- QVERIFY_3TIMES(QRandomGenerator::generate() != QRandomGenerator::generate());
+ QVERIFY_3TIMES(rng.generate() != rng.generate());
}
void tst_QRandomGenerator::generate64()
{
QFETCH(uint, control);
- setRNGControl(control);
+ RandomGenerator rng(control);
+ QVERIFY_3TIMES(rng.generate64() > std::numeric_limits<quint32>::max());
for (int i = 0; i < 4; ++i) {
- QVERIFY_3TIMES([] {
- quint64 value = QRandomGenerator::generate();
+ QVERIFY_3TIMES([&] {
+ quint64 value = rng.generate64();
return value != 0 && value != RandomValue32 && value != RandomValue64;
}());
}
// and should hopefully be different from repeated calls
for (int i = 0; i < 4; ++i)
- QVERIFY_3TIMES(QRandomGenerator::generate64() != QRandomGenerator::generate64());
+ QVERIFY_3TIMES(rng.generate64() != rng.generate64());
for (int i = 0; i < 4; ++i)
- QVERIFY_3TIMES(QRandomGenerator::generate() != quint32(QRandomGenerator::generate64()));
+ QVERIFY_3TIMES(rng.generate() != quint32(rng.generate64()));
for (int i = 0; i < 4; ++i)
- QVERIFY_3TIMES(QRandomGenerator::generate() != (QRandomGenerator::generate64() >> 32));
+ QVERIFY_3TIMES(rng.generate() != (rng.generate64() >> 32));
}
void tst_QRandomGenerator::quality()
@@ -190,7 +334,9 @@ void tst_QRandomGenerator::quality()
Q_STATIC_ASSERT(FailureThreshold > AcceptableThreshold);
QFETCH(uint, control);
- setRNGControl(control);
+ if (control & RandomDataMask)
+ return;
+ RandomGenerator rng(control);
int histogram[UCHAR_MAX + 1];
memset(histogram, 0, sizeof(histogram));
@@ -199,7 +345,7 @@ void tst_QRandomGenerator::quality()
// test the quality of the generator
quint32 buffer[BufferCount];
memset(buffer, 0xcc, sizeof(buffer));
- generate_n(buffer, +BufferCount, [] { return QRandomGenerator::generate(); });
+ generate_n(buffer, +BufferCount, [&] { return rng.generate(); });
quint8 *ptr = reinterpret_cast<quint8 *>(buffer);
quint8 *end = ptr + sizeof(buffer);
@@ -224,20 +370,20 @@ void tst_QRandomGenerator::quality()
template <typename T> void fillRange_template()
{
QFETCH(uint, control);
- setRNGControl(control);
+ RandomGenerator rng(control);
for (int i = 0; i < 4; ++i) {
- QVERIFY_3TIMES([] {
+ QVERIFY_3TIMES([&] {
T value[1] = { RandomValue32 };
- QRandomGenerator::fillRange(value);
+ rng.fillRange(value);
return value[0] != 0 && value[0] != RandomValue32;
}());
}
for (int i = 0; i < 4; ++i) {
- QVERIFY_3TIMES([] {
+ QVERIFY_3TIMES([&] {
T array[2] = {};
- QRandomGenerator::fillRange(array);
+ rng.fillRange(array);
return array[0] != array[1];
}());
}
@@ -245,18 +391,18 @@ template <typename T> void fillRange_template()
if (sizeof(T) > sizeof(quint32)) {
// just to shut up a warning about shifting uint more than the width
enum { Shift = sizeof(T) / 2 * CHAR_BIT };
- QVERIFY_3TIMES([] {
+ QVERIFY_3TIMES([&] {
T value[1] = { };
- QRandomGenerator::fillRange(value);
+ rng.fillRange(value);
return quint32(value[0] >> Shift) != quint32(value[0]);
}());
}
// fill in a longer range
- auto longerArrayCheck = [] {
+ auto longerArrayCheck = [&] {
T array[32];
memset(array, 0, sizeof(array));
- QRandomGenerator::fillRange(array);
+ rng.fillRange(array);
if (sizeof(T) == sizeof(RandomValue64)
&& find(begin(array), end(array), RandomValue64) != end(array))
return false;
@@ -273,11 +419,11 @@ void tst_QRandomGenerator::fillRangeULLong() { fillRange_template<qulonglong>();
template <typename T> void generate_template()
{
QFETCH(uint, control);
- setRNGControl(control);
+ RandomGenerator rng(control);
// almost the same as fillRange, but limited to 32 bits
for (int i = 0; i < 4; ++i) {
- QVERIFY_3TIMES([] {
+ QVERIFY_3TIMES([&] {
T value[1] = { RandomValue32 };
QRandomGenerator().generate(begin(value), end(value));
return value[0] != 0 && value[0] != RandomValue32
@@ -286,10 +432,10 @@ template <typename T> void generate_template()
}
// fill in a longer range
- auto longerArrayCheck = [] {
+ auto longerArrayCheck = [&] {
T array[72] = {}; // at least 256 bytes
QRandomGenerator().generate(begin(array), end(array));
- return find_if(begin(array), end(array), [](T cur) {
+ return find_if(begin(array), end(array), [&](T cur) {
return cur == 0 || cur == RandomValue32 ||
cur == RandomValue64 || cur > numeric_limits<quint32>::max();
}) == end(array);
@@ -303,12 +449,12 @@ void tst_QRandomGenerator::generateULLong() { generate_template<qulonglong>(); }
void tst_QRandomGenerator::generateNonContiguous()
{
QFETCH(uint, control);
- setRNGControl(control);
+ RandomGenerator rng(control);
QLinkedList<quint64> list = { 0, 0, 0, 0, 0, 0, 0, 0 };
auto longerArrayCheck = [&] {
QRandomGenerator().generate(list.begin(), list.end());
- return find_if(list.begin(), list.end(), [](quint64 cur) {
+ return find_if(list.begin(), list.end(), [&](quint64 cur) {
return cur == 0 || cur == RandomValue32 ||
cur == RandomValue64 || cur > numeric_limits<quint32>::max();
}) == list.end();
@@ -326,7 +472,7 @@ void tst_QRandomGenerator::bounded_data()
QTest::addColumn<quint32>("sup");
QTest::addColumn<quint32>("expected");
- auto newRow = [](quint32 val, quint32 sup) {
+ auto newRow = [&](quint32 val, quint32 sup) {
// calculate the scaled value
quint64 scaled = val;
scaled <<= 32;
@@ -352,31 +498,31 @@ void tst_QRandomGenerator::bounded()
QFETCH(uint, control);
QFETCH(quint32, sup);
QFETCH(quint32, expected);
- setRNGControl(control);
+ RandomGenerator rng(control);
- quint32 value = QRandomGenerator::bounded(sup);
+ quint32 value = rng.bounded(sup);
QVERIFY(value < sup);
QCOMPARE(value, expected);
- int ivalue = QRandomGenerator::bounded(sup);
+ int ivalue = rng.bounded(sup);
QVERIFY(ivalue < int(sup));
QCOMPARE(ivalue, int(expected));
// confirm only the bound now
- setRNGControl(control & (SkipHWRNG|SkipSystemRNG));
- value = QRandomGenerator::bounded(sup);
+ setRNGControl(control & (SkipHWRNG|SkipSystemRNG|UseSystemRNG));
+ value = rng.bounded(sup);
QVERIFY(value < sup);
- value = QRandomGenerator::bounded(sup / 2, 3 * sup / 2);
+ value = rng.bounded(sup / 2, 3 * sup / 2);
QVERIFY(value >= sup / 2);
QVERIFY(value < 3 * sup / 2);
- ivalue = QRandomGenerator::bounded(-int(sup), int(sup));
+ ivalue = rng.bounded(-int(sup), int(sup));
QVERIFY(ivalue >= -int(sup));
QVERIFY(ivalue < int(sup));
// wholly negative range
- ivalue = QRandomGenerator::bounded(-int(sup), 0);
+ ivalue = rng.bounded(-int(sup), 0);
QVERIFY(ivalue >= -int(sup));
QVERIFY(ivalue < 0);
}
@@ -407,7 +553,9 @@ void tst_QRandomGenerator::boundedQuality()
Q_STATIC_ASSERT(FailureThreshold > AcceptableThreshold);
QFETCH(uint, control);
- setRNGControl(control);
+ if (control & RandomDataMask)
+ return;
+ RandomGenerator rng(control);
int histogram[Bound];
memset(histogram, 0, sizeof(histogram));
@@ -415,7 +563,7 @@ void tst_QRandomGenerator::boundedQuality()
{
// test the quality of the generator
QVector<quint32> buffer(BufferCount, 0xcdcdcdcd);
- generate(buffer.begin(), buffer.end(), [] { return QRandomGenerator::bounded(Bound); });
+ generate(buffer.begin(), buffer.end(), [&] { return rng.bounded(Bound); });
for (quint32 value : qAsConst(buffer)) {
QVERIFY(value < Bound);
@@ -441,24 +589,26 @@ void tst_QRandomGenerator::boundedQuality()
void tst_QRandomGenerator::generateReal()
{
QFETCH(uint, control);
- setRNGControl(control);
+ RandomGenerator rng(control);
for (int i = 0; i < 4; ++i) {
- QVERIFY_3TIMES([] {
- qreal value = QRandomGenerator::generateDouble();
+ QVERIFY_3TIMES([&] {
+ qreal value = rng.generateDouble();
return value >= 0 && value < 1 && value != RandomValueFP;
}());
}
// and should hopefully be different from repeated calls
for (int i = 0; i < 4; ++i)
- QVERIFY_3TIMES(QRandomGenerator::generateDouble() != QRandomGenerator::generateDouble());
+ QVERIFY_3TIMES(rng.generateDouble() != rng.generateDouble());
}
void tst_QRandomGenerator::qualityReal()
{
QFETCH(uint, control);
- setRNGControl(control);
+ if (control & RandomDataMask)
+ return;
+ RandomGenerator rng(control);
enum {
SampleSize = 160,
@@ -474,7 +624,7 @@ void tst_QRandomGenerator::qualityReal()
};
double data[SampleSize];
- std::generate(std::begin(data), std::end(data), &QRandomGenerator::generateDouble);
+ std::generate(std::begin(data), std::end(data), [&rng] { return rng.generateDouble(); });
int aboveHalf = 0;
int belowOneEighth = 0;
@@ -503,12 +653,22 @@ void tst_QRandomGenerator::qualityReal()
template <typename Engine> void seedStdRandomEngine()
{
- QRandomGenerator rd;
- Engine e(rd);
- QVERIFY_3TIMES(e() != 0);
+ {
+ QRandomGenerator &rd = *QRandomGenerator::system();
+ Engine e(rd);
+ QVERIFY_3TIMES(e() != 0);
+
+ e.seed(rd);
+ QVERIFY_3TIMES(e() != 0);
+ }
+ {
+ QRandomGenerator64 &rd = *QRandomGenerator64::system();
+ Engine e(rd);
+ QVERIFY_3TIMES(e() != 0);
- e.seed(rd);
- QVERIFY_3TIMES(e() != 0);
+ e.seed(rd);
+ QVERIFY_3TIMES(e() != 0);
+ }
}
void tst_QRandomGenerator::seedStdRandomEngines()
@@ -533,12 +693,16 @@ void tst_QRandomGenerator::stdUniformIntDistribution_data()
QTest::addColumn<uint>("control");
QTest::addColumn<quint32>("max");
- auto newRow = [](quint32 max) {
- QTest::addRow("default:%u", max) << 0U << max;
- QTest::addRow("system:%u", max) << uint(SkipHWRNG) << max;
- #ifdef HAVE_FALLBACK_ENGINE
- QTest::addRow("fallback:%u", max) << uint(SkipHWRNG | SkipSystemRNG) << max;
- #endif
+ auto newRow = [&](quint32 max) {
+#ifdef QT_BUILD_INTERNAL
+ if (qt_has_hwrng())
+ QTest::addRow("hwrng:%u", max) << uint(UseSystemRNG) << max;
+ QTest::addRow("system:%u", max) << uint(UseSystemRNG | SkipHWRNG) << max;
+# ifdef HAVE_FALLBACK_ENGINE
+ QTest::addRow("system-fallback:%u", max) << uint(UseSystemRNG | SkipHWRNG | SkipSystemRNG) << max;
+# endif
+#endif
+ QTest::addRow("global:%u", max) << 0U << max;
};
// useless: we can only generate zeroes:
@@ -553,7 +717,7 @@ void tst_QRandomGenerator::stdUniformIntDistribution()
{
QFETCH(uint, control);
QFETCH(quint32, max);
- setRNGControl(control & (SkipHWRNG|SkipSystemRNG));
+ RandomGenerator rng(control);
{
QRandomGenerator rd;
@@ -621,21 +785,19 @@ void tst_QRandomGenerator::stdGenerateCanonical()
QSKIP("MSVC 2013's std::generate_canonical is broken");
#else
QFETCH(uint, control);
- setRNGControl(control);
+ RandomGenerator rng(control);
for (int i = 0; i < 4; ++i) {
- QVERIFY_3TIMES([] {
- QRandomGenerator rd;
- qreal value = std::generate_canonical<qreal COMMA 32>(rd);
+ QVERIFY_3TIMES([&] {
+ qreal value = std::generate_canonical<qreal COMMA 32>(rng);
return value > 0 && value < 1 && value != RandomValueFP;
}());
}
// and should hopefully be different from repeated calls
- QRandomGenerator rd;
for (int i = 0; i < 4; ++i)
- QVERIFY_3TIMES(std::generate_canonical<qreal COMMA 32>(rd) !=
- std::generate_canonical<qreal COMMA 32>(rd));
+ QVERIFY_3TIMES(std::generate_canonical<qreal COMMA 32>(rng) !=
+ std::generate_canonical<qreal COMMA 32>(rng));
#endif
}
@@ -649,12 +811,16 @@ void tst_QRandomGenerator::stdUniformRealDistribution_data()
QTest::addColumn<double>("min");
QTest::addColumn<double>("sup");
- auto newRow = [](double min, double sup) {
- QTest::addRow("default:%g-%g", min, sup) << 0U << min << sup;
- QTest::addRow("system:%g-%g", min, sup) << uint(SkipHWRNG) << min << sup;
- #ifdef HAVE_FALLBACK_ENGINE
- QTest::addRow("fallback:%g-%g", min, sup) << uint(SkipHWRNG | SkipSystemRNG) << min << sup;
- #endif
+ auto newRow = [&](double min, double sup) {
+#ifdef QT_BUILD_INTERNAL
+ if (qt_has_hwrng())
+ QTest::addRow("hwrng:%g-%g", min, sup) << uint(UseSystemRNG) << min << sup;
+ QTest::addRow("system:%g-%g", min, sup) << uint(UseSystemRNG | SkipHWRNG) << min << sup;
+# ifdef HAVE_FALLBACK_ENGINE
+ QTest::addRow("system-fallback:%g-%g", min, sup) << uint(UseSystemRNG | SkipHWRNG | SkipSystemRNG) << min << sup;
+# endif
+#endif
+ QTest::addRow("global:%g-%g", min, sup) << 0U << min << sup;
};
newRow(0, 0); // useless: we can only generate zeroes
@@ -670,7 +836,7 @@ void tst_QRandomGenerator::stdUniformRealDistribution()
QFETCH(uint, control);
QFETCH(double, min);
QFETCH(double, sup);
- setRNGControl(control & (SkipHWRNG|SkipSystemRNG));
+ RandomGenerator rng(control & (SkipHWRNG|SkipSystemRNG|UseSystemRNG));
{
QRandomGenerator rd;
@@ -695,13 +861,9 @@ void tst_QRandomGenerator::stdUniformRealDistribution()
}
}
-void tst_QRandomGenerator::stdRandomDistributions()
+template <typename Generator> void stdRandomDistributions_template()
{
- // just a compile check for some of the distributions, besides
- // std::uniform_int_distribution and std::uniform_real_distribution (tested
- // above)
-
- QRandomGenerator rd;
+ Generator rd;
std::bernoulli_distribution()(rd);
@@ -723,6 +885,16 @@ void tst_QRandomGenerator::stdRandomDistributions()
}
}
+void tst_QRandomGenerator::stdRandomDistributions()
+{
+ // just a compile check for some of the distributions, besides
+ // std::uniform_int_distribution and std::uniform_real_distribution (tested
+ // above)
+
+ stdRandomDistributions_template<QRandomGenerator>();
+ stdRandomDistributions_template<QRandomGenerator64>();
+}
+
QTEST_APPLESS_MAIN(tst_QRandomGenerator)
#include "tst_qrandomgenerator.moc"