trial.stackresult 295/313(94%) line coverage

      
10
20
30
40
50
60
70
80
90
100
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
280
290
300
310
320
330
340
350
360
370
380
391
401
411
420
431
440
451
460
470
480
490
500
510
520
530
540
550
560
570
580
590
600
610
620
631
641
650
662
670
680
690
700
710
723
730
743
750
763
770
783
790
802
810
820
836
840
851
860
870
883
890
900
910
920
933
940
950
960
970
980
990
1001
1011
1020
1032
1042
1052
1060
1070
1080
1090
1100
1111
1121
1130
1142
1152
1162
1170
1180
1190
1200
1210
1220
1230
1240
1250
1260
1270
1280
1295
1305
1310
1325
1335
1345
135227
1360
13774
1380
1396
1400
1410
14274
1430
1446
1450
1460
14774
1480
1495
1500
15169
1520
1530
1545
1555
1565
1570
1585
1595
1600
1615
1620
1631
1640
1650
1664
1670
1689
1690
1700
1710
1720
1730
1740
1751
1760
1772
1780
1790
1802
1810
1822
1830
1840
1850
1862
1870
1880
1890
1900
1910
1920
1930
1940
1950
1960
1970
1980
1990
2000
2010
2020
2032
2040
2052
2060
20726
20826
20926
2100
2110
2120
2130
2140
2150
2160
21728
21826
2190
2200
2210
2220
2230
2240
2250
2260
2272
2280
22982
2300
23126
2320
2330
2342
2350
2360
2370
2380
2390
2400
2410
2420
2430
2440
2450
2460
2470
2480
2490
2500
2510
2520
2530
2540
2550
2560
2570
2580
2590
2600
2610
2620
2630
2640
2650
2660
2671
2680
2690
2700
2711
2720
2730
2740
2751
2760
2770
2781
2790
2802
2812
2820
2830
2840
2850
2860
2870
2880
2890
2900
2910
2920
2930
2940
2950
2960
2970
2980
2990
3000
3010
3020
3030
3040
3050
3060
3070
3080
30932
3100
31132
3121
3130
3140
31532
31664
3170
31832
3198
3200
3210
32232
3234
3240
3250
32632
32721
3280
32921
33020
3310
3320
33321
3340
3350
33632
3370
3380
3390
3400
3416
3421
3430
3440
3456
34612
3470
3486
3493
3503
3510
3520
3536
3544
3554
3560
3570
3586
3592
3602
3610
3622
3631
3641
3650
3660
3672
3680
3690
3700
3710
3720
3730
3740
3752
3760
3770
3780
3790
3800
3810
3820
3832
3840
3850
3860
3870
3880
3890
3900
3912
3920
3930
3940
3950
3960
3970
3980
3992
4000
4010
4020
4030
4040
4050
4060
4072
4080
4090
4100
4110
4120
4130
4140
4152
4160
4170
4180
4190
4200
4210
4220
4230
4240
42518
4260
4270
4280
42917
4300
4310
4320
4330
4340
4350
4360
4370
4380
4390
4400
4410
4420
4430
4440
4450
4460
4470
4480
4490
4500
4510
4520
4531
4541
4550
4562
4570
4580
4590
4600
4610
4620
4630
4641
4651
4660
4672
4680
4690
4700
4710
4720
4730
4740
4751
4761
4770
4782
4790
4800
4810
4820
4830
4840
4850
4861
4871
4880
4892
4900
4910
4920
4930
4940
4950
4960
4971
4981
4990
5002
5010
5020
5030
5040
5050
5060
5070
5081
5091
5100
5112
5120
5130
5140
5150
5160
5170
5180
5190
5200
5210
5220
5230
5240
5250
5260
5270
5280
5290
53037
5310
53237
5330
5340
53574
5360
53737
5381
5391
5401
5411
5420
5431
5440
5450
5460
5470
5480
54936
5500
55172
5520
5530
55436
55536
55636
55736
5580
5591
5601
5611
5620
5631
5640
5650
5660
5670
5680
56935
5700
57170
57235
57335
5740
57569
5761
5770
5781
5790
5800
5810
5820
5830
58434
5850
58668
5870
58834
58934
59034
5910
59234
5930
59434
5950
5961
5971
5980
5990
60046
60122
60237
6037
6040
6057
6060
6070
6080
6090
6100
61127
6120
61354
6140
61527
61627
61727
61827
6190
62053
6211
6221
6231
6240
6251
6260
6270
6280
6290
63026
6310
63252
6330
63426
63526
63626
63726
6380
63923
64023
64123
64223
6430
64423
6450
6460
6470
6480
6493
6500
6516
6520
6533
6543
6550
6563
6573
6580
6593
6600
6610
6620
6630
6640
66537
6660
6670
6680
66937
6700
6710
6720
6730
6740
6750
6760
67736
6780
6790
6800
6810
6820
6830
6840
68535
6860
6870
6880
6890
6900
6910
6920
69334
6940
6950
6960
6970
6980
6990
7000
70127
7020
7030
7040
7050
7060
7070
7080
70926
7100
7110
7120
7130
7140
7150
7160
7173
7180
7190
7200
7210
7220
7230
7240
7250
7260
7270
7280
7291
7300
7311
7322
7332
7342
7352
7362
7370
7380
7390
7400
7410
7421
7430
7441
7452
7462
7472
7482
7492
7500
7510
7520
7530
7540
7551
7560
7571
7582
7592
7602
7612
7622
7632
7642
7650
7660
7670
7680
7690
7701
7710
7721
7730
7742
7752
7762
7772
7782
7790
7800
7810
7820
7830
7841
7850
7861
7870
7882
7892
7902
7912
7922
7930
7940
7950
7960
7970
7981
7990
8001
8010
8022
8032
8042
8052
8062
8070
8080
8090
8100
8111
8120
8131
8140
8152
8162
8172
8182
8192
8202
8212
8220
8230
8240
8250
8261
8271
8280
8292
8302
8312
8322
8332
8342
8352
8360
8370
8380
8390
8401
8411
8420
8432
8442
8452
8462
8472
8482
8492
8500
8510
8520
8530
8541
8551
8560
8572
8582
8592
8602
8612
8622
8632
8640
8650
8660
8670
8680
8691
8701
8710
8722
8732
8742
8752
8762
8772
8782
8790
8800
8810
8820
8830
8840
8850
8860
8870
8880
8890
8900
8910
8920
8930
8940
8950
8960
/++ A module containing custom exceptions for display convenience Copyright: © 2017 Szabo Bogdan License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. Authors: Szabo Bogdan +/ module trial.stackresult; import std.conv; import std.regex; import std.exception; import std.stdio; import std.string; import std.algorithm; import core.demangle; version (Have_fluent_asserts_core) { } else { auto toTestException(Throwable t) { return t; } } version (Have_fluent_asserts_core) { import fluentasserts.core.base; import fluentasserts.core.results; /// class TestExceptionWrapper : TestException { private { TestException exception; IResult[] results; } /// this(TestException exception, IResult[] results, string fileName, size_t line, Throwable next = null) { this.exception = exception; this.results = results; super(results, fileName, line, next); this.msg = exception.msg ~ "\n" ~ this.msg; } /// override void print(ResultPrinter printer) { exception.print(printer); results.each!(a => a.print(printer)); } /// override string toString() { return exception.toString ~ results.map!(a => a.toString).join("\n").to!string; } } /// The message of a wrapped exception should contain the original exception unittest { auto exception = new TestException([ new MessageResult("first message") ], "", 0); auto wrappedException = new TestExceptionWrapper(exception, [ new MessageResult("second message") ], "", 0); wrappedException.msg.should.equal("first message\n\nsecond message\n"); } /// Converts a Throwable to a TestException which improves the failure verbosity TestException toTestException(Throwable t) { auto exception = cast(TestException) t; if (exception is null) { IResult[] results = [cast(IResult) new MessageResult(t.classinfo.name ~ ": " ~ t.msg)]; if (t.file.indexOf("../") == -1) { results ~= cast(IResult) new SourceResult(t.file, t.line); } if (t !is null && t.info !is null) { results ~= cast(IResult) new StackResult(t.info); } exception = new TestException(results, t.file, t.line, t); } else { exception = new TestExceptionWrapper(exception, [ cast(IResult) new StackResult(t.info) ], t.file, t.line, t); } return exception; } @("toTestException should convert an Exception from the current project to a TestException with 2 reporters") unittest { auto exception = new Exception("random text"); auto testException = exception.toTestException; (testException !is null).should.equal(true); testException.toString.should.contain("random text"); testException.toString.should.contain("lifecycle/trial/runner.d"); } @("toTestException should convert an Exception from other project to a TestException with 1 reporter") unittest { auto exception = new Exception("random text", "../file.d"); auto testException = exception.toTestException; (testException !is null).should.equal(true); testException.toString.should.contain("random text"); testException.toString.should.not.contain("lifecycle/trial/runner.d"); } /// A structure that allows you to detect which modules are relevant to display struct ExternalValidator { /// The list of external modules like the standard library or dub dependencies string[] externalModules; /// Check if the provided name comes from an external dependency bool isExternal(const string name) { auto reversed = name.dup; reverse(reversed); string substring = name; int sum = 0; int index = 0; foreach (ch; reversed) { if (ch == ')') { sum++; } if (ch == '(') { sum--; } if (sum == 0) { break; } index++; } auto tmpSubstring = reversed[index .. $]; reverse(tmpSubstring); substring = tmpSubstring.to!string; auto wordEnd = substring.lastIndexOf(' ') + 1; auto chainEnd = substring.lastIndexOf(").") + 1; if (chainEnd > wordEnd) { return isExternal(name[0 .. chainEnd]); } auto functionName = substring[wordEnd .. $]; return !externalModules.filter!(a => functionName.indexOf(a) == 0).empty; } } @("It should detect external functions") unittest { auto validator = ExternalValidator(["selenium.api", "selenium.session"]); validator.isExternal("selenium.api.SeleniumApiConnector selenium.api.SeleniumApiConnector.__ctor()") .should.equal(true); validator.isExternal("void selenium.api.SeleniumApiConnector.__ctor()").should.equal(true); validator.isExternal( "pure @safe bool selenium.api.enforce!(Exception, bool).enforce(bool, lazy const(char)[], immutable(char)[], ulong)") .should.equal(true); validator.isExternal("immutable(immutable(selenium.session.SeleniumSession) function(immutable(char)[], selenium.api.Capabilities, selenium.api.Capabilities, selenium.api.Capabilities)) selenium.session.SeleniumSession.__ctor") .should.equal(true); } /// Used to display the stack class StackResult : IResult { static { /// string[] externalModules; } /// Frame[] frames; /// this(Throwable.TraceInfo t) { foreach (line; t) { auto frame = line.to!string.toFrame; frame.name = demangle(frame.name).to!string; frames ~= frame; } } private { auto getFrames() { return frames.until!(a => a.name.indexOf("generated") != -1) .until!(a => a.name.indexOf("D5trial") != -1); } } override { /// Converts the result to a string string toString() { string result = "Stack trace:\n-------------------\n...\n"; foreach (frame; getFrames) { result ~= frame.toString ~ "\n"; } return result ~ "..."; } /// Prints the stack using the default writer void print(ResultPrinter printer) { int colorIndex = 0; printer.primary("Stack trace:\n-------------------\n...\n"); auto validator = ExternalValidator(externalModules); foreach (frame; getFrames) { if (validator.isExternal(frame.name)) { printer.primary(frame.toString); } else { frame.print(printer); } printer.primary("\n"); } printer.primary("..."); } } } @("The stack result should display the stack in a readable form") unittest { Throwable exception; try { assert(false, "random message"); } catch (Throwable t) { exception = t; } auto result = new StackResult(exception.info).toString; result.should.startWith("Stack trace:\n-------------------\n..."); result.should.endWith("\n..."); } /// Represents a stack frame struct Frame { /// int index = -1; /// string moduleName; /// string address; /// string name; /// string offset; /// string file; /// int line = -1; string toString() const { string result; if(index >= 0) { result ~= leftJustifier(index.to!string, 4).to!string; } result ~= address ~ " "; result ~= name == "" ? "????" : name; if(moduleName != "") { result ~= " at " ~ moduleName; } if(offset != "") { result ~= " + " ~ offset; } if(file != "") { result ~= " (" ~ file; if(line > 0) { result ~= ":" ~ line.to!string; } result ~= ")"; } return result; } void print(ResultPrinter printer) { if(index >= 0) { printer.info(leftJustifier(index.to!string, 4).to!string); } printer.primary(address ~ " "); printer.info(name == "" ? "????" : name); if(moduleName != "") { printer.primary(" at "); printer.info(moduleName); } if(offset != "") { printer.primary(" + "); printer.info(offset); } if(file != "") { printer.primary(" ("); printer.info(file); if(line > 0) { printer.primary(":"); printer.info(line.to!string); } printer.primary(")"); } } } /// The frame should convert a frame to string unittest { Frame(10, "some.module", "0xffffff", "name", "offset", "file.d", 120).toString.should.equal( `10 0xffffff name at some.module + offset (file.d:120)` ); } /// The frame should not output an index < 0 or a line < 0 unittest { Frame(-1, "some.module", "0xffffff", "name", "offset", "file.d", -1).toString.should.equal( `0xffffff name at some.module + offset (file.d)` ); } /// The frame should not output the file if it is missing from the stack unittest { Frame(-1, "some.module", "0xffffff", "name", "offset", "", 10).toString.should.equal( `0xffffff name at some.module + offset` ); } /// The frame should not output the module if it is missing from the stack unittest { Frame(-1, "", "0xffffff", "name", "offset", "", 10).toString.should.equal( `0xffffff name + offset` ); } /// The frame should not output the offset if it is missing from the stack unittest { Frame(-1, "", "0xffffff", "name", "", "", 10).toString.should.equal( `0xffffff name` ); } /// The frame should display `????` when the name is missing unittest { Frame(-1, "", "0xffffff", "", "", "", 10).toString.should.equal( `0xffffff ????` ); } version(unittest) { class MockPrinter : ResultPrinter { string buffer; void primary(string val) { buffer ~= val; } void info(string val) { buffer ~= "[info:" ~ val ~ "]"; } void danger(string val) { buffer ~= "[danger:" ~ val ~ "]"; } void success(string val) { buffer ~= "[success:" ~ val ~ "]"; } void dangerReverse(string val) { buffer ~= "[dangerReverse:" ~ val ~ "]"; } void successReverse(string val) { buffer ~= "[successReverse:" ~ val ~ "]"; } } } /// The frame should print all fields unittest { auto printer = new MockPrinter; Frame(10, "some.module", "0xffffff", "name", "offset", "file.d", 120).print(printer); printer.buffer.should.equal( `[info:10 ]0xffffff [info:name] at [info:some.module] + [info:offset] ([info:file.d]:[info:120])` ); } /// The frame should not print an index < 0 or a line < 0 unittest { auto printer = new MockPrinter; Frame(-1, "some.module", "0xffffff", "name", "offset", "file.d", -1).print(printer); printer.buffer.should.equal( `0xffffff [info:name] at [info:some.module] + [info:offset] ([info:file.d])` ); } /// The frame should not print the file if it's missing unittest { auto printer = new MockPrinter; Frame(-1, "some.module", "0xffffff", "name", "offset", "", 10).print(printer); printer.buffer.should.equal( `0xffffff [info:name] at [info:some.module] + [info:offset]` ); } /// The frame should not print the module if it's missing unittest { auto printer = new MockPrinter; Frame(-1, "", "0xffffff", "name", "offset", "", 10).print(printer); printer.buffer.should.equal( `0xffffff [info:name] + [info:offset]` ); } /// The frame should not print the offset if it's missing unittest { auto printer = new MockPrinter; Frame(-1, "", "0xffffff", "name", "", "", 10).print(printer); printer.buffer.should.equal( `0xffffff [info:name]` ); } /// The frame should print ???? when the name is missing unittest { auto printer = new MockPrinter; Frame(-1, "", "0xffffff", "", "", "", 10).print(printer); printer.buffer.should.equal( `0xffffff [info:????]` ); } immutable static { string index = `(?P<index>[0-9]+)`; string moduleName = `(?P<module>\S+)`; string address = `(?P<address>0x[0-9a-fA-F]+)`; string name = `(?P<name>.+)`; string offset = `(?P<offset>(0x[0-9A-Za-z]+)|([0-9]+))`; string file = `(?P<file>.+)`; string linePattern = `(?P<line>[0-9]+)`; } /// Parse a MacOS string frame Frame toDarwinFrame(string line) { Frame frame; auto darwinPattern = index ~ `(\s+)` ~ moduleName ~ `(\s+)` ~ address ~ `(\s+)` ~ name ~ `\s\+\s` ~ offset; auto matched = matchFirst(line, darwinPattern); frame.index = matched["index"].to!int; frame.moduleName = matched["module"]; frame.address = matched["address"]; frame.name = matched["name"]; frame.offset = matched["offset"]; return frame; } /// Parse a Windows string frame Frame toWindows1Frame(string line) { Frame frame; auto matched = matchFirst(line, address ~ `(\s+)in(\s+)` ~ name ~ `(\s+)at(\s+)` ~ file ~ `\(` ~ linePattern ~ `\)`); // ~ ); frame.address = matched["address"]; frame.name = matched["name"]; frame.file = matched["file"]; frame.line = matched["line"].to!int; enforce(frame.address != "", "address not found"); enforce(frame.name != "", "name not found"); enforce(frame.file != "", "file not found"); return frame; } /// ditto Frame toWindows2Frame(string line) { Frame frame; auto matched = matchFirst(line, address ~ `(\s+)in(\s+)` ~ name); frame.address = matched["address"]; frame.name = matched["name"]; enforce(frame.address != "", "address not found"); enforce(frame.name != "", "name not found"); return frame; } /// Parse a GLibC string frame Frame toGLibCFrame(string line) { Frame frame; auto matched = matchFirst(line, moduleName ~ `\(` ~ name ~ `\)\s+\[` ~ address ~ `\]`); frame.address = matched["address"]; frame.name = matched["name"]; frame.moduleName = matched["module"]; auto plusSign = frame.name.indexOf("+"); if (plusSign != -1) { frame.offset = frame.name[plusSign + 1 .. $]; frame.name = frame.name[0 .. plusSign]; } enforce(frame.address != "", "address not found"); enforce(frame.name != "", "name not found"); enforce(frame.name.indexOf("(") == -1, "name should not contain `(`"); enforce(frame.moduleName != "", "module not found"); return frame; } /// Parse a NetBsd string frame Frame toNetBsdFrame(string line) { Frame frame; auto matched = matchFirst(line, address ~ `\s+<` ~ name ~ `\+` ~ offset ~ `>\s+at\s+` ~ moduleName); frame.address = matched["address"]; frame.name = matched["name"]; frame.moduleName = matched["module"]; frame.offset = matched["offset"]; enforce(frame.address != "", "address not found"); enforce(frame.name != "", "name not found"); enforce(frame.moduleName != "", "module not found"); enforce(frame.offset != "", "offset not found"); return frame; } /// Parse a Linux frame Frame toLinuxFrame(string line) { Frame frame; auto matched = matchFirst(line, file ~ `:` ~ linePattern ~ `\s+` ~ name ~ `\s+\[` ~ address ~ `\]`); frame.file = matched["file"]; frame.name = matched["name"]; frame.address = matched["address"]; frame.line = matched["line"].to!int; enforce(frame.address != "", "address not found"); enforce(frame.name != "", "name not found"); enforce(frame.file != "", "file not found"); enforce(frame.line > 0, "line not found"); return frame; } /// Parse a Linux frame Frame toMissingInfoLinuxFrame(string line) { Frame frame; auto matched = matchFirst(line, `\?\?:\?\s+` ~ name ~ `\s+\[` ~ address ~ `\]`); frame.name = matched["name"]; frame.address = matched["address"]; enforce(frame.address != "", "address not found"); enforce(frame.name != "", "name not found"); return frame; } /// Converts a stack trace line to a Frame structure Frame toFrame(string line) { Frame frame; try { return line.toDarwinFrame; } catch (Exception e) { } try { return line.toWindows1Frame; } catch (Exception e) { } try { return line.toWindows2Frame; } catch (Exception e) { } try { return line.toGLibCFrame; } catch (Exception e) { } try { return line.toNetBsdFrame; } catch (Exception e) { } try { return line.toLinuxFrame; } catch (Exception e) { } try { return line.toMissingInfoLinuxFrame; } catch (Exception e) { } return frame; } @("Get frame info from Darwin platform format") unittest { auto line = "1 ???fluent-asserts 0x00abcdef000000 D6module4funcAFZv + 0"; auto frame = line.toFrame; frame.index.should.equal(1); frame.moduleName.should.equal("???fluent-asserts"); frame.address.should.equal("0x00abcdef000000"); frame.name.should.equal("D6module4funcAFZv"); frame.offset.should.equal("0"); } @("Get frame info from windows platform format without path") unittest { auto line = "0x779CAB5A in RtlInitializeExceptionChain"; auto frame = line.toFrame; frame.index.should.equal(-1); frame.moduleName.should.equal(""); frame.address.should.equal("0x779CAB5A"); frame.name.should.equal("RtlInitializeExceptionChain"); frame.offset.should.equal(""); } @("Get frame info from windows platform format with path") unittest { auto line = `0x00402669 in void app.__unitestL82_8() at D:\tidynumbers\source\app.d(84)`; auto frame = line.toFrame; frame.index.should.equal(-1); frame.moduleName.should.equal(""); frame.address.should.equal("0x00402669"); frame.name.should.equal("void app.__unitestL82_8()"); frame.file.should.equal(`D:\tidynumbers\source\app.d`); frame.line.should.equal(84); frame.offset.should.equal(""); } @("Get frame info from CRuntime_Glibc format without offset") unittest { auto line = `module(_D6module4funcAFZv) [0x00000000]`; auto frame = line.toFrame; frame.moduleName.should.equal("module"); frame.name.should.equal("_D6module4funcAFZv"); frame.address.should.equal("0x00000000"); frame.index.should.equal(-1); frame.offset.should.equal(""); } @("Get frame info from CRuntime_Glibc format with offset") unittest { auto line = `module(_D6module4funcAFZv+0x78) [0x00000000]`; auto frame = line.toFrame; frame.moduleName.should.equal("module"); frame.name.should.equal("_D6module4funcAFZv"); frame.address.should.equal("0x00000000"); frame.index.should.equal(-1); frame.offset.should.equal("0x78"); } @("Get frame info from NetBSD format") unittest { auto line = `0x00000000 <_D6module4funcAFZv+0x78> at module`; auto frame = line.toFrame; frame.moduleName.should.equal("module"); frame.name.should.equal("_D6module4funcAFZv"); frame.address.should.equal("0x00000000"); frame.index.should.equal(-1); frame.offset.should.equal("0x78"); } /// Get the main frame info from linux format unittest { auto line = `generated.d:45 _Dmain [0x8e80c4]`; auto frame = line.toFrame; frame.moduleName.should.equal(""); frame.file.should.equal("generated.d"); frame.line.should.equal(45); frame.name.should.equal("_Dmain"); frame.address.should.equal("0x8e80c4"); frame.index.should.equal(-1); frame.offset.should.equal(""); } /// Get a function frame info from linux format unittest { auto line = `lifecycle/trial/runner.d:106 trial.interfaces.SuiteResult[] trial.runner.runTests(const(trial.interfaces.TestCase)[], immutable(char)[]) [0x8b0ec1]`; auto frame = line.toFrame; frame.moduleName.should.equal(""); frame.file.should.equal("lifecycle/trial/runner.d"); frame.line.should.equal(106); frame.name.should.equal("trial.interfaces.SuiteResult[] trial.runner.runTests(const(trial.interfaces.TestCase)[], immutable(char)[])"); frame.address.should.equal("0x8b0ec1"); frame.index.should.equal(-1); frame.offset.should.equal(""); } /// Get an external function frame info from linux format unittest { auto line = `../../.dub/packages/fluent-asserts-0.6.6/fluent-asserts/core/fluentasserts/core/base.d:39 void fluentasserts.core.base.Result.perform() [0x8f4b47]`; auto frame = line.toFrame; frame.moduleName.should.equal(""); frame.file.should.equal("../../.dub/packages/fluent-asserts-0.6.6/fluent-asserts/core/fluentasserts/core/base.d"); frame.line.should.equal(39); frame.name.should.equal("void fluentasserts.core.base.Result.perform()"); frame.address.should.equal("0x8f4b47"); frame.index.should.equal(-1); frame.offset.should.equal(""); } /// Get an external function frame info from linux format unittest { auto line = `lifecycle/trial/discovery/unit.d:268 _D5trial9discovery4unit17UnitTestDiscovery231__T12addTestCasesVAyaa62_2f686f6d652f626f737a2f776f726b73706163652f64746573742f6c6966656379636c652f747269616c2f6578656375746f722f706172616c6c656c2e64VAyaa23_747269616c2e6578656375746f722e706172616c6c656cS245trial8executor8parallelZ12addTestCasesMFZ9__lambda4FZv [0x872000]`; auto frame = line.toFrame; frame.moduleName.should.equal(""); frame.file.should.equal("lifecycle/trial/discovery/unit.d"); frame.line.should.equal(268); frame.name.should.equal("_D5trial9discovery4unit17UnitTestDiscovery231__T12addTestCasesVAyaa62_2f686f6d652f626f737a2f776f726b73706163652f64746573742f6c6966656379636c652f747269616c2f6578656375746f722f706172616c6c656c2e64VAyaa23_747269616c2e6578656375746f722e706172616c6c656cS245trial8executor8parallelZ12addTestCasesMFZ9__lambda4FZv"); frame.address.should.equal("0x872000"); frame.index.should.equal(-1); frame.offset.should.equal(""); } /// Get an missing info function frame info from linux format unittest { auto line = `??:? __libc_start_main [0x174bbf44]`; auto frame = line.toFrame; frame.moduleName.should.equal(""); frame.file.should.equal(""); frame.line.should.equal(-1); frame.name.should.equal("__libc_start_main"); frame.address.should.equal("0x174bbf44"); frame.index.should.equal(-1); frame.offset.should.equal(""); } /* lifecycle/trial/executor/single.d:96 void trial.executor.single.DefaultExecutor.createTestResult(const(trial.interfaces.TestCase)) [0x8653dd6] lifecycle/trial/executor/single.d:130 trial.interfaces.SuiteResult[] trial.executor.single.DefaultExecutor.execute(ref const(trial.interfaces.TestCase)) [0x86540f0] lifecycle/trial/runner.d:456 trial.interfaces.SuiteResult[] trial.runner.LifeCycleListeners.execute(ref const(trial.interfaces.TestCase)) [0x86773fd] lifecycle/trial/runner.d:284 trial.interfaces.SuiteResult[] trial.runner.runTests(const(trial.interfaces.TestCase)[], immutable(char)[]) [0x86768a7] lifecycle/trial/interfaces.d:477 void trial.interfaces.__unittestL464_146() [0x8655f7a] ??:? void trial.interfaces.__modtest() [0x86589b0] ??:? int core.runtime.runModuleUnitTests().__foreachbody2(object.ModuleInfo*) [0x8770420] ??:? int object.ModuleInfo.opApply(scope int delegate(object.ModuleInfo*)).__lambda2(immutable(object.ModuleInfo*)) [0x8745e20] ??:? int rt.minfo.moduleinfos_apply(scope int delegate(immutable(object.ModuleInfo*))).__foreachbody2(ref rt.sections_elf_shared.DSO) [0x874f2ca] */ }