1 /** 2 Tests for converting from XLOPER12 to D types. 3 */ 4 module ut.conv.from; 5 6 import test; 7 import xlld.conv.to: toXlOper; 8 import xlld.conv.from; 9 10 11 @("fromXlOper!double") 12 @system unittest { 13 import xlld.sdk.framework: freeXLOper; 14 15 TestAllocator allocator; 16 auto num = 4.0; 17 auto oper = num.toXlOper(allocator); 18 auto back = oper.fromXlOper!double(allocator); 19 back.shouldEqual(num); 20 21 freeXLOper(&oper, allocator); 22 } 23 24 25 /// 26 @("isNan for fromXlOper!double") 27 @system unittest { 28 import std.math: isNaN; 29 import xlld.memorymanager: allocator; 30 XLOPER12 oper; 31 oper.xltype = XlType.xltypeMissing; 32 fromXlOper!double(&oper, allocator).isNaN.shouldBeTrue; 33 } 34 35 36 @("fromXlOper!double wrong oper type") 37 @system unittest { 38 "foo".toXlOper(theGC).fromXlOper!double(theGC).shouldThrowWithMessage("Wrong type for fromXlOper!double"); 39 } 40 41 42 /// 43 @("fromXlOper!int") 44 @system unittest { 45 42.toXlOper(theGC).fromXlOper!int(theGC).shouldEqual(42); 46 } 47 48 /// 49 @("fromXlOper!int when given xltypeNum") 50 @system unittest { 51 42.0.toXlOper(theGC).fromXlOper!int(theGC).shouldEqual(42); 52 } 53 54 /// 55 @("0 for fromXlOper!int missing oper") 56 @system unittest { 57 XLOPER12 oper; 58 oper.xltype = XlType.xltypeMissing; 59 oper.fromXlOper!int(theGC).shouldEqual(0); 60 } 61 62 @("fromXlOper!int wrong oper type") 63 @system unittest { 64 "foo".toXlOper(theGC).fromXlOper!int(theGC).shouldThrowWithMessage("Wrong type for fromXlOper!int"); 65 } 66 67 /// 68 @("fromXlOper!string missing") 69 @system unittest { 70 import xlld.memorymanager: allocator; 71 XLOPER12 oper; 72 oper.xltype = XlType.xltypeMissing; 73 fromXlOper!string(&oper, allocator).shouldBeNull; 74 } 75 76 /// 77 @("fromXlOper!string") 78 @system unittest { 79 import std.experimental.allocator: dispose; 80 import xlld.sdk.framework: freeXLOper; 81 82 TestAllocator allocator; 83 auto oper = "foo".toXlOper(allocator); 84 auto str = fromXlOper!string(&oper, allocator); 85 allocator.numAllocations.shouldEqual(2); 86 87 freeXLOper(&oper, allocator); 88 str.shouldEqual("foo"); 89 allocator.dispose(cast(void[])str); 90 } 91 92 /// 93 @("fromXlOper!string unicode") 94 @system unittest { 95 auto oper = "é".toXlOper(theGC); 96 auto str = fromXlOper!string(&oper, theGC); 97 str.shouldEqual("é"); 98 } 99 100 @("fromXlOper!string allocation failure") 101 @system unittest { 102 auto allocator = FailingAllocator(); 103 "foo".toXlOper(theGC).fromXlOper!string(allocator).shouldThrowWithMessage("Could not allocate memory for array of char"); 104 } 105 106 107 @("fromXlOper!string wrong oper type") 108 @system unittest { 109 42.toXlOper(theGC).fromXlOper!string(theGC).shouldThrowWithMessage("Wrong type for fromXlOper!string"); 110 } 111 112 /// 113 @("fromXlOper any double") 114 @system unittest { 115 any(5.0, theGC).fromXlOper!Any(theGC).shouldEqual(any(5.0, theGC)); 116 } 117 118 /// 119 @("fromXlOper any string") 120 @system unittest { 121 any("foo", theGC).fromXlOper!Any(theGC)._impl 122 .fromXlOper!string(theGC).shouldEqual("foo"); 123 } 124 125 /// 126 @("fromXlOper!string[][]") 127 unittest { 128 import xlld.memorymanager: allocator; 129 import xlld.sdk.framework: freeXLOper; 130 131 auto strings = [["foo", "bar", "baz"], ["toto", "titi", "quux"]]; 132 auto oper = strings.toXlOper(allocator); 133 scope(exit) freeXLOper(&oper, allocator); 134 oper.fromXlOper!(string[][])(allocator).shouldEqual(strings); 135 } 136 137 /// 138 @("fromXlOper!double[][]") 139 unittest { 140 import xlld.memorymanager: allocator; 141 import xlld.sdk.framework: freeXLOper; 142 143 auto doubles = [[1.0, 2.0], [3.0, 4.0]]; 144 auto oper = doubles.toXlOper(allocator); 145 scope(exit) freeXLOper(&oper, allocator); 146 oper.fromXlOper!(double[][])(allocator).shouldEqual(doubles); 147 } 148 149 /// 150 @("fromXlOper!string[][] TestAllocator") 151 unittest { 152 import std.experimental.allocator: disposeMultidimensionalArray; 153 import xlld.sdk.framework: freeXLOper; 154 155 TestAllocator allocator; 156 auto strings = [["foo", "bar", "baz"], ["toto", "titi", "quux"]]; 157 auto oper = strings.toXlOper(allocator); 158 auto backAgain = oper.fromXlOper!(string[][])(allocator); 159 160 allocator.numAllocations.shouldEqual(16); 161 162 freeXLOper(&oper, allocator); 163 backAgain.shouldEqual(strings); 164 allocator.disposeMultidimensionalArray(cast(void[][][])backAgain); 165 } 166 167 /// 168 @("fromXlOper!string[][] when not all opers are strings") 169 unittest { 170 import xlld.conv.misc: multi; 171 import std.experimental.allocator.mallocator: Mallocator; 172 alias allocator = theGC; 173 174 const rows = 2; 175 const cols = 3; 176 auto array = multi(rows, cols, allocator); 177 auto opers = array.val.array.lparray[0 .. rows*cols]; 178 const strings = ["foo", "bar", "baz"]; 179 const numbers = [1.0, 2.0, 3.0]; 180 181 int i; 182 foreach(r; 0 .. rows) { 183 foreach(c; 0 .. cols) { 184 if(r == 0) 185 opers[i++] = strings[c].toXlOper(allocator); 186 else 187 opers[i++] = numbers[c].toXlOper(allocator); 188 } 189 } 190 191 opers[3].fromXlOper!string(allocator).shouldEqual("1.000000"); 192 // sanity checks 193 opers[0].fromXlOper!string(allocator).shouldEqual("foo"); 194 opers[3].fromXlOper!double(allocator).shouldEqual(1.0); 195 // the actual assertion 196 array.fromXlOper!(string[][])(allocator).shouldEqual([["foo", "bar", "baz"], 197 ["1.000000", "2.000000", "3.000000"]]); 198 } 199 200 201 /// 202 @("fromXlOper!double[][] TestAllocator") 203 unittest { 204 import xlld.sdk.framework: freeXLOper; 205 import std.experimental.allocator: disposeMultidimensionalArray; 206 207 TestAllocator allocator; 208 auto doubles = [[1.0, 2.0], [3.0, 4.0]]; 209 auto oper = doubles.toXlOper(allocator); 210 auto backAgain = oper.fromXlOper!(double[][])(allocator); 211 212 allocator.numAllocations.shouldEqual(4); 213 214 freeXLOper(&oper, allocator); 215 backAgain.shouldEqual(doubles); 216 allocator.disposeMultidimensionalArray(backAgain); 217 } 218 219 /// 220 @("fromXlOper!string[]") 221 unittest { 222 import xlld.memorymanager: allocator; 223 import xlld.sdk.framework: freeXLOper; 224 225 auto strings = ["foo", "bar", "baz", "toto", "titi", "quux"]; 226 auto oper = strings.toXlOper(allocator); 227 scope(exit) freeXLOper(&oper, allocator); 228 oper.fromXlOper!(string[])(allocator).shouldEqual(strings); 229 } 230 231 /// 232 @("fromXlOper!double[] from row") 233 unittest { 234 import xlld.sdk.xlcall: xlfCaller; 235 236 XLOPER12 caller; 237 caller.xltype = XlType.xltypeSRef; 238 caller.val.sref.ref_.rwFirst = 1; 239 caller.val.sref.ref_.rwLast = 1; 240 caller.val.sref.ref_.colFirst = 2; 241 caller.val.sref.ref_.colLast = 4; 242 243 with(MockXlFunction(xlfCaller, caller)) { 244 auto doubles = [1.0, 2.0, 3.0, 4.0]; 245 auto oper = doubles.toXlOper(theGC); 246 oper.shouldEqualDlang(doubles); 247 } 248 } 249 250 /// 251 @("fromXlOper!double[]") 252 unittest { 253 auto doubles = [1.0, 2.0, 3.0, 4.0]; 254 doubles.toXlOper(theGC).fromXlOper!(double[])(theGC).shouldEqual(doubles); 255 } 256 257 @("fromXlOper!int[]") 258 unittest { 259 auto ints = [1, 2, 3, 4]; 260 ints.toXlOper(theGC).fromXlOper!(int[])(theGC).shouldEqual(ints); 261 } 262 263 264 /// 265 @("fromXlOper!string[] TestAllocator") 266 unittest { 267 import std.experimental.allocator: disposeMultidimensionalArray; 268 import xlld.sdk.framework: freeXLOper; 269 270 TestAllocator allocator; 271 auto strings = ["foo", "bar", "baz", "toto", "titi", "quux"]; 272 auto oper = strings.toXlOper(allocator); 273 auto backAgain = oper.fromXlOper!(string[])(allocator); 274 275 allocator.numAllocations.shouldEqual(14); 276 277 backAgain.shouldEqual(strings); 278 freeXLOper(&oper, allocator); 279 allocator.disposeMultidimensionalArray(cast(void[][])backAgain); 280 } 281 282 /// 283 @("fromXlOper!double[] TestAllocator") 284 unittest { 285 import std.experimental.allocator: dispose; 286 import xlld.sdk.framework: freeXLOper; 287 288 TestAllocator allocator; 289 auto doubles = [1.0, 2.0, 3.0, 4.0]; 290 auto oper = doubles.toXlOper(allocator); 291 auto backAgain = oper.fromXlOper!(double[])(allocator); 292 293 allocator.numAllocations.shouldEqual(2); 294 295 backAgain.shouldEqual(doubles); 296 freeXLOper(&oper, allocator); 297 allocator.dispose(backAgain); 298 } 299 300 @("fromXlOper!double[][] nil") 301 @system unittest { 302 XLOPER12 oper; 303 oper.xltype = XlType.xltypeNil; 304 double[][] empty; 305 oper.fromXlOper!(double[][])(theGC).shouldEqual(empty); 306 } 307 308 309 @("fromXlOper any 1D array") 310 @system unittest { 311 import xlld.memorymanager: allocatorContext; 312 with(allocatorContext(theGC)) { 313 auto array = [any(1.0), any("foo")]; 314 auto oper = toXlOper(array); 315 auto back = fromXlOper!(Any[])(oper); 316 back.shouldEqual(array); 317 } 318 } 319 320 321 /// 322 @("fromXlOper Any 2D array") 323 @system unittest { 324 import xlld.memorymanager: allocatorContext; 325 with(allocatorContext(theGC)) { 326 auto array = [[any(1.0), any(2.0)], [any("foo"), any("bar")]]; 327 auto oper = toXlOper(array); 328 auto back = fromXlOper!(Any[][])(oper); 329 back.shouldEqual(array); 330 } 331 } 332 333 /// 334 @("fromXlOper!DateTime") 335 @system unittest { 336 XLOPER12 oper; 337 auto mockDateTime = MockDateTime(2017, 12, 31, 1, 2, 3); 338 339 const dateTime = oper.fromXlOper!DateTime(theGC); 340 341 dateTime.year.shouldEqual(2017); 342 dateTime.month.shouldEqual(12); 343 dateTime.day.shouldEqual(31); 344 dateTime.hour.shouldEqual(1); 345 dateTime.minute.shouldEqual(2); 346 dateTime.second.shouldEqual(3); 347 } 348 349 @("fromXlOper!DateTime wrong oper type") 350 @system unittest { 351 42.toXlOper(theGC).fromXlOper!DateTime(theGC).shouldThrowWithMessage( 352 "Wrong type for fromXlOper!DateTime"); 353 } 354 355 356 @("fromXlOper!bool when bool") 357 @system unittest { 358 import xlld.sdk.xlcall: XLOPER12, XlType; 359 XLOPER12 oper; 360 oper.xltype = XlType.xltypeBool; 361 oper.val.bool_ = 1; 362 oper.fromXlOper!bool(theGC).shouldEqual(true); 363 364 oper.val.bool_ = 0; 365 oper.fromXlOper!bool(theGC).shouldEqual(false); 366 367 oper.val.bool_ = 2; 368 oper.fromXlOper!bool(theGC).shouldEqual(true); 369 } 370 371 @("fromXlOper!bool when int") 372 @system unittest { 373 42.toXlOper(theGC).fromXlOper!bool(theGC).shouldEqual(true); 374 0.toXlOper(theGC).fromXlOper!bool(theGC).shouldEqual(false); 375 } 376 377 @("fromXlOper!bool when double") 378 @system unittest { 379 33.3.toXlOper(theGC).fromXlOper!bool(theGC).shouldEqual(true); 380 0.0.toXlOper(theGC).fromXlOper!bool(theGC).shouldEqual(false); 381 } 382 383 384 @("fromXlOper!bool when string") 385 @system unittest { 386 "true".toXlOper(theGC).fromXlOper!bool(theGC).shouldEqual(true); 387 "True".toXlOper(theGC).fromXlOper!bool(theGC).shouldEqual(true); 388 "TRUE".toXlOper(theGC).fromXlOper!bool(theGC).shouldEqual(true); 389 "false".toXlOper(theGC).fromXlOper!bool(theGC).shouldEqual(false); 390 } 391 392 @("fromXlOper!enum") 393 @system unittest { 394 enum Enum { 395 foo, bar, baz, 396 } 397 398 "bar".toXlOper(theGC).fromXlOper!Enum(theGC).shouldEqual(Enum.bar); 399 "quux".toXlOper(theGC).fromXlOper!Enum(theGC).shouldThrowWithMessage("Enum does not have a member named 'quux'"); 400 } 401 402 @("fromXlOper!enum wrong type") 403 @system unittest { 404 enum Enum { foo, bar, baz, } 405 406 42.toXlOper(theGC).fromXlOper!Enum(theGC).shouldThrowWithMessage( 407 "Wrong type for fromXlOper!Enum"); 408 } 409 410 411 @("1D array to struct") 412 @system unittest { 413 static struct Foo { int x, y; } 414 [2, 3].toXlOper(theGC).fromXlOper!Foo(theGC).shouldEqual(Foo(2, 3)); 415 } 416 417 @("wrong oper type to struct") 418 @system unittest { 419 static struct Foo { int x, y; } 420 421 2.toXlOper(theGC).fromXlOper!Foo(theGC).shouldThrowWithMessage( 422 "Can only convert arrays to structs. Must be either 1xN, Nx1, 2xN or Nx2"); 423 } 424 425 @("1D array to struct with wrong length") 426 @system unittest { 427 428 import nogc: NoGcException; 429 430 static struct Foo { int x, y; } 431 432 [2, 3, 4].toXlOper(theGC).fromXlOper!Foo(theGC).shouldThrowWithMessage!NoGcException( 433 "1D array length must match number of members in Foo. Expected 2, got 3"); 434 435 [2].toXlOper(theGC).fromXlOper!Foo(theGC).shouldThrowWithMessage!NoGcException( 436 "1D array length must match number of members in Foo. Expected 2, got 1"); 437 } 438 439 @("1D array to struct with wrong type") 440 @system unittest { 441 static struct Foo { int x, y; } 442 443 ["foo", "bar"].toXlOper(theGC).fromXlOper!Foo(theGC).shouldThrowWithMessage( 444 "Wrong type converting oper to Foo"); 445 } 446 447 @("2D horizontal array to struct") 448 unittest { 449 import xlld.memorymanager: allocatorContext; 450 451 static struct Foo { int x, y, z; } 452 453 with(allocatorContext(theGC)) { 454 [[any("x"), any("y"), any("z")], [any(2), any(3), any(4)]].toFrom!Foo.shouldEqual(Foo(2, 3, 4)); 455 } 456 } 457 458 @("2D vertical array to struct") 459 unittest { 460 import xlld.memorymanager: allocatorContext; 461 462 static struct Foo { int x, y, z; } 463 464 with(allocatorContext(theGC)) { 465 [[any("x"), any(2)], [any("y"), any(3)], [any("z"), any(4)]].toFrom!Foo.shouldEqual(Foo(2, 3, 4)); 466 } 467 } 468 469 470 @("2D array wrong size") 471 unittest { 472 import xlld.memorymanager: allocatorContext; 473 import nogc: NoGcException; 474 475 static struct Foo { int x, y, z; } 476 477 with(allocatorContext(theGC)) { 478 [[any("x"), any(2)], [any("y"), any(3)], [any("z"), any(4)], [any("w"), any(5)]].toFrom!Foo. 479 shouldThrowWithMessage!NoGcException("2D array must be 2x3 or 3x2 for Foo"); 480 } 481 } 482 483 484 @("PriceBar[]") 485 @system /*allocatorContext*/ unittest { 486 487 import xlld.memorymanager: allocatorContext; 488 489 static struct PriceBar { 490 double open, high, low, close; 491 } 492 493 with(allocatorContext(theGC)) { 494 auto array = 495 [ 496 [any("open"), any("high"), any("low"), any("close")], 497 [any(1.1), any(2.2), any(3.3), any(4.4)], 498 [any(2.1), any(3.2), any(4.3), any(5.4)], 499 ]; 500 501 array.toFrom!(PriceBar[]).should == [ 502 PriceBar(1.1, 2.2, 3.3, 4.4), 503 PriceBar(2.1, 3.2, 4.3, 5.4), 504 ]; 505 } 506 } 507 508 509 @("fromXlOperCoerce") 510 unittest { 511 double[][] doubles = [[1, 2, 3, 4], [11, 12, 13, 14]]; 512 auto doublesOper = toSRef(doubles, theGC); 513 doublesOper.fromXlOper!(double[][])(theGC).shouldThrowWithMessage( 514 "fromXlOper: oper not of multi type"); 515 doublesOper.fromXlOperCoerce!(double[][]).shouldEqual(doubles); 516 } 517 518 519 private auto toFrom(R, T)(T val) { 520 import std.experimental.allocator.gc_allocator: GCAllocator; 521 return val.toXlOper(GCAllocator.instance).fromXlOper!R(GCAllocator.instance); 522 } 523 524 525 @("fromXlOper!(Tuple!(double, double))") 526 @system unittest { 527 import std.typecons: tuple, Tuple; 528 import xlld.conv.from: fromXlOper; 529 tuple(22.2, 33.3) 530 .toXlOper(theGC) 531 .fromXlOper!(Tuple!(double, double))(theGC) 532 .shouldEqual(tuple(22.2, 33.3)); 533 } 534 535 @("fromXlOper!(Tuple!(int, int, int))") 536 @system unittest { 537 import std.typecons: tuple, Tuple; 538 import xlld.conv.from: fromXlOper; 539 tuple(1, 2, 3) 540 .toXlOper(theGC) 541 .fromXlOper!(Tuple!(int, int, int))(theGC) 542 .shouldEqual(tuple(1, 2, 3)); 543 } 544 545 546 @("double[].fromXlOper!int[]") 547 @system unittest { 548 [1.0, 2.0] 549 .toXlOper(theGC) 550 .fromXlOper!(int[])(theGC) 551 .should == [1, 2]; 552 } 553 554 555 @("autoFreeOper") 556 @system unittest { 557 import xlld.conv.to: toAutoFreeOper; 558 [42.0].toAutoFreeOper.fromXlOper!(double[])(theGC).should == [42.0]; 559 [42].toAutoFreeOper.fromXlOper!(int[])(theGC).should == [42]; 560 }