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 }