1 module unit_threaded.ut.issues;
2 
3 import unit_threaded;
4 import unit_threaded.asserts;
5 
6 
7 interface ICalcView {
8    @property string total() @safe pure;
9    @property void total(string t) @safe pure;
10 }
11 
12 class CalcController {
13     private ICalcView view;
14 
15     this(ICalcView view) @safe pure {
16         this.view = view;
17     }
18 
19     void onClick(int number) @safe pure {
20         import std.conv: to;
21         view.total = number.to!string;
22     }
23 }
24 
25 
26 @("54")
27 @safe pure unittest {
28    auto m = mock!ICalcView;
29    m.expect!"total"("42");
30 
31    auto ctrl = new CalcController(m);
32    ctrl.onClick(42);
33 
34    m.verify;
35 }
36 
37 
38 @("82")
39 // @system because of Object member functions are @system
40 @system unittest {
41 
42     import std.exception: assertThrown;
43 
44     static class A {
45         string x;
46 
47         override string toString() @safe const {
48             return x;
49         }
50     }
51 
52     class B : A {}
53 
54     auto actual = new B;
55     auto expected = new B;
56 
57     actual.x = "foo";
58     expected.x = "bar";
59 
60     assertThrown(actual.shouldEqual(expected));
61 }
62 
63 
64 @("124")
65 @safe pure unittest {
66     static struct Array {
67 
68         alias opSlice this;
69 
70         private int[] ints;
71 
72         bool opCast(T)() const if(is(T == bool)) {
73             return ints.length != 0;
74         }
75 
76         inout(int)[] opSlice() @safe inout {
77             return ints;
78         }
79 
80         string toString() @safe pure const {
81             import std.conv: text;
82             return text(this);
83         }
84     }
85 
86 
87     static huh() @safe {
88         import std.conv: to;
89         return Array([1, 2, 3]).to!string;
90     }
91 
92     {
93         auto arr = Array([1, 2, 3]);
94         arr.shouldEqual([1, 2, 3]);
95     }
96 
97     {
98         const arr = Array([1, 2, 3]);
99         arr.shouldEqual([1, 2, 3]);
100     }
101 
102 }
103 
104 
105 @("138")
106 @safe unittest {
107     import std.exception: assertThrown;
108 
109     static class Class {
110         private string foo;
111         override bool opEquals(scope Object b) @safe @nogc pure nothrow scope const {
112             return foo == (cast(Class)b).foo;
113         }
114     }
115 
116     auto a = new Class;
117     auto b = new Class;
118 
119     a.foo = "1";
120     b.foo = "2";
121 
122     // Object.opEquals isn't scope and therefore not @safe
123     assertThrown(() @trusted { a.should == b; }());
124 }
125 
126 
127 @("146")
128 @safe unittest {
129     version(unitThreadedLight) {}
130     else {
131         assertExceptionMsg(shouldApproxEqual(42000.301, 42000.302, 1e-9),
132                            `    tests/unit_threaded/ut/issues.d:123 - Expected approx: 42000.302000` ~ "\n" ~
133                            `    tests/unit_threaded/ut/issues.d:123 -      Got       : 42000.301000`);
134     }
135 }
136 
137 
138 version(unitThreadedLight) {}
139 else {
140 
141     // should not compile for @safe
142     @("176.0")
143         @safe pure unittest {
144 
145         int* ptr;
146         bool func(int a) {
147             *(ptr + 256) = 42;
148             return a % 2 == 0;
149         }
150 
151         static assert(!__traits(compiles, check!func(100)));
152     }
153 
154     @("176.1")
155         @safe unittest {
156         import std.traits: isSafe;
157 
158         int* ptr;
159         bool func(int a) {
160             *(ptr + 256) = 42;
161             return a % 2 == 0;
162         }
163 
164         static assert(!isSafe!({ check!func(100); }));
165     }
166 }
167 
168 
169 @("182")
170 // not @safe or pure because the InputRange interface member functions aren't
171 @system unittest {
172     import std.range: inputRangeObject;
173     auto a = [1, 2, 3];
174     auto b = [1, 2, 3];
175     a.inputRangeObject.should == b;
176 }
177 
178 
179 @("184.0")
180 @safe pure unittest {
181 
182     import std.traits;
183 
184     auto obviouslySystem = {
185         int* foo = cast(int*) 42;
186         *foo = 42;
187     };
188 
189     static assert(!isSafe!(obviouslySystem));
190 
191     void oops()() {
192         shouldThrow(obviouslySystem);
193     }
194 
195     // oops;  // uncomment to ever check the compiler error message
196     static assert(!isSafe!(oops!()),
197                   "Passing @system functions to shouldThrow should not be @safe");
198 }
199 
200 
201 @("184.1")
202 @safe pure unittest {
203 
204     import std.traits: isUnsafe;
205 
206     auto obviouslySystem = {
207         int* foo = cast(int*) 42;
208         *foo = 42;
209     };
210 
211     static assert(isUnsafe!(obviouslySystem));
212 
213     void oops()() {
214         shouldThrowExactly!Exception(obviouslySystem);
215     }
216 
217     // oops;  // uncomment to ever check the compiler error message
218     static assert(isUnsafe!(oops!()),
219                   "Passing @system functions to shouldThrowExactly should not be @safe");
220 }
221 
222 
223 @("185")
224 @safe pure unittest {
225     static struct S {
226 
227         int i;
228 
229         bool opEquals(T...)(T whatever) /* not const */ {
230             return true;
231         }
232     }
233 
234     S(42).should == S(33);
235 }
236 
237 
238 version(unitThreadedLight) {}
239 else {
240     @("186")
241     @safe pure unittest {
242 
243         import std.traits: isUnsafe;
244 
245         static struct Key {
246 
247             int val;
248 
249             string toString () const @system {
250                 int* ptr = cast(int*) 42;
251                 *ptr = 42;
252                 return "Oops";
253             }
254         }
255 
256         Key a = Key(42);
257         Key b = Key(84);
258 
259         void impl()() {
260             a.should == b;
261         }
262 
263         // unsafe due to unsafe toString
264         static assert(isUnsafe!(impl!()));
265     }
266 }
267 
268 
269 @("shouldEqual.enum.text")
270 @safe pure unittest {
271     static enum Enum {
272         text,
273     }
274 
275     Enum.init.should == Enum.init;
276 }
277 
278 
279 @("212.0")
280 // not pure because of float comparison
281 @safe unittest {
282     float[] lhs  = [2f, 4, 6, 8, 10, 12];
283     float[6] rhs = [2f, 4, 6, 8, 10, 12];
284 
285     lhs.should == rhs;
286     rhs.should == lhs;
287 }
288 
289 
290 @("212.1")
291 @safe pure unittest {
292     int[] lhs  = [2, 4, 6, 8, 10, 12];
293     int[6] rhs = [2, 4, 6, 8, 10, 12];
294 
295     lhs.should == rhs;
296     rhs.should == lhs;
297 }