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 }