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 }