1 module ut.wrap.module_; 2 3 import test; 4 import ut.wrap.wrapped; 5 import xlld.wrap; 6 import xlld.conv.to: toXlOper; 7 import std.datetime; 8 import std.experimental.allocator.mallocator: Mallocator; 9 alias theMallocator = Mallocator.instance; 10 11 12 /// 13 @("Wrap double[][] -> double") 14 @system unittest { 15 import xlld.memorymanager: allocator; 16 17 auto arg = toSRef(cast(double[][])[[1, 2, 3, 4], [11, 12, 13, 14]], allocator); 18 FuncAddEverything(&arg).shouldEqualDlang(60.0); 19 20 arg = toSRef(cast(double[][])[[0, 1, 2, 3], [4, 5, 6, 7]], allocator); 21 FuncAddEverything(&arg).shouldEqualDlang(28.0); 22 } 23 24 /// 25 @("Wrap double[][] -> double[][]") 26 @system unittest { 27 import xlld.memorymanager: allocator; 28 29 auto arg = toSRef(cast(double[][])[[1, 2, 3, 4], [11, 12, 13, 14]], allocator); 30 FuncTripleEverything(&arg).shouldEqualDlang(cast(double[][])[[3, 6, 9, 12], [33, 36, 39, 42]]); 31 32 arg = toSRef(cast(double[][])[[0, 1, 2, 3], [4, 5, 6, 7]], allocator); 33 FuncTripleEverything(&arg).shouldEqualDlang(cast(double[][])[[0, 3, 6, 9], [12, 15, 18, 21]]); 34 } 35 36 37 /// 38 @("Wrap string[][] -> double") 39 @system unittest { 40 41 import xlld.memorymanager: allocator; 42 43 auto arg = toSRef([["foo", "bar", "baz", "quux"], ["toto", "titi", "tutu", "tete"]], allocator); 44 FuncAllLengths(&arg).shouldEqualDlang(29.0); 45 46 arg = toSRef([["", "", "", ""], ["", "", "", ""]], allocator); 47 FuncAllLengths(&arg).shouldEqualDlang(0.0); 48 } 49 50 /// 51 @("Wrap string[][] -> double[][]") 52 @system unittest { 53 54 import xlld.memorymanager: allocator; 55 56 auto arg = toSRef([["foo", "bar", "baz", "quux"], ["toto", "titi", "tutu", "tete"]], allocator); 57 FuncLengths(&arg).shouldEqualDlang(cast(double[][])[[3, 3, 3, 4], [4, 4, 4, 4]]); 58 59 arg = toSRef([["", "", ""], ["", "", "huh"]], allocator); 60 FuncLengths(&arg).shouldEqualDlang(cast(double[][])[[0, 0, 0], [0, 0, 3]]); 61 } 62 63 /// 64 @("Wrap string[][] -> string[][]") 65 @system unittest { 66 67 import xlld.memorymanager: allocator; 68 69 auto arg = toSRef([["foo", "bar", "baz", "quux"], ["toto", "titi", "tutu", "tete"]], allocator); 70 FuncBob(&arg).shouldEqualDlang([["foobob", "barbob", "bazbob", "quuxbob"], 71 ["totobob", "titibob", "tutubob", "tetebob"]]); 72 } 73 74 /// 75 @("Wrap string[] -> double") 76 @system unittest { 77 import xlld.memorymanager: allocator; 78 79 auto arg = toSRef([["foo", "bar"], ["baz", "quux"]], allocator); 80 FuncStringSlice(&arg).shouldEqualDlang(4.0); 81 } 82 83 /// 84 @("Wrap double[] -> double") 85 @system unittest { 86 import xlld.memorymanager: allocator; 87 auto arg = toSRef([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]], allocator); 88 FuncDoubleSlice(&arg).shouldEqualDlang(6.0); 89 } 90 91 /// 92 @("Wrap double[] -> double[]") 93 @system unittest { 94 import xlld.memorymanager: allocator; 95 auto arg = toSRef([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]], allocator); 96 FuncSliceTimes3(&arg).shouldEqualDlang([3.0, 6.0, 9.0, 12.0, 15.0, 18.0]); 97 } 98 99 /// 100 @("Wrap string[] -> string[]") 101 @system unittest { 102 import xlld.memorymanager: allocator; 103 auto arg = toSRef(["quux", "toto"], allocator); 104 StringsToStrings(&arg).shouldEqualDlang(["quuxfoo", "totofoo"]); 105 } 106 107 /// 108 @("Wrap string[] -> string") 109 @system unittest { 110 import xlld.memorymanager: allocator; 111 auto arg = toSRef(["quux", "toto"], allocator); 112 StringsToString(&arg).shouldEqualDlang("quux, toto"); 113 } 114 115 /// 116 @("Wrap string -> string") 117 @system unittest { 118 import xlld.memorymanager: allocator; 119 auto arg = toXlOper("foo", allocator); 120 StringToString(&arg).shouldEqualDlang("foobar"); 121 } 122 123 /// 124 @("Wrap string, string, string -> string") 125 @system unittest { 126 import xlld.memorymanager: allocator; 127 auto arg0 = toXlOper("foo", allocator); 128 auto arg1 = toXlOper("bar", allocator); 129 auto arg2 = toXlOper("baz", allocator); 130 ManyToString(&arg0, &arg1, &arg2).shouldEqualDlang("foobarbaz"); 131 } 132 133 /// 134 @("nothrow functions") 135 @system unittest { 136 import xlld.memorymanager: allocator; 137 auto arg = toXlOper(2.0, allocator); 138 static assert(__traits(compiles, FuncThrows(&arg))); 139 } 140 141 /// 142 @("FuncAddEverything wrapper is @nogc") 143 @system @nogc unittest { 144 import std.experimental.allocator.mallocator: Mallocator; 145 import xlld.sdk.framework: freeXLOper; 146 147 auto arg = toXlOper(2.0, Mallocator.instance); 148 scope(exit) freeXLOper(&arg, Mallocator.instance); 149 FuncAddEverything(&arg); 150 } 151 152 /// 153 @("Wrap a function that throws") 154 @system unittest { 155 auto arg = toSRef(33.3, theGC); 156 FuncThrows(&arg); // should not actually throw 157 } 158 159 /// 160 @("Wrap a function that asserts") 161 @system unittest { 162 auto arg = toSRef(33.3, theGC); 163 FuncAsserts(&arg); // should not actually throw 164 } 165 166 /// 167 @("Wrap a function that accepts DateTime") 168 @system unittest { 169 import xlld.sdk.xlcall: XlType; 170 import xlld.conv.misc: stripMemoryBitmask; 171 import std.conv: text; 172 173 // the argument doesn't matter since we mock extracting the year from it 174 // but it does have to be of double type (DateTime for Excel) 175 auto arg = 33.3.toXlOper(theGC); 176 177 const year = 2017; 178 const mock = MockDateTime(year, 1, 2, 3, 4, 5); 179 const ret = DateTimeToDouble(&arg); 180 181 try 182 ret.xltype.stripMemoryBitmask.shouldEqual(XlType.xltypeNum); 183 catch(Exception _) 184 assert(false, text("Expected xltypeNum, got ", *ret)); 185 186 ret.val.num.shouldEqual(year * 2); 187 } 188 189 /// 190 @("Wrap a function that accepts DateTime[]") 191 @system unittest { 192 //the arguments don't matter since we mock extracting year, etc. from them 193 //they just need to be double (DateTime to Excel) 194 auto arg = [0.1, 0.2].toXlOper(theGC); 195 196 auto mockDateTimes = MockDateTimes(DateTime(1, 1, 31), 197 DateTime(1, 1, 30)); 198 199 auto ret = DateTimesToString(&arg); 200 201 ret.shouldEqualDlang("31, 30"); 202 } 203 204 205 @Serial 206 @("Wrap a function that takes an enum") 207 @safe unittest { 208 import test.d_funcs: MyEnum; 209 210 auto arg = MyEnum.baz.toXlOper(theGC); 211 auto ret = () @trusted { return FuncMyEnumArg(&arg); }(); 212 ret.shouldEqualDlang("prefix_baz"); 213 } 214 215 @Serial 216 @("Wrap a function that returns an enum") 217 @safe unittest { 218 import test.d_funcs: MyEnum; 219 220 auto arg = 1.toXlOper(theGC); 221 auto ret = () @trusted { return FuncMyEnumRet(&arg); }(); 222 ret.shouldEqualDlang("bar"); 223 } 224 225 226 @Serial 227 @("Register a custom to enum conversion") 228 @safe unittest { 229 import std.conv: to; 230 import test.d_funcs: MyEnum; 231 import xlld.conv.from: registerConversionTo, unregisterConversionTo; 232 233 registerConversionTo!MyEnum((str) => str[3 .. $].to!MyEnum); 234 scope(exit) unregisterConversionTo!MyEnum; 235 236 auto arg = "___baz".toXlOper(theGC); 237 auto ret = () @trusted { return FuncMyEnumArg(&arg); }(); 238 239 ret.shouldEqualDlang("prefix_baz"); 240 } 241 242 @Serial 243 @("Register a custom from enum conversion") 244 @safe unittest { 245 246 import std.conv: text; 247 import test.d_funcs: MyEnum; 248 import xlld.conv: registerConversionFrom, unregisterConversionFrom; 249 250 registerConversionFrom!MyEnum((val) => "___" ~ text(cast(MyEnum)val)); 251 scope(exit)unregisterConversionFrom!MyEnum; 252 253 auto arg = 1.toXlOper(theGC); 254 auto ret = () @trusted { return FuncMyEnumRet(&arg); }(); 255 256 ret.shouldEqualDlang("___bar"); 257 } 258 259 @("Wrap a function that takes a struct using 1D array") 260 unittest { 261 auto arg = [2, 3].toXlOper(theGC); 262 auto ret = () @trusted { return FuncPointArg(&arg); }(); 263 264 ret.shouldEqualDlang(5); 265 } 266 267 @("Wrap a function that returns a struct") 268 unittest { 269 auto arg1 = 2.toXlOper(theGC); 270 auto arg2 = 3.toXlOper(theGC); 271 auto ret = () @trusted { return FuncPointRet(&arg1, &arg2); }(); 272 273 ret.shouldEqualDlang("Point(2, 3)"); 274 } 275 276 @("Wrap a function that returns a simple tuple") 277 unittest { 278 import xlld.conv.from: fromXlOper; 279 import xlld.conv.misc: stripMemoryBitmask; 280 import std.conv: to; 281 282 auto arg1 = 42.toXlOper(theGC); 283 auto arg2 = "foo".toXlOper(theGC); 284 auto ret = () @trusted { return FuncSimpleTupleRet(&arg1, &arg2); }(); 285 286 if(ret.xltype.stripMemoryBitmask != XlType.xltypeMulti) { 287 if(ret.xltype.stripMemoryBitmask == XlType.xltypeStr) 288 throw new Exception(ret.fromXlOper!string(theGC)); 289 else 290 throw new Exception("Oper not of multi type: " ~ to!string(*ret)); 291 } 292 293 ret.val.array.rows.shouldEqual(1); 294 ret.val.array.columns.shouldEqual(2); 295 ret.val.array.lparray[0].fromXlOper!int(theGC).shouldEqual(42); 296 ret.val.array.lparray[1].fromXlOper!string(theGC).shouldEqual("foo"); 297 } 298 299 @("Wrap a function that returns a complex tuple") 300 unittest { 301 import xlld.conv.from: fromXlOper; 302 import xlld.conv.misc: stripMemoryBitmask; 303 import std.conv: to; 304 305 auto dates = MockDates([1.0, 2.0, 3.0, 4.0]); 306 auto times = MockTimes([101.0, 102.0, 103.0, 104.0]); 307 auto dateTimes = MockDateTimes(DateTime(2017, 1, 2), DateTime(2017, 2, 2), 308 DateTime(2018, 1, 3), DateTime(2018, 2, 3)); 309 auto arg1 = 2.toXlOper(theGC); 310 auto arg2 = 3.toXlOper(theGC); 311 auto ret = () @trusted { return FuncComplexTupleRet(&arg1, &arg2); }(); 312 313 if(ret.xltype.stripMemoryBitmask != XlType.xltypeMulti) { 314 if(ret.xltype.stripMemoryBitmask == XlType.xltypeStr) 315 throw new Exception(ret.fromXlOper!string(theGC)); 316 else 317 throw new Exception("Oper not of multi type: " ~ to!string(*ret)); 318 } 319 320 ret.xltype.stripMemoryBitmask.shouldEqual(XlType.xltypeMulti); 321 ret.val.array.rows.shouldEqual(1); 322 ret.val.array.columns.shouldEqual(2); 323 324 ret.val.array.lparray[0].fromXlOper!(DateTime[])(theGC).shouldEqual( 325 [DateTime(2017, 1, 2), DateTime(2017, 2, 2)]); 326 327 ret.val.array.lparray[1].fromXlOper!(DateTime[])(theGC).shouldEqual( 328 [DateTime(2018, 1, 3), DateTime(2018, 2, 3)]); 329 } 330 331 @("Wrap a function that returns an array of tuples") 332 unittest { 333 import xlld.conv.from: fromXlOper; 334 import xlld.conv.misc: stripMemoryBitmask; 335 import std.conv: to; 336 337 auto dates = MockDates([0.1, 0.2, 0.3]); 338 auto times = MockTimes([10.1, 11.1, 12.1]); 339 auto dateTimes = MockDateTimes(DateTime(2017, 1, 1), DateTime(2018, 1, 1), DateTime(2019, 1, 1)); 340 341 auto oper = () @trusted { return FuncTupleArrayRet(); }(); 342 343 void assertMulti(in XLOPER12 oper) { 344 if(oper.xltype.stripMemoryBitmask != XlType.xltypeMulti) { 345 if(oper.xltype.stripMemoryBitmask == XlType.xltypeStr) 346 throw new Exception(oper.fromXlOper!string(theGC)); 347 else 348 throw new Exception("Oper not of multi type: " ~ to!string(oper)); 349 } 350 } 351 352 assertMulti(*oper); 353 oper.val.array.rows.shouldEqual(1); 354 oper.val.array.columns.shouldEqual(3); 355 356 auto elts = oper.val.array.lparray[0 .. 3]; 357 foreach(elt; elts) assertMulti(elt); 358 359 elts[0].val.array.lparray[0].fromXlOper!DateTime(theGC).shouldEqual(DateTime(2017, 1, 1)); 360 elts[0].val.array.lparray[1].fromXlOper!double(theGC).shouldEqual(11.1); 361 362 elts[1].val.array.lparray[0].fromXlOper!DateTime(theGC).shouldEqual(DateTime(2018, 1, 1)); 363 elts[1].val.array.lparray[1].fromXlOper!double(theGC).shouldEqual(22.2); 364 365 elts[2].val.array.lparray[0].fromXlOper!DateTime(theGC).shouldEqual(DateTime(2019, 1, 1)); 366 elts[2].val.array.lparray[1].fromXlOper!double(theGC).shouldEqual(33.3); 367 } 368 369 @("Wrap a function that takes an enum array") 370 unittest { 371 import test.d_funcs: MyEnum; 372 auto arg = [MyEnum.foo].toXlOper(theGC); 373 FuncEnumArray(&arg); 374 } 375 376 /// 377 @("wrapModuleFunctionStr") 378 @system unittest { 379 import xlld.wrap.worksheet; 380 import std.traits: getUDAs; 381 382 mixin(wrapModuleFunctionStr!("test.d_funcs", "FuncAddEverything")); 383 alias registerAttrs = getUDAs!(FuncAddEverything, Register); 384 static assert(registerAttrs[0].argumentText.value == "Array to add"); 385 } 386 387 388 /// 389 @("No memory allocation bugs in wrapModuleFunctionImpl for double return Mallocator") 390 @system unittest { 391 import test.d_funcs: FuncAddEverything; 392 import xlld.sdk.xlcall: xlbitDLLFree; 393 import xlld.memorymanager: autoFree; 394 395 TestAllocator allocator; 396 auto arg = toSRef([1.0, 2.0], theMallocator); 397 auto oper = wrapModuleFunctionImpl!FuncAddEverything(allocator, &arg); 398 (oper.xltype & xlbitDLLFree).shouldBeTrue; 399 allocator.numAllocations.shouldEqual(2); 400 oper.shouldEqualDlang(3.0); 401 autoFree(oper); // normally this is done by Excel 402 } 403 404 /// 405 @("No memory allocation bugs in wrapModuleFunctionImpl for double[][] return Mallocator") 406 @system unittest { 407 import test.d_funcs: FuncTripleEverything; 408 import xlld.sdk.xlcall: xlbitDLLFree, XlType; 409 import xlld.memorymanager: autoFree; 410 411 TestAllocator allocator; 412 auto arg = toSRef([1.0, 2.0, 3.0], theMallocator); 413 auto oper = wrapModuleFunctionImpl!FuncTripleEverything(allocator, &arg); 414 (oper.xltype & xlbitDLLFree).shouldBeTrue; 415 (oper.xltype & ~xlbitDLLFree).shouldEqual(XlType.xltypeMulti); 416 allocator.numAllocations.shouldEqual(2); 417 oper.shouldEqualDlang([[3.0, 6.0, 9.0]]); 418 autoFree(oper); // normally this is done by Excel 419 } 420 421 /// 422 @("No memory allocation bugs in wrapModuleFunctionImpl for double[][] return pool") 423 @system unittest { 424 import std.typecons: Ternary; 425 import xlld.memorymanager: gTempAllocator, autoFree; 426 import test.d_funcs: FuncTripleEverything; 427 428 auto arg = toSRef([1.0, 2.0, 3.0], gTempAllocator); 429 auto oper = wrapModuleFunctionImpl!FuncTripleEverything(gTempAllocator, &arg); 430 gTempAllocator.empty.shouldEqual(Ternary.yes); 431 oper.shouldEqualDlang([[3.0, 6.0, 9.0]]); 432 autoFree(oper); // normally this is done by Excel 433 } 434 435 /// 436 @("No memory allocation bugs in wrapModuleFunctionImpl for string") 437 @system unittest { 438 import std.typecons: Ternary; 439 import xlld.memorymanager: gTempAllocator; 440 import test.d_funcs: StringToString; 441 442 auto arg = "foo".toSRef(gTempAllocator); 443 auto oper = wrapModuleFunctionImpl!StringToString(gTempAllocator, &arg); 444 gTempAllocator.empty.shouldEqual(Ternary.yes); 445 oper.shouldEqualDlang("foobar"); 446 } 447 448 /// 449 @("No memory allocation bugs in wrapModuleFunctionImpl for Any[][] -> Any[][] -> Any[][] mallocator") 450 @system unittest { 451 import xlld.memorymanager: allocatorContext; 452 import test.d_funcs: FirstOfTwoAnyArrays; 453 454 with(allocatorContext(theGC)) { 455 auto dArg = [[any(1.0), any("foo"), any(3.0)], [any(4.0), any(5.0), any(6.0)]]; 456 auto arg = toXlOper(dArg); 457 auto oper = wrapModuleFunctionImpl!FirstOfTwoAnyArrays(theMallocator, &arg, &arg); 458 oper.shouldEqualDlang(dArg); 459 } 460 } 461 462 /// 463 @("No memory allocation bugs in wrapModuleFunctionImpl for Any[][] -> Any[][] -> Any[][] TestAllocator") 464 @system unittest { 465 import xlld.memorymanager: allocatorContext; 466 import test.d_funcs: FirstOfTwoAnyArrays; 467 468 auto testAllocator = TestAllocator(); 469 470 with(allocatorContext(theGC)) { 471 auto dArg = [ 472 [ any(1.0), any("foo"), any(3.0) ], 473 [ any(4.0), any(5.0), any(6.0) ], 474 ]; 475 auto arg = toXlOper(dArg); 476 auto oper = wrapModuleFunctionImpl!FirstOfTwoAnyArrays(testAllocator, &arg, &arg); 477 oper.shouldEqualDlang(dArg); 478 } 479 } 480 481 /// 482 @("Correct number of coercions and frees in wrapModuleFunctionImpl") 483 @system unittest { 484 import test.d_funcs: FuncAddEverything; 485 import xlld.test.util: gNumXlAllocated, gNumXlFree; 486 487 const oldNumAllocated = gNumXlAllocated; 488 const oldNumFree = gNumXlFree; 489 490 auto arg = toSRef([1.0, 2.0], theGC); 491 auto oper = wrapModuleFunctionImpl!FuncAddEverything(theGC, &arg); 492 493 (gNumXlAllocated - oldNumAllocated).shouldEqual(1); 494 (gNumXlFree - oldNumFree).shouldEqual(1); 495 } 496 497 498 /// 499 @("Can't return empty 1D array to Excel") 500 @system unittest { 501 import xlld.memorymanager: allocatorContext; 502 import test.d_funcs: EmptyStrings1D; 503 504 with(allocatorContext(theGC)) { 505 auto dArg = any(1.0); 506 auto arg = toXlOper(dArg); 507 auto oper = wrapModuleFunctionImpl!EmptyStrings1D(theGC, &arg); 508 oper.shouldEqualDlang("#ERROR: empty result"); 509 } 510 } 511 512 513 /// 514 @("Can't return empty 2D array to Excel") 515 @system unittest { 516 import xlld.memorymanager: allocatorContext; 517 import test.d_funcs: EmptyStrings2D; 518 519 with(allocatorContext(theGC)) { 520 auto dArg = any(1.0); 521 auto arg = toXlOper(dArg); 522 auto oper = wrapModuleFunctionImpl!EmptyStrings2D(theGC, &arg); 523 oper.shouldEqualDlang("#ERROR: empty result"); 524 } 525 } 526 527 /// 528 @("Can't return half empty 2D array to Excel") 529 @system unittest { 530 import xlld.memorymanager: allocatorContext; 531 import test.d_funcs: EmptyStringsHalfEmpty2D; 532 533 with(allocatorContext(theGC)) { 534 auto dArg = any(1.0); 535 auto arg = toXlOper(dArg); 536 auto oper = wrapModuleFunctionImpl!EmptyStringsHalfEmpty2D(theGC, &arg); 537 oper.shouldEqualDlang("#ERROR: empty result"); 538 } 539 } 540 541 /// 542 @("issue 25 - make sure to reserve memory for all dArgs") 543 @system unittest { 544 import std.typecons: Ternary; 545 import xlld.memorymanager: allocatorContext, MemoryPool; 546 import test.d_funcs: FirstOfTwoAnyArrays; 547 548 auto pool = MemoryPool(); 549 550 with(allocatorContext(theGC)) { 551 auto dArg = [[any(1.0), any("foo"), any(3.0)], [any(4.0), any(5.0), any(6.0)]]; 552 auto arg = toSRef(dArg); 553 auto oper = wrapModuleFunctionImpl!FirstOfTwoAnyArrays(pool, &arg, &arg); 554 } 555 556 pool.empty.shouldEqual(Ternary.yes); // deallocateAll in wrapImpl 557 } 558 559 560 /// 561 @("wrapModuleFunctionStr function that returns Any[][]") 562 @safe unittest { 563 mixin(wrapModuleFunctionStr!("test.d_funcs", "DoubleArrayToAnyArray")); 564 565 auto oper = [[1.0, 2.0], [3.0, 4.0]].toSRef(theGC); 566 auto arg = () @trusted { return &oper; }(); 567 auto ret = DoubleArrayToAnyArray(arg); 568 569 auto opers = () @trusted { return ret.val.array.lparray[0 .. 4]; }(); 570 opers[0].shouldEqualDlang(2.0); 571 opers[1].shouldEqualDlang(6.0); 572 opers[2].shouldEqualDlang("3quux"); 573 opers[3].shouldEqualDlang("4toto"); 574 } 575 576 /// 577 @("wrapModuleFunctionStr int -> int") 578 @safe unittest { 579 mixin(wrapModuleFunctionStr!("test.d_funcs", "Twice")); 580 581 auto oper = 3.toSRef(theGC); 582 auto arg = () @trusted { return &oper; }(); 583 Twice(arg).shouldEqualDlang(6); 584 } 585 586 /// 587 @("issue 31 - D functions can have const arguments") 588 @safe unittest { 589 mixin(wrapModuleFunctionStr!("test.d_funcs", "FuncConstDouble")); 590 591 auto oper = (3.0).toSRef(theGC); 592 auto arg = () @trusted { return &oper; }(); 593 FuncConstDouble(arg).shouldEqualDlang(3.0); 594 } 595 596 597 @Flaky 598 @("wrapModuleFunctionStr async double -> double") 599 unittest { 600 import xlld.conv.from: fromXlOper; 601 import xlld.wrap.traits: Async; 602 import xlld.test.util: asyncReturn, newAsyncHandle; 603 import core.time: MonoTime; 604 import core.thread; 605 606 mixin(wrapModuleFunctionStr!("test.d_funcs", "AsyncDoubleToDouble")); 607 608 auto oper = (3.0).toXlOper(theGC); 609 auto arg = () @trusted { return &oper; }(); 610 auto asyncHandle = newAsyncHandle; 611 () @trusted { AsyncDoubleToDouble(arg, &asyncHandle); }(); 612 613 const start = MonoTime.currTime; 614 const expected = 6.0; 615 while(asyncReturn(asyncHandle).fromXlOper!double(theGC) != expected && 616 MonoTime.currTime - start < 1.seconds) 617 { 618 Thread.sleep(10.msecs); 619 } 620 asyncReturn(asyncHandle).shouldEqualDlang(expected); 621 } 622 623 @("wrapModuleFunctionStr () -> NaN") 624 unittest { 625 mixin(wrapModuleFunctionStr!("test.d_funcs", "NaN")); 626 NaN().shouldEqualDlang("#NaN"); 627 } 628 629 630 631 @("wrapModuleFunctionImpl gTempAllocator @safe") 632 @safe unittest { 633 import xlld.memorymanager: gTempAllocator; 634 import test.d_funcs: Twice; 635 636 auto arg = 3.toXlOper(theGC); 637 auto argPtr = () @trusted { return &arg; }(); 638 auto oper = wrapModuleFunctionImpl!Twice(gTempAllocator, argPtr); 639 oper.shouldEqualDlang(6); 640 } 641 642 643 @("oper") 644 @safe unittest { 645 auto arg = (3.3).toXlOper(theGC); 646 scope argPtr = &arg; 647 FuncOper(argPtr).shouldEqualDlang(6.6); 648 } 649 650 651 @("vector.1d") 652 @safe unittest { 653 auto arg = 7.toXlOper(theGC); 654 scope argPtr = &arg; 655 FuncVector(argPtr).shouldEqualDlang([0, 1, 2, 3, 4, 5, 6]); 656 } 657 658 659 @("vector.2d") 660 @safe unittest { 661 auto arg = 7.toXlOper(theGC); 662 scope argPtr = &arg; 663 FuncVector2D(argPtr).shouldEqualDlang([[7, 7, 7], [8, 8, 8]]); 664 }