1 module automem.test_utils;
2 
3 mixin template TestUtils() {
4     version(unittest) {
5         import unit_threaded;
6         import test_allocator;
7 
8         /**
9            Returns an object that, while in scope, replaces whatever
10            theAllocator was with TestAllocator.
11          */
12         auto theTestAllocator() {
13             static struct Context {
14                 import std.experimental.allocator: theAllocator;
15 
16                 TestAllocator testAllocator;
17                 typeof(theAllocator) oldAllocator;
18 
19                 static auto create() {
20                     import std.experimental.allocator: allocatorObject;
21 
22                     Context ctx;
23 
24                     ctx.oldAllocator = theAllocator;
25                     theAllocator = allocatorObject(ctx.testAllocator);
26 
27                     return ctx;
28                 }
29 
30                 ~this() {
31                     import std.experimental.allocator: dispose;
32 
33                     // 2.079.0 changed the API - we check here
34                     static if(__traits(compiles, testAllocator.dispose(theAllocator)))
35                         testAllocator.dispose(theAllocator);
36 
37                     theAllocator = oldAllocator;
38                 }
39             }
40 
41             return Context.create;
42         }
43 
44         @Setup
45         void before() {
46         }
47 
48         @Shutdown
49         void after() {
50             reset;
51         }
52 
53         void reset() {
54             Struct.numStructs = 0;
55             Class.numClasses = 0;
56             SharedStruct.numStructs = 0;
57             NoGcStruct.numStructs = 0;
58         }
59 
60 
61         void _writelnUt(T...)(T args) {
62             try {
63                 () @trusted { writelnUt(args); }();
64             } catch(Exception ex) {
65                 assert(false);
66             }
67         }
68 
69         private struct Struct {
70             int i;
71             static int numStructs = 0;
72 
73             this(int i) @safe nothrow {
74                 this.i = i;
75 
76                 ++numStructs;
77                 _writelnUt("Struct ", &this, " normal   ctor, i=", i, ", N=", numStructs);
78             }
79 
80             this(this) @safe nothrow {
81                 ++numStructs;
82                 _writelnUt("Struct ", &this, " postBlit ctor, i=", i, ", N=", numStructs);
83             }
84 
85             ~this() @safe nothrow const {
86                 --numStructs;
87                 _writelnUt("Struct ", &this, "          dtor, i=", i, ", N=", numStructs);
88             }
89 
90             int twice() @safe pure const nothrow {
91                 return i * 2;
92             }
93         }
94 
95         private struct SharedStruct {
96             int i;
97             static int numStructs = 0;
98 
99             this(int i) @safe nothrow shared {
100                 this.i = i;
101 
102                 ++numStructs;
103                 try () @trusted {
104                         _writelnUt("Struct normal ctor ", &this, ", i=", i, ", N=", numStructs);
105                     }();
106                 catch(Exception ex) {}
107             }
108 
109             this(this) @safe nothrow shared {
110                 ++numStructs;
111                 try () @trusted {
112                         _writelnUt("Struct postBlit ctor ", &this, ", i=", i, ", N=", numStructs);
113                     }();
114                 catch(Exception ex) {}
115             }
116 
117             ~this() @safe nothrow {
118                 --numStructs;
119                 try () @trusted { _writelnUt("Struct dtor ", &this, ", i=", i, ", N=", numStructs); }();
120                 catch(Exception ex) {}
121             }
122 
123             int twice() @safe pure const nothrow shared {
124                 return i * 2;
125             }
126         }
127 
128         private class Class {
129             int i;
130             static int numClasses = 0;
131 
132             this(int i) @safe nothrow {
133                 this.i = i;
134                 ++numClasses;
135             }
136 
137             ~this() @safe nothrow {
138                 --numClasses;
139             }
140 
141             int twice() @safe pure const nothrow {
142                 return i * 2;
143             }
144         }
145 
146         private struct SafeAllocator {
147 
148             import std.experimental.allocator.mallocator: Mallocator;
149 
150             void[] allocate(this T)(size_t i) @trusted nothrow @nogc {
151                 return Mallocator.instance.allocate(i);
152             }
153 
154             void deallocate(this T)(void[] bytes) @trusted nothrow @nogc {
155                 Mallocator.instance.deallocate(bytes);
156             }
157         }
158 
159         private struct NoGcStruct {
160             int i;
161 
162             static int numStructs = 0;
163 
164             this(int i) @safe @nogc nothrow {
165                 this.i = i;
166 
167                 ++numStructs;
168             }
169 
170             this(this) @safe @nogc nothrow {
171                 ++numStructs;
172             }
173 
174             ~this() @safe @nogc nothrow {
175                 --numStructs;
176             }
177 
178         }
179 
180         private class NoGcClass {
181             int i;
182             static int numClasses = 0;
183 
184             this(int i) @safe @nogc nothrow {
185                 this.i = i;
186                 ++numClasses;
187             }
188 
189             ~this() @safe @nogc nothrow {
190                 --numClasses;
191             }
192         }
193     }
194 }