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