1 module ut.conv.from;
2 
3 import test;
4 import xlld.conv.to: toXlOper;
5 import xlld.conv.from;
6 
7 
8 @("fromXlOper!double")
9 @system unittest {
10     import xlld.sdk.framework: freeXLOper;
11 
12     TestAllocator allocator;
13     auto num = 4.0;
14     auto oper = num.toXlOper(allocator);
15     auto back = oper.fromXlOper!double(allocator);
16     back.shouldEqual(num);
17 
18     freeXLOper(&oper, allocator);
19 }
20 
21 
22 ///
23 @("isNan for fromXlOper!double")
24 @system unittest {
25     import std.math: isNaN;
26     import xlld.memorymanager: allocator;
27     XLOPER12 oper;
28     oper.xltype = XlType.xltypeMissing;
29     fromXlOper!double(&oper, allocator).isNaN.shouldBeTrue;
30 }
31 
32 
33 @("fromXlOper!double wrong oper type")
34 @system unittest {
35     "foo".toXlOper(theGC).fromXlOper!double(theGC).shouldThrowWithMessage("Wrong type for fromXlOper!double");
36 }
37 
38 
39 ///
40 @("fromXlOper!int")
41 @system unittest {
42     42.toXlOper(theGC).fromXlOper!int(theGC).shouldEqual(42);
43 }
44 
45 ///
46 @("fromXlOper!int when given xltypeNum")
47 @system unittest {
48     42.0.toXlOper(theGC).fromXlOper!int(theGC).shouldEqual(42);
49 }
50 
51 ///
52 @("0 for fromXlOper!int missing oper")
53 @system unittest {
54     XLOPER12 oper;
55     oper.xltype = XlType.xltypeMissing;
56     oper.fromXlOper!int(theGC).shouldEqual(0);
57 }
58 
59 @("fromXlOper!int wrong oper type")
60 @system unittest {
61     "foo".toXlOper(theGC).fromXlOper!int(theGC).shouldThrowWithMessage("Wrong type for fromXlOper!int");
62 }
63 
64 ///
65 @("fromXlOper!string missing")
66 @system unittest {
67     import xlld.memorymanager: allocator;
68     XLOPER12 oper;
69     oper.xltype = XlType.xltypeMissing;
70     fromXlOper!string(&oper, allocator).shouldBeNull;
71 }
72 
73 ///
74 @("fromXlOper!string")
75 @system unittest {
76     import std.experimental.allocator: dispose;
77     import xlld.sdk.framework: freeXLOper;
78 
79     TestAllocator allocator;
80     auto oper = "foo".toXlOper(allocator);
81     auto str = fromXlOper!string(&oper, allocator);
82     allocator.numAllocations.shouldEqual(2);
83 
84     freeXLOper(&oper, allocator);
85     str.shouldEqual("foo");
86     allocator.dispose(cast(void[])str);
87 }
88 
89 ///
90 @("fromXlOper!string unicode")
91 @system unittest {
92     auto oper = "é".toXlOper(theGC);
93     auto str = fromXlOper!string(&oper, theGC);
94     str.shouldEqual("é");
95 }
96 
97 @("fromXlOper!string allocation failure")
98 @system unittest {
99     auto allocator = FailingAllocator();
100     "foo".toXlOper(theGC).fromXlOper!string(allocator).shouldThrowWithMessage("Could not allocate memory for array of char");
101 }
102 
103 
104 @("fromXlOper!string wrong oper type")
105 @system unittest {
106     42.toXlOper(theGC).fromXlOper!string(theGC).shouldThrowWithMessage("Wrong type for fromXlOper!string");
107 }
108 
109 ///
110 @("fromXlOper any double")
111 @system unittest {
112     any(5.0, theGC).fromXlOper!Any(theGC).shouldEqual(any(5.0, theGC));
113 }
114 
115 ///
116 @("fromXlOper any string")
117 @system unittest {
118     any("foo", theGC).fromXlOper!Any(theGC)._impl
119         .fromXlOper!string(theGC).shouldEqual("foo");
120 }
121 
122 ///
123 @("fromXlOper!string[][]")
124 unittest {
125     import xlld.memorymanager: allocator;
126     import xlld.sdk.framework: freeXLOper;
127 
128     auto strings = [["foo", "bar", "baz"], ["toto", "titi", "quux"]];
129     auto oper = strings.toXlOper(allocator);
130     scope(exit) freeXLOper(&oper, allocator);
131     oper.fromXlOper!(string[][])(allocator).shouldEqual(strings);
132 }
133 
134 ///
135 @("fromXlOper!double[][]")
136 unittest {
137     import xlld.memorymanager: allocator;
138     import xlld.sdk.framework: freeXLOper;
139 
140     auto doubles = [[1.0, 2.0], [3.0, 4.0]];
141     auto oper = doubles.toXlOper(allocator);
142     scope(exit) freeXLOper(&oper, allocator);
143     oper.fromXlOper!(double[][])(allocator).shouldEqual(doubles);
144 }
145 
146 ///
147 @("fromXlOper!string[][] TestAllocator")
148 unittest {
149     import std.experimental.allocator: disposeMultidimensionalArray;
150     import xlld.sdk.framework: freeXLOper;
151 
152     TestAllocator allocator;
153     auto strings = [["foo", "bar", "baz"], ["toto", "titi", "quux"]];
154     auto oper = strings.toXlOper(allocator);
155     auto backAgain = oper.fromXlOper!(string[][])(allocator);
156 
157     allocator.numAllocations.shouldEqual(16);
158 
159     freeXLOper(&oper, allocator);
160     backAgain.shouldEqual(strings);
161     allocator.disposeMultidimensionalArray(cast(void[][][])backAgain);
162 }
163 
164 ///
165 @("fromXlOper!string[][] when not all opers are strings")
166 unittest {
167     import xlld.conv.misc: multi;
168     import std.experimental.allocator.mallocator: Mallocator;
169     alias allocator = theGC;
170 
171     const rows = 2;
172     const cols = 3;
173     auto array = multi(rows, cols, allocator);
174     auto opers = array.val.array.lparray[0 .. rows*cols];
175     const strings = ["foo", "bar", "baz"];
176     const numbers = [1.0, 2.0, 3.0];
177 
178     int i;
179     foreach(r; 0 .. rows) {
180         foreach(c; 0 .. cols) {
181             if(r == 0)
182                 opers[i++] = strings[c].toXlOper(allocator);
183             else
184                 opers[i++] = numbers[c].toXlOper(allocator);
185         }
186     }
187 
188     opers[3].fromXlOper!string(allocator).shouldEqual("1.000000");
189     // sanity checks
190     opers[0].fromXlOper!string(allocator).shouldEqual("foo");
191     opers[3].fromXlOper!double(allocator).shouldEqual(1.0);
192     // the actual assertion
193     array.fromXlOper!(string[][])(allocator).shouldEqual([["foo", "bar", "baz"],
194                                                           ["1.000000", "2.000000", "3.000000"]]);
195 }
196 
197 
198 ///
199 @("fromXlOper!double[][] TestAllocator")
200 unittest {
201     import xlld.sdk.framework: freeXLOper;
202     import std.experimental.allocator: disposeMultidimensionalArray;
203 
204     TestAllocator allocator;
205     auto doubles = [[1.0, 2.0], [3.0, 4.0]];
206     auto oper = doubles.toXlOper(allocator);
207     auto backAgain = oper.fromXlOper!(double[][])(allocator);
208 
209     allocator.numAllocations.shouldEqual(4);
210 
211     freeXLOper(&oper, allocator);
212     backAgain.shouldEqual(doubles);
213     allocator.disposeMultidimensionalArray(backAgain);
214 }
215 
216 ///
217 @("fromXlOper!string[]")
218 unittest {
219     import xlld.memorymanager: allocator;
220     import xlld.sdk.framework: freeXLOper;
221 
222     auto strings = ["foo", "bar", "baz", "toto", "titi", "quux"];
223     auto oper = strings.toXlOper(allocator);
224     scope(exit) freeXLOper(&oper, allocator);
225     oper.fromXlOper!(string[])(allocator).shouldEqual(strings);
226 }
227 
228 ///
229 @("fromXlOper!double[] from row")
230 unittest {
231     import xlld.sdk.xlcall: xlfCaller;
232 
233     XLOPER12 caller;
234     caller.xltype = XlType.xltypeSRef;
235     caller.val.sref.ref_.rwFirst = 1;
236     caller.val.sref.ref_.rwLast = 1;
237     caller.val.sref.ref_.colFirst = 2;
238     caller.val.sref.ref_.colLast = 4;
239 
240     with(MockXlFunction(xlfCaller, caller)) {
241         auto doubles = [1.0, 2.0, 3.0, 4.0];
242         auto oper = doubles.toXlOper(theGC);
243         oper.shouldEqualDlang(doubles);
244     }
245 }
246 
247 ///
248 @("fromXlOper!double[]")
249 unittest {
250     auto doubles = [1.0, 2.0, 3.0, 4.0];
251     doubles.toXlOper(theGC).fromXlOper!(double[])(theGC).shouldEqual(doubles);
252 }
253 
254 @("fromXlOper!int[]")
255 unittest {
256     auto ints = [1, 2, 3, 4];
257     ints.toXlOper(theGC).fromXlOper!(int[])(theGC).shouldEqual(ints);
258 }
259 
260 
261 ///
262 @("fromXlOper!string[] TestAllocator")
263 unittest {
264     import std.experimental.allocator: disposeMultidimensionalArray;
265     import xlld.sdk.framework: freeXLOper;
266 
267     TestAllocator allocator;
268     auto strings = ["foo", "bar", "baz", "toto", "titi", "quux"];
269     auto oper = strings.toXlOper(allocator);
270     auto backAgain = oper.fromXlOper!(string[])(allocator);
271 
272     allocator.numAllocations.shouldEqual(14);
273 
274     backAgain.shouldEqual(strings);
275     freeXLOper(&oper, allocator);
276     allocator.disposeMultidimensionalArray(cast(void[][])backAgain);
277 }
278 
279 ///
280 @("fromXlOper!double[] TestAllocator")
281 unittest {
282     import std.experimental.allocator: dispose;
283     import xlld.sdk.framework: freeXLOper;
284 
285     TestAllocator allocator;
286     auto doubles = [1.0, 2.0, 3.0, 4.0];
287     auto oper = doubles.toXlOper(allocator);
288     auto backAgain = oper.fromXlOper!(double[])(allocator);
289 
290     allocator.numAllocations.shouldEqual(2);
291 
292     backAgain.shouldEqual(doubles);
293     freeXLOper(&oper, allocator);
294     allocator.dispose(backAgain);
295 }
296 
297 @("fromXlOper!double[][] nil")
298 @system unittest {
299     XLOPER12 oper;
300     oper.xltype = XlType.xltypeNil;
301     double[][] empty;
302     oper.fromXlOper!(double[][])(theGC).shouldEqual(empty);
303 }
304 
305 
306 @("fromXlOper any 1D array")
307 @system unittest {
308     import xlld.memorymanager: allocatorContext;
309     with(allocatorContext(theGC)) {
310         auto array = [any(1.0), any("foo")];
311         auto oper = toXlOper(array);
312         auto back = fromXlOper!(Any[])(oper);
313         back.shouldEqual(array);
314     }
315 }
316 
317 
318 ///
319 @("fromXlOper Any 2D array")
320 @system unittest {
321     import xlld.memorymanager: allocatorContext;
322     with(allocatorContext(theGC)) {
323         auto array = [[any(1.0), any(2.0)], [any("foo"), any("bar")]];
324         auto oper = toXlOper(array);
325         auto back = fromXlOper!(Any[][])(oper);
326         back.shouldEqual(array);
327     }
328 }
329 
330 ///
331 @("fromXlOper!DateTime")
332 @system unittest {
333     XLOPER12 oper;
334     auto mockDateTime = MockDateTime(2017, 12, 31, 1, 2, 3);
335 
336     const dateTime = oper.fromXlOper!DateTime(theGC);
337 
338     dateTime.year.shouldEqual(2017);
339     dateTime.month.shouldEqual(12);
340     dateTime.day.shouldEqual(31);
341     dateTime.hour.shouldEqual(1);
342     dateTime.minute.shouldEqual(2);
343     dateTime.second.shouldEqual(3);
344 }
345 
346 @("fromXlOper!DateTime wrong oper type")
347 @system unittest {
348     42.toXlOper(theGC).fromXlOper!DateTime(theGC).shouldThrowWithMessage(
349         "Wrong type for fromXlOper!DateTime");
350 }
351 
352 
353 @("fromXlOper!bool when bool")
354 @system unittest {
355     import xlld.sdk.xlcall: XLOPER12, XlType;
356     XLOPER12 oper;
357     oper.xltype = XlType.xltypeBool;
358     oper.val.bool_ = 1;
359     oper.fromXlOper!bool(theGC).shouldEqual(true);
360 
361     oper.val.bool_ = 0;
362     oper.fromXlOper!bool(theGC).shouldEqual(false);
363 
364     oper.val.bool_ = 2;
365     oper.fromXlOper!bool(theGC).shouldEqual(true);
366 }
367 
368 @("fromXlOper!bool when int")
369 @system unittest {
370     42.toXlOper(theGC).fromXlOper!bool(theGC).shouldEqual(true);
371     0.toXlOper(theGC).fromXlOper!bool(theGC).shouldEqual(false);
372 }
373 
374 @("fromXlOper!bool when double")
375 @system unittest {
376     33.3.toXlOper(theGC).fromXlOper!bool(theGC).shouldEqual(true);
377     0.0.toXlOper(theGC).fromXlOper!bool(theGC).shouldEqual(false);
378 }
379 
380 
381 @("fromXlOper!bool when string")
382 @system unittest {
383     "true".toXlOper(theGC).fromXlOper!bool(theGC).shouldEqual(true);
384     "True".toXlOper(theGC).fromXlOper!bool(theGC).shouldEqual(true);
385     "TRUE".toXlOper(theGC).fromXlOper!bool(theGC).shouldEqual(true);
386     "false".toXlOper(theGC).fromXlOper!bool(theGC).shouldEqual(false);
387 }
388 
389 @("fromXlOper!enum")
390 @system unittest {
391     enum Enum {
392         foo, bar, baz,
393     }
394 
395     "bar".toXlOper(theGC).fromXlOper!Enum(theGC).shouldEqual(Enum.bar);
396     "quux".toXlOper(theGC).fromXlOper!Enum(theGC).shouldThrowWithMessage("Enum does not have a member named 'quux'");
397 }
398 
399 @("fromXlOper!enum wrong type")
400 @system unittest {
401     enum Enum { foo, bar, baz, }
402 
403     42.toXlOper(theGC).fromXlOper!Enum(theGC).shouldThrowWithMessage(
404         "Wrong type for fromXlOper!Enum");
405 }
406 
407 
408 @("1D array to struct")
409 @system unittest {
410     static struct Foo { int x, y; }
411     [2, 3].toXlOper(theGC).fromXlOper!Foo(theGC).shouldEqual(Foo(2, 3));
412 }
413 
414 @("wrong oper type to struct")
415 @system unittest {
416     static struct Foo { int x, y; }
417 
418     2.toXlOper(theGC).fromXlOper!Foo(theGC).shouldThrowWithMessage(
419         "Can only convert arrays to structs. Must be either 1xN, Nx1, 2xN or Nx2");
420 }
421 
422 @("1D array to struct with wrong length")
423 @system unittest {
424 
425     static struct Foo { int x, y; }
426 
427     [2, 3, 4].toXlOper(theGC).fromXlOper!Foo(theGC).shouldThrowWithMessage(
428         "1D array length must match number of members in Foo. Expected 2, got 3");
429 
430     [2].toXlOper(theGC).fromXlOper!Foo(theGC).shouldThrowWithMessage(
431         "1D array length must match number of members in Foo. Expected 2, got 1");
432 }
433 
434 @("1D array to struct with wrong type")
435 @system unittest {
436     static struct Foo { int x, y; }
437 
438     ["foo", "bar"].toXlOper(theGC).fromXlOper!Foo(theGC).shouldThrowWithMessage(
439         "Wrong type converting oper to Foo");
440 }
441 
442 @("2D horizontal array to struct")
443 unittest {
444     import xlld.memorymanager: allocatorContext;
445 
446     static struct Foo { int x, y, z; }
447 
448     with(allocatorContext(theGC)) {
449         [[any("x"), any("y"), any("z")], [any(2), any(3), any(4)]].toFrom!Foo.shouldEqual(Foo(2, 3, 4));
450     }
451 }
452 
453 @("2D vertical array to struct")
454 unittest {
455     import xlld.memorymanager: allocatorContext;
456 
457     static struct Foo { int x, y, z; }
458 
459     with(allocatorContext(theGC)) {
460         [[any("x"), any(2)], [any("y"), any(3)], [any("z"), any(4)]].toFrom!Foo.shouldEqual(Foo(2, 3, 4));
461     }
462 }
463 
464 @("2D array wrong size")
465 unittest {
466     import xlld.memorymanager: allocatorContext;
467 
468     static struct Foo { int x, y, z; }
469 
470     with(allocatorContext(theGC)) {
471         [[any("x"), any(2)], [any("y"), any(3)], [any("z"), any(4)], [any("w"), any(5)]].toFrom!Foo.
472             shouldThrowWithMessage("2D array must be 2x3 or 3x2 for Foo");
473     }
474 
475 }
476 
477 ///
478 @("fromXlOperCoerce")
479 unittest {
480     double[][] doubles = [[1, 2, 3, 4], [11, 12, 13, 14]];
481     auto doublesOper = toSRef(doubles, theGC);
482     doublesOper.fromXlOper!(double[][])(theGC).shouldThrowWithMessage(
483         "fromXlOper: oper not of multi type");
484     doublesOper.fromXlOperCoerce!(double[][]).shouldEqual(doubles);
485 }
486 
487 
488 private auto toFrom(R, T)(T val) {
489     import std.experimental.allocator.gc_allocator: GCAllocator;
490     return val.toXlOper(GCAllocator.instance).fromXlOper!R(GCAllocator.instance);
491 }
492 
493 
494 @("fromXlOper!(Tuple!(double, double))")
495 @system unittest {
496     import std.typecons: tuple, Tuple;
497     import xlld.conv.from: fromXlOper;
498     tuple(22.2, 33.3)
499         .toXlOper(theGC)
500         .fromXlOper!(Tuple!(double, double))(theGC)
501         .shouldEqual(tuple(22.2, 33.3));
502 }
503 
504 @("fromXlOper!(Tuple!(int, int, int))")
505 @system unittest {
506     import std.typecons: tuple, Tuple;
507     import xlld.conv.from: fromXlOper;
508     tuple(1, 2, 3)
509         .toXlOper(theGC)
510         .fromXlOper!(Tuple!(int, int, int))(theGC)
511         .shouldEqual(tuple(1, 2, 3));
512 }