1 // QT_MODULES: core
2 module testcore1;
3 
4 import qt.config;
5 import qt.core.coreapplication;
6 import qt.core.list;
7 import qt.core.object;
8 import qt.core.string;
9 import qt.core.typeinfo;
10 import qt.core.variant;
11 import qt.core.vector;
12 import qt.helpers;
13 import std.stdio;
14 
15 QCoreApplication app;
16 shared static this()
17 {
18     import core.runtime;
19     app = new QCoreApplication(Runtime.cArgs.argc, Runtime.cArgs.argv);
20     assert(QCoreApplication.instance() is app);
21 }
22 
23 class TestObject : QObject
24 {
25     mixin(Q_OBJECT_D);
26 public:
27     /+ explicit +/@QInvokable this(QObject parent = null)
28     {
29         super(parent);
30         lastStr = QString.create;
31     }
32 
33     QString lastStr;
34 
35     @QInvokable final void emitSignalVoid()
36     {
37         /+ emit +/ signalVoid();
38     }
39     @QInvokable final void emitSignalInt(int i)
40     {
41         /+ emit +/ signalInt(i);
42     }
43     @QInvokable final void emitSignalInt3(int x, int y, int z)
44     {
45         /+ emit +/ signalInt3(x, y, z);
46     }
47     @QInvokable final void emitSignalDouble(double d)
48     {
49         /+ emit +/ signalDouble(d);
50     }
51     @QInvokable final void emitSignalString(ref const(QString) s)
52     {
53         /+ emit +/ signalString(s);
54     }
55     @QInvokable final void emitSignalListInt(ref const(QList!(int)) l)
56     {
57         /+ emit +/ signalListInt(l);
58     }
59     @QInvokable final void emitSignalVectorInt(ref const(QVector!(int)) v)
60     {
61         /+ emit +/ signalVectorInt(v);
62     }
63     @QInvokable final void emitSignalPointerInt(int* p)
64     {
65         /+ emit +/ signalPointerInt(p);
66     }
67 
68 /+ signals +/public:
69     @QSignal final void signalVoid(){mixin(Q_SIGNAL_IMPL_D);}
70     @QSignal final void signalInt(int i){mixin(Q_SIGNAL_IMPL_D);}
71     @QSignal final void signalInt3(int x, int y, int z){mixin(Q_SIGNAL_IMPL_D);}
72     @QSignal final void signalDouble(double d){mixin(Q_SIGNAL_IMPL_D);}
73     @QSignal final void signalString(ref const(QString) s){mixin(Q_SIGNAL_IMPL_D);}
74     @QSignal final void signalListInt(ref const(QList!(int)) l){mixin(Q_SIGNAL_IMPL_D);}
75     @QSignal final void signalVectorInt(ref const(QVector!(int)) v){mixin(Q_SIGNAL_IMPL_D);}
76     @QSignal final void signalPointerInt(int* p){mixin(Q_SIGNAL_IMPL_D);}
77 
78 public /+ slots +/:
79     @QSlot final void onSignalVoid()
80     {
81         lastStr = QString("void");
82     }
83     @QSlot final void onSignalInt(int i)
84     {
85         lastStr = "int " ~ QString.number(i);
86     }
87     @QSlot final void onSignalInt3(int x, int y, int z)
88     {
89         lastStr = "int3 " ~ QString.number(x) ~ " " ~ QString.number(y) ~ " " ~ QString.number(z);
90     }
91     @QSlot final void onSignalDouble(double d)
92     {
93         lastStr = "double " ~ QString.number(d);
94     }
95     @QSlot final void onSignalString(ref const(QString) s)
96     {
97         lastStr = "QString " ~ s;
98     }
99     @QSlot final void onSignalListInt(ref const(QList!(int)) l)
100     {
101         lastStr = QString("QList<int>");
102         for(int i=0; i<l.size(); i++)
103             lastStr ~= " " ~ QString.number(l[i]);
104     }
105     @QSlot final void onSignalVectorInt(ref const(QVector!(int)) v)
106     {
107         lastStr = QString("QVector<int>");
108         for(int i=0; i<v.size(); i++)
109             lastStr ~= " " ~ QString.number(v[i]);
110     }
111     @QSlot final void onSignalPointerInt(int* p)
112     {
113         lastStr = "int* " ~ QString.number(*p);
114     }
115 
116 }
117 
118 unittest
119 {
120     QString s = QString.create;
121     s = QString("QString(Utf8): abc äöüÄÖÜßẞ αβ ∃∀ ∨∧⊥¬ ≤≥≠ 𝕆🎵🎶");
122     assert(s.toConstWString == "QString(Utf8): abc äöüÄÖÜßẞ αβ ∃∀ ∨∧⊥¬ ≤≥≠ 𝕆🎵🎶"w);
123 
124     s = QString.fromUtf8("QString::fromUtf8: abc äöüÄÖÜßẞ αβ ∃∀ ∨∧⊥¬ ≤≥≠ 𝕆🎵🎶".ptr);
125     assert(s.toConstWString == "QString::fromUtf8: abc äöüÄÖÜßẞ αβ ∃∀ ∨∧⊥¬ ≤≥≠ 𝕆🎵🎶"w);
126 
127     s = QString("QString(Utf16): abc äöüÄÖÜßẞ αβ ∃∀ ∨∧⊥¬ ≤≥≠ 𝕆🎵🎶"w);
128     assert(s.toConstWString == "QString(Utf16): abc äöüÄÖÜßẞ αβ ∃∀ ∨∧⊥¬ ≤≥≠ 𝕆🎵🎶"w);
129 
130     s = QString.fromUtf16("QString::fromUtf16: abc äöüÄÖÜßẞ αβ ∃∀ ∨∧⊥¬ ≤≥≠ 𝕆🎵🎶"w.ptr);
131     assert(s.toConstWString == "QString::fromUtf16: abc äöüÄÖÜßẞ αβ ∃∀ ∨∧⊥¬ ≤≥≠ 𝕆🎵🎶"w);
132 
133     s = QString("QString(Utf32): abc äöüÄÖÜßẞ αβ ∃∀ ∨∧⊥¬ ≤≥≠ 𝕆🎵🎶"d);
134     assert(s.toConstWString == "QString(Utf32): abc äöüÄÖÜßẞ αβ ∃∀ ∨∧⊥¬ ≤≥≠ 𝕆🎵🎶"w);
135 
136     s = QString.fromUcs4("QString::fromUcs4: abc äöüÄÖÜßẞ αβ ∃∀ ∨∧⊥¬ ≤≥≠ 𝕆🎵🎶"d.ptr);
137     assert(s.toConstWString == "QString::fromUcs4: abc äöüÄÖÜßẞ αβ ∃∀ ∨∧⊥¬ ≤≥≠ 𝕆🎵🎶"w);
138 }
139 
140 void checkType(T, bool relocatable, bool complex)()
141 {
142     //writefln("checkType!(%s, %d, %d)();\n", T.stringof, QTypeInfo!T.isRelocatable, QTypeInfo!T.isComplex);
143     static assert(QTypeInfo!(T).isRelocatable == relocatable);
144     static assert(QTypeInfo!(T).isComplex == complex);
145 }
146 
147 unittest
148 {
149     import core.stdc.wchar_;
150     import qt.core.abstractitemmodel;
151     import qt.core.bytearray;
152     import qt.core.itemselectionmodel;
153     import qt.core.line;
154     import qt.core.locale;
155     import qt.core.namespace;
156     import qt.core.pair;
157     import qt.core.point;
158     import qt.core.size;
159     import qt.core.stringview;
160     import qt.core.timezone;
161     import qt.core.url;
162 
163     checkType!(double, 1, 0)();
164     checkType!(int, 1, 0)();
165     checkType!(uint, 1, 0)();
166     checkType!(int*, 1, 0)();
167     checkType!(void*, 1, 0)();
168     checkType!(void, 0, 0)();
169     checkType!(ubyte, 1, 0)();
170     checkType!(char, 1, 0)();
171     checkType!(wchar, 1, 0)();
172     checkType!(wchar_t, 1, 0)();
173     checkType!(QLocale.Country, 1, 0)();
174     checkType!(/+ Qt:: +/qt.core.namespace.DayOfWeek, 1, 0)();
175     checkType!(QTimeZone.OffsetData, 1, 1)();
176     checkType!(QByteArray, 1, 1)();
177     checkType!(QItemSelectionRange, 1, 1)();
178     checkType!(QLine, 1, 1)();
179     checkType!(QLineF, 1, 1)();
180     checkType!(QLocale, 1, 1)();
181     checkType!(QModelIndex, 1, 1)();
182     checkType!(QObject, 1, 0)();
183     checkType!(qt.core.pair.QPair!(double, QSize), 1, 1)();
184     checkType!(QPersistentModelIndex, 1, 1)();
185     checkType!(QPoint, 1, 0)();
186     checkType!(QPointF, 1, 0)();
187     checkType!(QSize, 1, 1)();
188     checkType!(QString, 1, 1)();
189     checkType!(QStringView, 1, 0)();
190     checkType!(QUrl, 1, 1)();
191     checkType!(QVariant, 1, 1)();
192     checkType!(QAbstractItemModel, 1, 0)();
193     checkType!(QTimeZone.OffsetData, 1, 1)();
194     checkType!(QList!(int), 1, 1)();
195     checkType!(QList!(void*), 1, 1)();
196     checkType!(QList!(QSize), 1, 1)();
197     checkType!(QVector!(int), 1, 1)();
198     checkType!(QVector!(void*), 1, 1)();
199     checkType!(QVector!(QSize), 1, 1)();
200     checkType!(/+ Qt:: +/qt.core.namespace.Edge, 1, 0)();
201     checkType!(/+ Qt:: +/qt.core.namespace.Edges, 1, 0)();
202 }
203 
204 unittest
205 {
206     import core.stdc.string;
207     import core.stdcpp.new_;
208     import qt.core.metaobject;
209     import qt.core.metatype;
210     import qt.core.objectdefs;
211 
212     const(QMetaObject)* mo = &TestObject.staticMetaObject;
213     assert(strcmp(mo.className(), "TestObject") == 0);
214     //assert(mo->constructorCount() == 2);
215     assert(mo.methodCount() - mo.methodOffset() == 8 + 8 + 8);
216 
217     TestObject a = cpp_new!TestObject();
218     assert(a.metaObject() == mo);
219 
220     QMetaMethod method = mo.method(mo.methodOffset() + 0);
221     assert(method.name().toConstCharArray() == "signalVoid");
222     assert(method.methodSignature().toConstCharArray() == "signalVoid()");
223     assert(method.parameterCount() == 0);
224 
225     method = mo.method(mo.methodOffset() + 1);
226     assert(method.name().toConstCharArray() == "signalInt");
227     assert(method.methodSignature().toConstCharArray() == "signalInt(int)");
228     assert(method.parameterCount() == 1);
229     assert(method.parameterType(0) == QMetaType.Type.Int);
230 
231     method = mo.method(mo.methodOffset() + 2);
232     assert(method.name().toConstCharArray() == "signalInt3");
233     assert(method.methodSignature().toConstCharArray() == "signalInt3(int,int,int)");
234     assert(method.parameterCount() == 3);
235     assert(method.parameterType(0) == QMetaType.Type.Int);
236     assert(method.parameterType(1) == QMetaType.Type.Int);
237     assert(method.parameterType(2) == QMetaType.Type.Int);
238 
239     method = mo.method(mo.methodOffset() + 3);
240     assert(method.name().toConstCharArray() == "signalDouble");
241     assert(method.methodSignature().toConstCharArray() == "signalDouble(double)");
242     assert(method.parameterCount() == 1);
243     assert(method.parameterType(0) == QMetaType.Type.Double);
244 
245     method = mo.method(mo.methodOffset() + 4);
246     assert(method.name().toConstCharArray() == "signalString");
247     assert(method.methodSignature().toConstCharArray() == "signalString(QString)");
248     assert(method.parameterCount() == 1);
249     assert(method.parameterType(0) == QMetaType.Type.QString);
250 
251     method = mo.method(mo.methodOffset() + 5);
252     assert(method.name().toConstCharArray() == "signalListInt");
253     assert(method.methodSignature().toConstCharArray() == "signalListInt(QList<int>)");
254     assert(method.parameterCount() == 1);
255 
256     method = mo.method(mo.methodOffset() + 6);
257     assert(method.name().toConstCharArray() == "signalVectorInt");
258     assert(method.methodSignature().toConstCharArray() == "signalVectorInt(QList<int>)");
259     assert(method.parameterCount() == 1);
260 
261     method = mo.method(mo.methodOffset() + 7);
262     assert(method.name().toConstCharArray() == "signalPointerInt");
263     assert(method.methodSignature().toConstCharArray() == "signalPointerInt(int*)");
264     assert(method.parameterCount() == 1);
265 }
266 
267 void connectByString(TestObject a, TestObject b)
268 {
269     import qt.core.object;
270     import qt.core.objectdefs;
271 
272     QObject.connect(a, (mixin(SIGNAL(q{signalVoid()}))).ptr, b, (mixin(SLOT(q{onSignalVoid()}))).ptr);
273     QObject.connect(a, (mixin(SIGNAL(q{signalInt(int)}))).ptr, b, (mixin(SLOT(q{onSignalInt(int)}))).ptr);
274     QObject.connect(a, (mixin(SIGNAL(q{signalInt3(int,int,int)}))).ptr, b, (mixin(SLOT(q{onSignalInt3(int,int,int)}))).ptr);
275     QObject.connect(a, (mixin(SIGNAL(q{signalDouble(double)}))).ptr, b, (mixin(SLOT(q{onSignalDouble(double)}))).ptr);
276     QObject.connect(a, (mixin(SIGNAL(q{signalString(const QString&)}))).ptr, b, (mixin(SLOT(q{onSignalString(const QString&)}))).ptr);
277     QObject.connect(a, (mixin(SIGNAL(q{signalListInt(const QList<int>&)}))).ptr, b, (mixin(SLOT(q{onSignalListInt(const QList<int>&)}))).ptr);
278     QObject.connect(a, (mixin(SIGNAL(q{signalVectorInt(const QVector<int>&)}))).ptr, b, (mixin(SLOT(q{onSignalVectorInt(const QVector<int>&)}))).ptr);
279     QObject.connect(a, (mixin(SIGNAL(q{signalPointerInt(int*)}))).ptr, b, (mixin(SLOT(q{onSignalPointerInt(int*)}))).ptr);
280 }
281 
282 void connectByPointer(TestObject a, TestObject b)
283 {
284     import qt.core.list;
285     import qt.core.object;
286     import qt.core.vector;
287 
288     QObject.connect(a.signal!"signalVoid", b.slot!"onSignalVoid");
289     QObject.connect(a.signal!"signalInt", b.slot!"onSignalInt");
290     QObject.connect(a.signal!"signalInt3", b.slot!"onSignalInt3");
291     QObject.connect(a.signal!"signalDouble", b.slot!"onSignalDouble");
292     QObject.connect(a.signal!"signalString", b.slot!"onSignalString");
293     QObject.connect(a.signal!"signalListInt", b.slot!"onSignalListInt");
294     QObject.connect(a.signal!"signalVectorInt", b.slot!"onSignalVectorInt");
295     QObject.connect(a.signal!"signalPointerInt", b.slot!"onSignalPointerInt");
296 }
297 
298 void testSignals(TestObject a, TestObject b)
299 {
300     import qt.core.list;
301     import qt.core.vector;
302 
303     a.emitSignalVoid();
304     assert(b.lastStr == "void");
305     a.emitSignalInt(5);
306     assert(b.lastStr == "int 5");
307     a.emitSignalInt3(1, 2, 3);
308     assert(b.lastStr == "int3 1 2 3");
309     a.emitSignalDouble(16.5);
310     assert(b.lastStr == "double 16.5");
311     auto tmp = QString("test"); a.emitSignalString(tmp);
312     assert(b.lastStr == "QString test");
313     QList!(int) l = QList!(int).create();
314     l ~= 10;
315     l ~= 11;
316     l ~= 12;
317     a.emitSignalListInt(l);
318     assert(b.lastStr == "QList<int> 10 11 12");
319     QVector!(int) v = QVector!(int).create();
320     v ~= 20;
321     v ~= 21;
322     v ~= 22;
323     a.emitSignalVectorInt(v);
324     assert(b.lastStr == "QVector<int> 20 21 22");
325     int x = 30;
326     a.emitSignalPointerInt(&x);
327     assert(b.lastStr == "int* 30");
328 }
329 
330 unittest
331 {
332     import core.stdcpp.new_;
333 
334     TestObject a = cpp_new!TestObject();
335     TestObject b = cpp_new!TestObject();
336     connectByString(a, b);
337     testSignals(a, b);
338 }
339 
340 unittest
341 {
342     import core.stdcpp.new_;
343 
344     TestObject a = cpp_new!TestObject();
345     TestObject b = cpp_new!TestObject();
346     connectByPointer(a, b);
347     testSignals(a, b);
348 }
349 
350 void compareVariant(ref const(QVariant) v, const(char)* expected)
351 {
352     import core.stdc.stdio;
353 
354     char[(v). sizeof * 3 + 1] buffer;
355     size_t pos = 0;
356     for(size_t i=0; i<(v). sizeof; i++)
357     {
358         snprintf(&buffer[pos], 3, "%02X", (cast(ubyte*)&v)[i]);
359         pos += 2;
360         if(i % 4 == 3 && i + 1 < (v). sizeof)
361         {
362             buffer[pos] = ' ';
363             pos++;
364         }
365     }
366     buffer[pos] = 0;
367     bool different = false;
368     for(size_t i=0; i<pos; i++)
369     {
370         if(!expected[i])
371             break;
372         if(expected[i] == '?')
373             continue;
374         if(buffer[i] != expected[i])
375             different = true;
376     }
377     if(different)
378     {
379         printf("expected: %s\n", expected);
380         printf("got:      %s\n", buffer.ptr);
381         assert(false);
382     }
383 }
384 
385 unittest
386 {
387     QVariant v;
388     static if((void*).sizeof == 8)
389         compareVariant(v, "00000000 00000000 00000000 00000000 00000000 00000000 02000000 00000000");
390     else
391         compareVariant(v, "00000000 00000000 00000000 02000000");
392     v = QVariant(5);
393     static if((void*).sizeof == 8)
394         compareVariant(v, "05000000 00000000 00000000 00000000 00000000 00000000 ???????? ????????");
395     else
396         compareVariant(v, "05000000 00000000 00000000 ????????");
397     v = QVariant(100.0f);
398     static if((void*).sizeof == 8)
399         compareVariant(v, "0000C842 00000000 00000000 00000000 00000000 00000000 ???????? ????????");
400     else
401         compareVariant(v, "0000C842 00000000 00000000 ????????");
402     v = QVariant(100.0);
403     static if((void*).sizeof == 8)
404         compareVariant(v, "00000000 00005940 00000000 00000000 00000000 00000000 ???????? ????????");
405     else
406         compareVariant(v, "00000000 00005940 00000000 ????????");
407     v = QVariant(cast(int)'A');
408     static if((void*).sizeof == 8)
409         compareVariant(v, "41000000 00000000 00000000 00000000 00000000 00000000 ???????? ????????");
410     else
411         compareVariant(v, "41000000 00000000 00000000 ????????");
412 }
413 
414 unittest
415 {
416     import qt.core.objectdefs;
417 
418     size_t changeCount = 0;
419     {
420         scope QObject dummy = new QObject;
421         QObject.connect(QCoreApplication.instance().signal!"applicationNameChanged", dummy, (){
422             changeCount++;
423         });
424         assert(changeCount == 0);
425         QCoreApplication.setApplicationName(QString("ApplicationName1"));
426         assert(changeCount == 1);
427     }
428     QCoreApplication.setApplicationName(QString("ApplicationName2"));
429     // Slot was not called again, because dummy is out of scope.
430     assert(changeCount == 1);
431 
432     scope QObject dummy = new QObject;
433     QMetaObject.Connection connection = QObject.connect(QCoreApplication.instance().signal!"applicationNameChanged", dummy, (){
434         changeCount++;
435     });
436     assert(changeCount == 1);
437 
438     QCoreApplication.setApplicationName(QString("ApplicationName3"));
439     assert(changeCount == 2);
440 
441     QObject.disconnect(connection);
442     QCoreApplication.setApplicationName(QString("ApplicationName4"));
443     assert(changeCount == 2);
444 }
445 
446 unittest
447 {
448     import core.stdcpp.new_;
449     import qt.core.timer;
450 
451     QObject obj = cpp_new!QObject();
452     assert(qobject_cast!(QObject)(obj) is obj);
453     assert(qobject_cast!(TestObject)(obj) is null);
454     assert(qobject_cast!(QTimer)(obj) is null);
455 
456     TestObject testObject = cpp_new!TestObject();
457     assert(qobject_cast!(QObject)(testObject) is testObject);
458     assert(qobject_cast!(TestObject)(testObject) is testObject);
459     assert(qobject_cast!(QTimer)(testObject) is null);
460 
461     QTimer timer = cpp_new!QTimer();
462     assert(qobject_cast!(QObject)(timer) is timer);
463     assert(qobject_cast!(TestObject)(timer) is null);
464     assert(qobject_cast!(QTimer)(timer) is timer);
465 }
466 
467 unittest
468 {
469     import qt.core.algorithms;
470 
471     assert(qPopulationCount(0U) == 0);
472     assert(qPopulationCount(0xffffU) == 16);
473     assert(qPopulationCount(0xffffffffU) == 32);
474     assert(qPopulationCount(0xffffffffffffffffU) == 64);
475     assert(qPopulationCount(0x8000000000000000U) == 1);
476 
477     assert(qCountTrailingZeroBits(cast(ubyte)0U) == 8);
478     assert(qCountTrailingZeroBits(cast(ushort)0U) == 16);
479     assert(qCountTrailingZeroBits(0U) == 32);
480     assert(qCountTrailingZeroBits(cast(ulong)0U) == 64);
481     assert(qCountTrailingZeroBits(0x10U) == 4);
482     assert(qCountTrailingZeroBits(0x1000U) == 12);
483     assert(qCountTrailingZeroBits(0x80000000U) == 31);
484     assert(qCountTrailingZeroBits(0x8000000000000000U) == 63);
485     assert(qCountTrailingZeroBits(0xffffffff80000000U) == 31);
486 
487     assert(qCountLeadingZeroBits(cast(ubyte)0U) == 8);
488     assert(qCountLeadingZeroBits(cast(ushort)0U) == 16);
489     assert(qCountLeadingZeroBits(0U) == 32);
490     assert(qCountLeadingZeroBits(cast(ulong)0U) == 64);
491     assert(qCountLeadingZeroBits(0x10U) == 27);
492     assert(qCountLeadingZeroBits(0x1000U) == 19);
493     assert(qCountLeadingZeroBits(0x80000000U) == 0);
494     assert(qCountLeadingZeroBits(0x8000000000000000U) == 0);
495     assert(qCountLeadingZeroBits(0xffffffff80000000U) == 0);
496 }