1 /**
2    Tests for converting from D types to XLOPER12
3  */
4 module ut.conv.to;
5 
6 import test;
7 import xlld.conv.to;
8 
9 
10 ///
11 @("int")
12 unittest {
13     auto oper = 42.toXlOper(theGC);
14     oper.xltype.shouldEqual(XlType.xltypeInt);
15     oper.val.w.shouldEqual(42);
16 }
17 
18 
19 ///
20 @("double")
21 unittest {
22     auto oper = (42.0).toXlOper(theGC);
23     oper.xltype.shouldEqual(XlType.xltypeNum);
24     oper.val.num.shouldEqual(42.0);
25 }
26 
27 ///
28 @("string.utf8")
29 @system unittest {
30     import xlld.memorymanager: allocator;
31     import xlld.sdk.framework: freeXLOper;
32     import std.conv: to;
33 
34     const str = "foo";
35     auto oper = str.toXlOper(allocator);
36     scope(exit) freeXLOper(&oper, allocator);
37 
38     oper.xltype.shouldEqual(XlType.xltypeStr);
39     (cast(int)oper.val.str[0]).shouldEqual(str.length);
40     (cast(wchar*)oper.val.str)[1 .. str.length + 1].to!string.shouldEqual(str);
41 }
42 
43 
44 ///
45 @("string.utf16")
46 @system unittest {
47     import xlld.memorymanager: allocator;
48     import xlld.sdk.framework: freeXLOper;
49 
50     const str = "foo"w;
51     auto oper = str.toXlOper(allocator);
52     scope(exit) freeXLOper(&oper, allocator);
53 
54     oper.xltype.shouldEqual(XlType.xltypeStr);
55     (cast(int)oper.val.str[0]).shouldEqual(str.length);
56     (cast(wchar*)oper.val.str)[1 .. str.length + 1].shouldEqual(str);
57 }
58 
59 ///
60 @("string.TestAllocator")
61 @system unittest {
62     import xlld.sdk.framework: freeXLOper;
63 
64     auto allocator = TestAllocator();
65     auto oper = "foo".toXlOper(allocator);
66     allocator.numAllocations.shouldEqual(1);
67     freeXLOper(&oper, allocator);
68 }
69 
70 ///
71 @("string.unicode")
72 @system unittest {
73     import std.utf: byWchar;
74     import std.array: array;
75 
76     "é".byWchar.array.length.shouldEqual(1);
77     "é"w.byWchar.array.length.shouldEqual(1);
78 
79     auto oper = "é".toXlOper(theGC);
80     const ushort length = oper.val.str[0];
81     length.shouldEqual("é"w.length);
82 }
83 
84 @("string.allocator.fail")
85 @safe unittest {
86     import xlld.conv.misc: dup;
87     auto allocator = FailingAllocator();
88     "foo".toXlOper(theGC).dup(allocator).shouldThrowWithMessage("Failed to allocate memory in dup");
89 }
90 
91 
92 ///
93 @("array.string.2d")
94 @system unittest {
95     import xlld.memorymanager: allocator;
96     import xlld.sdk.framework: freeXLOper;
97 
98     auto oper = [["foo", "bar", "baz"], ["toto", "titi", "quux"]].toXlOper(allocator);
99     scope(exit) freeXLOper(&oper, allocator);
100 
101     oper.xltype.shouldEqual(XlType.xltypeMulti);
102     oper.val.array.rows.shouldEqual(2);
103     oper.val.array.columns.shouldEqual(3);
104     auto opers = oper.val.array.lparray[0 .. oper.val.array.rows * oper.val.array.columns];
105 
106     opers[0].shouldEqualDlang("foo");
107     opers[3].shouldEqualDlang("toto");
108     opers[5].shouldEqualDlang("quux");
109 }
110 
111 ///
112 @("array.string.2d.TestAllocator")
113 @system unittest {
114     import xlld.sdk.framework: freeXLOper;
115 
116     TestAllocator allocator;
117     auto oper = [["foo", "bar", "baz"], ["toto", "titi", "quux"]].toXlOper(allocator);
118     allocator.numAllocations.shouldEqual(7);
119     freeXLOper(&oper, allocator);
120 }
121 
122 ///
123 @("array.double.2d")
124 @system unittest {
125     import xlld.sdk.framework: freeXLOper;
126 
127     TestAllocator allocator;
128     auto oper = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]].toXlOper(allocator);
129     allocator.numAllocations.shouldEqual(1);
130     freeXLOper(&oper, allocator);
131 }
132 
133 @("array.double.2d.allocator.fail")
134 @system unittest {
135     auto allocator = FailingAllocator();
136     [33.3].toXlOper(allocator).shouldThrowWithMessage("Failed to allocate memory for multi oper");
137 }
138 
139 @("array.double.2d.wrong shape")
140 @system unittest {
141     [[33.3], [1.0, 2.0]].toXlOper(theGC).shouldThrowWithMessage("# of columns must all be the same and aren't");
142 }
143 
144 ///
145 @("array.string.1d")
146 @system unittest {
147     import xlld.sdk.framework: freeXLOper;
148 
149     TestAllocator allocator;
150     auto oper = ["foo", "bar", "baz", "toto", "titi", "quux"].toXlOper(allocator);
151     allocator.numAllocations.shouldEqual(7);
152     freeXLOper(&oper, allocator);
153 }
154 
155 ///
156 @("any.double")
157 unittest {
158     any(5.0, theGC).toXlOper(theGC).shouldEqualDlang(5.0);
159 }
160 
161 ///
162 @("any.string")
163 unittest {
164     any("foo", theGC).toXlOper(theGC).shouldEqualDlang("foo");
165 }
166 
167 ///
168 @("array.array.double.2d")
169 unittest {
170     any([[1.0, 2.0], [3.0, 4.0]], theGC)
171         .toXlOper(theGC).shouldEqualDlang([[1.0, 2.0], [3.0, 4.0]]);
172 }
173 
174 ///
175 @("any.array.string.2d")
176 unittest {
177     any([["foo", "bar"], ["quux", "toto"]], theGC)
178         .toXlOper(theGC).shouldEqualDlang([["foo", "bar"], ["quux", "toto"]]);
179 }
180 
181 
182 ///
183 @("any.array.1d.0")
184 unittest {
185     import xlld.memorymanager: allocatorContext;
186 
187     with(allocatorContext(theGC)) {
188         auto oper = toXlOper([any(42.0), any("foo")]);
189         oper.xltype.shouldEqual(XlType.xltypeMulti);
190         oper.val.array.lparray[0].shouldEqualDlang(42.0);
191         oper.val.array.lparray[1].shouldEqualDlang("foo");
192     }
193 }
194 
195 
196 ///
197 @("any.array.1d.1")
198 unittest {
199     const a = any([any(1.0, theGC), any("foo", theGC)],
200                   theGC);
201     auto oper = a.toXlOper(theGC);
202     oper.xltype.shouldEqual(XlType.xltypeMulti);
203 
204     const rows = oper.val.array.rows;
205     const cols = oper.val.array.columns;
206     auto opers = oper.val.array.lparray[0 .. rows * cols];
207     opers[0].shouldEqualDlang(1.0);
208     opers[1].shouldEqualDlang("foo");
209 }
210 
211 ///
212 @("any.array.2d.0")
213 unittest {
214     import xlld.memorymanager: allocatorContext;
215 
216     with(allocatorContext(theGC)) {
217         auto oper = toXlOper([[any(42.0), any("foo"), any("quux")], [any("bar"), any(7.0), any("toto")]]);
218         oper.xltype.shouldEqual(XlType.xltypeMulti);
219         oper.val.array.rows.shouldEqual(2);
220         oper.val.array.columns.shouldEqual(3);
221         oper.val.array.lparray[0].shouldEqualDlang(42.0);
222         oper.val.array.lparray[1].shouldEqualDlang("foo");
223         oper.val.array.lparray[2].shouldEqualDlang("quux");
224         oper.val.array.lparray[3].shouldEqualDlang("bar");
225         oper.val.array.lparray[4].shouldEqualDlang(7.0);
226         oper.val.array.lparray[5].shouldEqualDlang("toto");
227     }
228 }
229 
230 
231 ///
232 @("any.array.2d.1")
233 unittest {
234     const a = any([
235                      [any(1.0, theGC), any(2.0, theGC)],
236                      [any("foo", theGC), any("bar", theGC)]
237                  ],
238                  theGC);
239     auto oper = a.toXlOper(theGC);
240     oper.xltype.shouldEqual(XlType.xltypeMulti);
241 
242     const rows = oper.val.array.rows;
243     const cols = oper.val.array.columns;
244     auto opers = oper.val.array.lparray[0 .. rows * cols];
245     opers[0].shouldEqualDlang(1.0);
246     opers[1].shouldEqualDlang(2.0);
247     opers[2].shouldEqualDlang("foo");
248     opers[3].shouldEqualDlang("bar");
249 }
250 
251 @("DateTime")
252 @safe unittest {
253 
254     import xlld.sdk.xlcall: xlfDate, xlfTime;
255 
256     const dateTime = DateTime(2017, 12, 31, 1, 2, 3);
257     {
258         auto mockDate = MockXlFunction(xlfDate, 0.1.toXlOper(theGC));
259         auto mockTime = MockXlFunction(xlfTime, 0.2.toXlOper(theGC));
260 
261         auto oper = dateTime.toXlOper(theGC);
262 
263         oper.xltype.shouldEqual(XlType.xltypeNum);
264         oper.val.num.shouldApproxEqual(0.3);
265     }
266 
267     {
268         auto mockDate = MockXlFunction(xlfDate, 1.1.toXlOper(theGC));
269         auto mockTime = MockXlFunction(xlfTime, 1.2.toXlOper(theGC));
270 
271         auto oper = dateTime.toXlOper(theGC);
272 
273         oper.xltype.shouldEqual(XlType.xltypeNum);
274         oper.val.num.shouldApproxEqual(2.3);
275     }
276 }
277 
278 ///
279 @("bool")
280 @system unittest {
281     import xlld.sdk.xlcall: XlType;
282     {
283         const oper = true.toXlOper(theGC);
284         oper.xltype.shouldEqual(XlType.xltypeBool);
285         oper.val.bool_.shouldEqual(1);
286     }
287 
288     {
289         const oper = false.toXlOper(theGC);
290         oper.xltype.shouldEqual(XlType.xltypeBool);
291         oper.val.bool_.shouldEqual(0);
292     }
293 }
294 
295 @("enum")
296 @safe unittest {
297 
298     enum Enum {
299         foo,
300         bar,
301         baz,
302     }
303 
304     Enum.bar.toXlOper(theGC).shouldEqualDlang("bar");
305 }
306 
307 
308 @("struct")
309 @safe unittest {
310     static struct Foo { int x, y; }
311     Foo(2, 3).toXlOper(theGC).shouldEqualDlang("Foo(2, 3)");
312 }
313 
314 @("Tuple!(int, int)")
315 @safe unittest {
316     import std.typecons: tuple;
317     auto oper = tuple(42, 33).toXlOper(theGC);
318     oper.shouldEqualDlang([42, 33]);
319 }
320 
321 @("Tuple!(DateTime, double)[]")
322 @system unittest {
323     import xlld.conv.misc: stripMemoryBitmask;
324     import xlld.test.util: MockDates;
325     import xlld.conv.from: fromXlOper;
326     import std.typecons: tuple;
327     import std.conv: to;
328     import std.algorithm: map;
329 
330     auto dates = MockDates([0.1, 0.2, 0.3]);
331     auto times = MockTimes([0.1, 0.2, 0.3]);
332 
333     auto oper = [
334         tuple(DateTime(2017, 1, 1), 11.1),
335         tuple(DateTime(2018, 1, 1), 22.2),
336         tuple(DateTime(2019, 1, 1), 33.3),
337     ].toXlOper(theGC);
338 
339     void assertMulti(in XLOPER12 oper) {
340         if(oper.xltype.stripMemoryBitmask != XlType.xltypeMulti) {
341             if(oper.xltype.stripMemoryBitmask == XlType.xltypeStr)
342                 throw new Exception(oper.fromXlOper!string(theGC));
343             else
344                 throw new Exception("Oper not of multi type: " ~ to!string(oper));
345         }
346     }
347 
348 
349     assertMulti(oper);
350     oper.val.array.rows.shouldEqual(1);
351     oper.val.array.columns.shouldEqual(3);
352 
353     auto dateTimes = MockDateTimes(DateTime(2017, 1, 1), DateTime(2018, 1, 1), DateTime(2019, 1, 1));
354 
355     auto elts = oper.val.array.lparray[0 .. 3];
356     foreach(elt; elts) assertMulti(elt);
357 
358     elts[0].val.array.lparray[0].fromXlOper!DateTime(theGC).shouldEqual(DateTime(2017, 1, 1));
359     elts[0].val.array.lparray[1].fromXlOper!double(theGC).shouldEqual(11.1);
360 
361     elts[1].val.array.lparray[0].fromXlOper!DateTime(theGC).shouldEqual(DateTime(2018, 1, 1));
362     elts[1].val.array.lparray[1].fromXlOper!double(theGC).shouldEqual(22.2);
363 
364     elts[2].val.array.lparray[0].fromXlOper!DateTime(theGC).shouldEqual(DateTime(2019, 1, 1));
365     elts[2].val.array.lparray[1].fromXlOper!double(theGC).shouldEqual(33.3);
366 }
367 
368 @("struct.array")
369 @system unittest {
370     import test.d_funcs: DateAndString;
371     import std.datetime: DateTime;
372     auto oper = [DateAndString(DateTime(2017, 1, 2), "foobar")].toXlOper(theGC);
373 }
374 
375 
376 @("range.1d.int")
377 @system unittest {
378     import std.range: iota;
379     import std.experimental.allocator.mallocator: Mallocator;
380 
381     auto range = 5.iota;
382     auto oper = () @nogc { return range.toXlOper(Mallocator.instance); }();
383     oper.shouldEqualDlang([0, 1, 2, 3, 4]);
384 }
385 
386 
387 @("range.2d.int")
388 @system unittest {
389     import std.range: iota, enumerate, repeat, take;
390     import std.algorithm: map;
391     import std.experimental.allocator.mallocator: Mallocator;
392 
393     auto range = 3
394         .iota
395         .map!(i => i.repeat.take(2))
396         ;
397     auto oper = () @nogc { return range.toXlOper(Mallocator.instance); }();
398     oper.shouldEqualDlang([[0, 0], [1, 1], [2, 2]]);
399 }
400 
401 
402 @("const(char)[]")
403 @system unittest {
404     const(char)[] str = "foo";
405     str.toXlOper(theGC).shouldEqualDlang("foo");
406 }