1 /**
2    C++ tests that must run
3  */
4 module it.cpp.run;
5 
6 import it;
7 
8 @Tags("run")
9 @("ctor")
10 @safe unittest {
11     shouldCompileAndRun(
12         Cpp(
13             q{
14                 struct Struct {
15                     void *data;
16 
17                     Struct(int i);
18                     Struct(const Struct&);
19                     Struct(Struct&&);
20 
21                     int number() const;
22                 };
23             }
24         ),
25         Cpp(
26             `
27                 #include <iostream>
28                 using namespace std;
29                 Struct::Struct(int i) {
30                     cout << "C++: int ctor" << endl;
31                     data = new int(i);
32                 }
33                 Struct::Struct(const Struct& other) {
34                     cout << "C++: copy ctor" << endl;
35                     data = new int(*reinterpret_cast<int*>(other.data) - 1);
36                 }
37                 Struct::Struct(Struct&& other) {
38                     cout << "C++: move ctor" << endl;
39                     data = other.data;
40                     *reinterpret_cast<int*>(data) = number() + 1;
41                 }
42                 int Struct::number() const { return *reinterpret_cast<int*>(data); }
43             `
44         ),
45         D(
46             q{
47                 import std.stdio;
48                 import std.process;
49 
50                 const dCompiler = environment.get("DC", "dmd");
51 
52                 writeln("D: Testing int ctor");
53                 auto cs = const Struct(42);
54                 assert(cs.number() == 42);
55                 assert(*(cast(int*)cs.data) == 42);
56                 auto ms = Struct(7);
57 
58                 writeln("D: Testing copy ctor");
59                 {
60                     auto s = Struct(cs);
61                     assert(s.number() == 41);
62                     assert(cs.data !is s.data);
63                 }
64                 {
65                     auto s = Struct(ms);
66                     assert(s.number() == 6);
67                     assert(cs.data !is s.data);
68                 }
69 
70                 writeln("D: Testing move ctor");
71                 auto tmp = Struct(33);
72                 const oldTmpData = tmp.data;
73                 auto mv1 = Struct(dpp.move(tmp));
74                 assert(mv1.number() == 34);
75                 assert(mv1.data is oldTmpData);
76                 assert(tmp.data is null);
77 
78                 static assert(!__traits(compiles, Struct(dpp.move(cs))));
79 
80                 if(dCompiler != "dmd") {
81                     auto mv2 = Struct(Struct(77));
82                     assert(mv2.number() == 78);
83                 }
84 
85                 static assert(!__traits(compiles, Struct()));
86             }
87          ),
88     );
89 }
90 
91 
92 @Tags("run")
93 @("dtor")
94 @safe unittest {
95     shouldCompileAndRun(
96         Cpp(
97             q{
98                 struct Struct {
99                     static int numStructs;
100                     Struct(int i);
101                     ~Struct();
102                 };
103             }
104         ),
105         Cpp(
106             q{
107                 int Struct::numStructs;
108                 // the i parameter is to force D to call a constructor,
109                 // since Struct() just blasts it with Struct.init
110                 Struct::Struct(int i)  { numStructs += i; }
111                 Struct::~Struct()      { --numStructs; }
112             }
113         ),
114         D(
115             q{
116                 import std.conv: text;
117                 assert(Struct.numStructs == 0, Struct.numStructs.text);
118                 {
119                     auto s1 = Struct(3);
120                     assert(Struct.numStructs == 3, Struct.numStructs.text);
121 
122                     {
123                         auto s2 = Struct(2);
124                         assert(Struct.numStructs == 5, Struct.numStructs.text);
125                     }
126 
127                     assert(Struct.numStructs == 4, Struct.numStructs.text);
128                 }
129 
130                 assert(Struct.numStructs == 3, Struct.numStructs.text);
131             }
132          ),
133     );
134 }
135 
136 
137 @Tags("run")
138 @("function")
139 @safe unittest {
140     shouldCompileAndRun(
141         Cpp(
142             q{
143                 int add(int i, int j);
144 
145                 struct Adder {
146                     int i;
147                     Adder(int i);
148                     int add(int j);
149                 };
150             }
151         ),
152         Cpp(
153             q{
154                 int add(int i, int j) { return i + j; }
155                 Adder::Adder(int i):i(i + 10) {}
156                 int Adder::add(int j) { return i + j; }
157             }
158         ),
159         D(
160             q{
161                 import std.conv: text;
162                 import std.exception: assertThrown;
163                 import core.exception: AssertError;
164 
165                 assert(add(2, 3) == 5, "add(2, 3) should be 5");
166 
167                 void func() {
168                     assert(add(2, 3) == 7);
169                 }
170                 assertThrown!AssertError(func(), "add(2, 3) should not be 7");
171 
172                 auto adder = Adder(3);
173                 assert(adder.add(4) == 17, "Adder(3).add(4) should be 17 not " ~ text(adder.add(4)));
174             }
175          ),
176     );
177 }
178 
179 @Tags("run", "collision")
180 @("collisions")
181 @safe unittest {
182     shouldRun(
183         Cpp(
184             q{
185                 struct foo {
186                     int i;
187                 };
188                 int foo(int i, int j);
189                 struct foo add_foo_ptrs(const struct foo* f1, const struct foo* f2);
190 
191                 union bar {
192                     int i;
193                     double d;
194                 };
195                 int bar(int i);
196 
197                 enum baz { one, two, three };
198                 int baz();
199 
200                 enum other { four, five };
201                 int other;
202             }
203         ),
204         Cpp(
205             q{
206                 int foo(int i, int j) { return i + j + 1; }
207                 struct foo add_foo_ptrs(const struct foo* f1, const struct foo* f2) {
208                     struct foo ret;
209                     ret.i = f1->i + f2->i;
210                     return ret;
211                 }
212                 int bar(int i) { return i * 2; }
213                 int baz() { return 42; }
214             }
215         ),
216         D(
217             q{
218                 assert(foo_(2, 3) == 6);
219                 assert(bar_(4) == 8);
220                 assert(baz_ == 42);
221 
222                 auto f1 = foo(2);
223                 auto f2 = foo(3);
224                 assert(add_foo_ptrs(&f1, &f2) == foo(5));
225 
226                 bar b;
227                 b.i = 42;
228                 b.d = 33.3;
229 
230                 baz z1 = two;
231                 baz z2 = baz.one;
232 
233                 other_ = 77;
234                 other o1 = other.four;
235                 other o2 = five;
236 
237                 import std.exception: assertThrown;
238                 import core.exception: AssertError;
239                 void func() {
240                     assert(foo_(2, 3) == 7);
241                 }
242                 assertThrown!AssertError(func());
243             }
244          ),
245     );
246 }
247 
248 
249 @Tags("run")
250 @("operators")
251 @safe unittest {
252     shouldRun(
253         Cpp(
254             q{
255                 struct Struct {
256                     int i;
257                     Struct(int i);
258 
259                     // Unary operators
260                     Struct operator+ ()    const;
261                     Struct operator- ()    const;
262                     Struct operator* ()    const;
263                     Struct operator& ()    const;
264                     Struct operator->()    const;
265                     Struct operator~ ()    const;
266                     bool   operator! ()    const;
267                     Struct operator++()    const;
268                     Struct operator--()    const;
269                     Struct operator++(int) const; // not defined on purpose
270                     Struct operator--(int) const; // not defined on purpose
271 
272                     // Binary operators
273                     Struct operator+  (const Struct& other) const;
274                     Struct operator-  (const Struct& other) const;
275                     Struct operator*  (const Struct& other) const;
276                     Struct operator/  (const Struct& other) const;
277                     Struct operator%  (const Struct& other) const;
278                     Struct operator^  (const Struct& other) const;
279                     Struct operator&  (const Struct& other) const;
280                     Struct operator|  (const Struct& other) const;
281                     Struct operator>> (const Struct& other) const;
282                     Struct operator<< (const Struct& other) const;
283                     Struct operator&& (const Struct& other) const;
284                     Struct operator|| (const Struct& other) const;
285                     Struct operator->*(const Struct& other) const;
286                     Struct operator,  (const Struct& other) const;
287 
288                     // assignment
289                     void operator=  (const Struct& other);
290                     void operator+= (int j);
291                     void operator-= (int j);
292                     void operator*= (int j);
293                     void operator/= (int j);
294                     void operator%= (int j);
295                     void operator^= (int j);
296                     void operator&= (int j);
297                     void operator|= (int j);
298                     void operator>>=(int j);
299                     void operator<<=(int j);
300 
301                     // special
302                     int operator()(int j) const;
303                     int operator[](int j) const;
304 
305                     // comparison
306                     bool operator==(int j) const;
307                     bool operator!=(const Struct& other) const; // not defined on purpose
308                     bool operator>=(const Struct& other) const; // not defined on purpose
309                     bool operator<=(const Struct& other) const; // not defined on purpose
310                     bool operator> (const Struct& other) const;
311                     bool operator< (const Struct& other) const;
312 
313                     // conversion
314                     operator int() const;
315 
316                     // allocation
317                     static void* operator new(unsigned long);
318                     static void* operator new[](unsigned long);
319                     static void operator delete(void*);
320                     static void operator delete[](void*);
321                 };
322 
323                 struct Stream {};
324                 Stream& operator<<(Stream& stream, const Struct& s);
325             }
326         ),
327         Cpp(
328             q{
329                 Struct::Struct(int i):i{i} {}
330                 Struct Struct::operator+ () const { return { +i };    }
331                 Struct Struct::operator- () const { return { -i };    }
332                 Struct Struct::operator* () const { return { i * 3 }; }
333                 Struct Struct::operator& () const { return { i / 4 }; }
334                 Struct Struct::operator->() const { return { i / 3 }; }
335                 Struct Struct::operator~ () const { return { i + 9 }; }
336                 bool   Struct::operator! () const { return i != 7;    }
337                 Struct Struct::operator++() const { return { i + 1 }; }
338                 Struct Struct::operator--() const { return { i - 1 }; }
339 
340                 Struct Struct::operator+  (const Struct& other) const { return { i + other.i }; }
341                 Struct Struct::operator-  (const Struct& other) const { return { i - other.i }; }
342                 Struct Struct::operator*  (const Struct& other) const { return { i * other.i }; }
343                 Struct Struct::operator/  (const Struct& other) const { return { i / other.i }; }
344                 Struct Struct::operator%  (const Struct& other) const { return { i % other.i }; }
345                 Struct Struct::operator^  (const Struct& other) const { return { i + other.i + 2 }; }
346                 Struct Struct::operator&  (const Struct& other) const { return { i * other.i + 1 }; }
347                 Struct Struct::operator|  (const Struct& other) const { return { i + other.i + 1 }; }
348                 Struct Struct::operator<< (const Struct& other) const { return { i + other.i }; }
349                 Struct Struct::operator>> (const Struct& other) const { return { i - other.i }; }
350                 Struct Struct::operator&& (const Struct& other) const { return { i && other.i }; }
351                 Struct Struct::operator|| (const Struct& other) const { return { i || other.i }; }
352                 Struct Struct::operator->*(const Struct& other) const { return { i - other.i }; }
353                 Struct Struct::operator,  (const Struct& other) const { return { i - other.i - 1 }; }
354 
355                 void Struct::operator= (const Struct& other)  { i = other.i + 10; };
356                 void Struct::operator+=(int j)                { i += j;           };
357                 void Struct::operator-=(int j)                { i -= j;           };
358                 void Struct::operator*=(int j)                { i *= j;           };
359                 void Struct::operator/=(int j)                { i /= j;           };
360                 void Struct::operator%=(int j)                { i %= j;           };
361                 void Struct::operator^=(int j)                { i ^= j;           };
362                 void Struct::operator&=(int j)                { i &= j;           };
363                 void Struct::operator|=(int j)                { i |= j;           };
364                 void Struct::operator>>=(int j)               { i >>= j;          };
365                 void Struct::operator<<=(int j)               { i <<= j;          };
366 
367                 int Struct::operator()(int j) const { return i * j; }
368                 int Struct::operator[](int j) const { return i / j; }
369 
370                 bool Struct::operator==(int j) const { return i == j; }
371                 bool Struct::operator<(const Struct& other) const { return i < other.i; }
372                 bool Struct::operator>(const Struct& other) const { return i > other.i; }
373 
374                 Struct::operator int() const { return i + 1; }
375 
376                 void* Struct::operator new(unsigned long count) { return new int{static_cast<int>(count)}; }
377                 void* Struct::operator new[](unsigned long count) { return new int{static_cast<int>(count + 1)}; }
378                 void Struct::operator delete(void*) {}
379                 void Struct::operator delete[](void*) {}
380 
381                 Stream& operator<<(Stream& stream, const Struct& s) { return stream; }
382             }
383         ),
384         D(
385             q{
386                 import std.conv: text;
387 
388                 // unary
389                 assert(+Struct(-4) == -4);
390                 assert(-Struct(4)  == -4);
391                 assert(-Struct(-5) == 5);
392                 assert(*Struct(2) == 6);
393                 assert(Struct(8).opCppAmpersand == 2);
394                 assert(Struct(9).opCppArrow == 3);
395                 assert(~Struct(7) == 16);
396                 assert(Struct(9).opCppBang);
397 
398                 assert(++Struct(2) == 3);
399                 assert(--Struct(5) == 4);
400 
401                 // binary
402                 auto s0 = const Struct(0);
403                 auto s2 = const Struct(2);
404                 auto s3 = const Struct(3);
405 
406                 assert(s2 + s3 == 5);
407                 assert(s3 - s2 == 1);
408                 assert(Struct(5) - s2 == 3);
409                 assert(s2 * s3 == 6);
410                 assert(Struct(11) / s3 == 3) ;
411 
412                 assert(Struct(5) % s2 == 1);
413                 assert(Struct(6) % s2 == 0);
414 
415                 assert((Struct(4) ^ s2) == 8);
416                 assert((Struct(4) & s2) == 9);
417                 assert((Struct(4) | s2) == 7);
418 
419                 assert(Struct(7) >> s2 == 5);
420                 assert(Struct(3) << s3 == 6);
421 
422                 assert(Struct(5).opCppArrowStar(s2) == 3);
423                 assert(Struct(5).opCppComma(s2) == 2);
424 
425                 // assignment
426                 {
427                     auto s = Struct(5);
428                     s = s2; assert(s == 12);
429                 }
430 
431                 {
432                     auto s = Struct(2);
433                     s += 3; assert(s == 5);
434                     s -= 2; assert(s == 3);
435                     s *= 2; assert(s == 6);
436                     s /= 3; assert(s == 2);
437                     s = s3;
438                     s %= 2; assert(s == 1);
439                     s ^= 1; assert(s == 0);
440                     s &= 1; assert(s == 0);
441                     s |= 1; assert(s == 1);
442                     s.i = 8;
443                     s >>= 2; assert(s == 2);
444                     s <<= 1; assert(s == 4);
445                 }
446 
447                 // special
448                 assert(Struct(2)(3) == 6);
449                 assert(Struct(7)[2] == 3);
450 
451                 // comparison (== already done everywhere above)
452                 assert(Struct(3) <  Struct(5));
453                 assert(Struct(5) >  Struct(3));
454                 assert(Struct(3) <= Struct(5));
455                 assert(Struct(3) <= Struct(3));
456                 assert(Struct(5) >  Struct(3));
457                 assert(Struct(5) >= Struct(5));
458 
459                 // conversion
460                 assert(cast(int) Struct(7) == 8);
461                 assert( cast(bool) Struct(7));
462                 assert(!cast(bool) Struct(3));
463 
464                 // allocation
465                 assert(*(cast(int*) Struct.opCppNew(5)) == 5);
466                 assert(*(cast(int*) Struct.opCppNewArray(5)) == 6);
467                 Struct.opCppDelete(null);
468                 Struct.opCppDeleteArray(null);
469 
470                 // free function
471                 Stream stream;
472                 stream.opCppLShift(s2);
473             }
474          ),
475     );
476 }
477 
478 @Tags("run")
479 @("templates")
480 @safe unittest {
481     shouldRun(
482         Cpp(
483             q{
484                 template<typename T>
485                 class vector {
486                     T _values[10];
487                     int _numValues = 0;
488 
489                 public:
490                     void push_back(T value) {
491                         _values[_numValues++] = value;
492                     }
493 
494                     int numValues() { return _numValues; }
495                     T value(int i) { return _values[i]; }
496                 };
497             }
498         ),
499         Cpp(
500             `
501                 #if __clang__
502                     [[clang::optnone]]
503                 #elif __GNUC__
504                     __attribute__((optimize("O0")))
505                 #endif
506                     __attribute((used, noinline))
507                 static void instantiate() {
508                     vector<int> v;
509                     v.push_back(42);
510                     v.value(0);
511                     v.numValues();
512                 }
513             `
514         ),
515         D(
516             q{
517                 vector!int v;
518                 assert(v.numValues == 0);
519 
520                 v.push_back(4);
521                 assert(v.numValues == 1);
522                 assert(v.value(0) == 4);
523 
524                 v.push_back(2);
525                 assert(v.numValues == 2);
526                 assert(v.value(0) == 4);
527                 assert(v.value(1) == 2);
528 
529                 foreach(i; 2 .. v.numValues)
530                     assert(v.value(i) == 0);
531             }
532          ),
533     );
534 }
535 
536 
537 @Tags("run")
538 @("namespaces")
539 @safe unittest {
540     shouldRun(
541         Cpp(
542             q{
543                 namespace ns0 {
544                     int foo();
545                     int bar();
546                     namespace ns1 {
547                         int baz();
548                     }
549                 }
550 
551                 namespace other {
552                     int quux();
553                 }
554 
555                 // can reopen namespace
556                 namespace ns0 {
557                     int toto();
558                 }
559             }
560         ),
561         Cpp(
562             q{
563                 namespace ns0 {
564                     int foo() { return 1; }
565                     int bar() { return 2; }
566                     namespace ns1 {
567                         int baz() { return 3; }
568                     }
569                 }
570 
571                 namespace other {
572                     int quux() { return 4; }
573                 }
574 
575                 // can reopen namespace
576                 namespace ns0 {
577                     int toto() { return 5; }
578                 }
579             }
580         ),
581         D(
582             q{
583                 assert(foo == 1);
584                 assert(bar == 2);
585                 assert(baz == 3);
586                 assert(quux == 4);
587                 assert(toto == 5);
588             }
589          ),
590     );
591 }