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