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