trial.stackresult 308/313(98%) 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
390
400
410
420
432
442
452
460
472
480
492
500
510
520
530
541
550
563
570
580
590
600
612
620
630
640
650
660
671
681
690
702
710
720
730
740
750
764
770
784
790
803
810
823
830
842
850
860
876
880
891
900
910
923
930
941
950
960
974
980
990
1000
1010
1020
1031
1041
1050
1062
1072
1082
1090
1100
1110
1120
1130
1141
1151
1160
1172
1182
1192
1200
1210
1220
1230
1240
1250
1260
1270
1280
1290
1300
1310
13219
13319
1340
13519
13619
13719
1381494
1390
140491
1410
14226
1430
1440
145491
1460
14725
1480
1490
150491
1510
15218
1530
154473
1550
1560
15719
15819
15919
1600
16119
16219
1630
16419
1650
1664
1670
1680
16915
1700
1711483
1720
1730
1740
1750
1760
1770
1781
1790
1802
1810
1820
1832
1840
1852
1860
1870
1880
1892
1900
1910
1920
1930
1940
1950
1960
1970
1980
1990
2000
2010
2020
2030
2040
2050
2063
2070
2083
2090
21038
21138
21238
2130
2140
2150
2160
2170
2180
2190
22095
22188
2220
2230
2240
2250
2260
2270
2280
2290
2306
2310
232243
2330
23477
2350
2360
2376
2380
2390
2400
2410
2420
2431
2441
2450
2461
2470
24835
2490
25011
2510
2523
2530
2540
2550
2568
2570
2580
25911
2600
2610
2621
2630
2640
2650
2660
2670
2680
2690
2701
2710
2720
2730
2741
2750
2760
2770
2781
2790
2800
2811
2820
2832
2842
2850
2860
2870
2880
2890
2900
2910
2920
2930
2940
2950
2960
2970
2980
2990
3000
3010
3020
3030
3040
3050
3060
3070
3080
3090
3100
3110
3120
3130
3140
3150
3160
3170
3180
3190
3200
3210
3220
3230
3240
3250
3260
3270
3280
3290
3300
3310
3320
3330
3340
3350
3360
3370
3380
3390
3400
3410
3420
3430
3440
3450
3460
3470
3480
3490
3500
3510
3520
3530
3540
3550
3560
3570
3580
3590
3600
3610
3620
36386
3640
36586
3661
3670
3680
36986
370172
3710
37286
37311
3740
3750
37686
3774
3780
3790
38086
38171
3820
38371
38470
3850
3860
38771
3880
3890
39086
3910
3920
3930
3940
3950
39614
3971
3980
3990
40014
40128
4020
40314
4044
4054
4060
4070
40814
4094
4104
4110
4120
41314
4149
4159
4160
4179
4188
4198
4200
4210
4229
4230
4240
4250
4260
4270
4280
4290
4300
4312
4320
4330
4340
4350
4360
4370
4380
4392
4400
4410
4420
4430
4440
4450
4460
4472
4480
4490
4500
4510
4520
4530
4540
4552
4560
4570
4580
4590
4600
4610
4620
4632
4640
4650
4660
4670
4680
4690
4700
4712
4720
4730
4740
4750
4760
4770
4780
4790
4800
4810
48218
4830
4840
4850
48617
4870
4880
4890
4900
4910
4920
4930
4940
4950
4960
4970
4980
4990
5000
5010
5020
5030
5040
5050
5060
5070
5080
5090
5101
5111
5120
5132
5140
5150
5160
5170
5180
5190
5200
5211
5221
5230
5242
5250
5260
5270
5280
5290
5300
5310
5321
5331
5340
5352
5360
5370
5380
5390
5400
5410
5420
5431
5441
5450
5462
5470
5480
5490
5500
5510
5520
5530
5541
5551
5560
5572
5580
5590
5600
5610
5620
5630
5640
5651
5661
5670
5682
5690
5700
5710
5720
5730
5740
5750
5760
5770
5780
5790
5800
5810
5820
5830
5840
5850
5860
58749
5880
58949
5900
5910
59298
5930
59449
5951
5961
5971
5981
5990
6001
6010
6020
6030
6040
6050
60648
6070
60896
6090
6100
61148
61248
61348
61448
6150
6161
6171
6181
6190
6201
6210
6220
6230
6240
6250
62647
6270
62894
62947
63047
6310
63293
6331
6340
6351
6360
6370
6380
6390
6400
64146
6420
64392
6440
64546
64646
64746
6480
64946
6500
65146
6520
6531
6541
6550
6560
65762
65830
65954
6606
6610
6626
6630
6640
6650
6660
6670
66840
6690
67080
6710
67240
67340
67440
67540
6760
67779
6781
6791
6801
6810
6821
6830
6840
6850
6860
68739
6880
68978
6900
69139
69239
69339
69439
6950
69636
69736
69836
69936
7000
70136
7020
7030
7040
7050
7063
7070
7086
7090
7103
7113
7120
7133
7143
7150
7163
7170
7180
7190
7200
7210
72249
7230
7240
7250
72649
7270
7280
7290
7300
7310
7320
7330
73448
7350
7360
7370
7380
7390
7400
7410
74247
7430
7440
7450
7460
7470
7480
7490
75046
7510
7520
7530
7540
7550
7560
7570
75840
7590
7600
7610
7620
7630
7640
7650
76639
7670
7680
7690
7700
7710
7720
7730
7743
7750
7760
7770
7780
7790
7800
7810
7820
7830
7840
7850
7861
7870
7881
7892
7902
7912
7922
7932
7940
7950
7960
7970
7980
7991
8000
8011
8022
8032
8042
8052
8062
8070
8080
8090
8100
8110
8121
8130
8141
8152
8162
8172
8182
8192
8202
8212
8220
8230
8240
8250
8260
8271
8280
8291
8300
8312
8322
8332
8342
8352
8360
8370
8380
8390
8400
8411
8420
8431
8440
8452
8462
8472
8482
8492
8500
8510
8520
8530
8540
8551
8560
8571
8580
8592
8602
8612
8622
8632
8640
8650
8660
8670
8681
8690
8701
8710
8722
8732
8742
8752
8762
8772
8782
8790
8800
8810
8820
8831
8841
8850
8862
8872
8882
8892
8902
8912
8922
8930
8940
8950
8960
8971
8981
8990
9002
9012
9022
9032
9042
9052
9062
9070
9080
9090
9100
9111
9121
9130
9142
9152
9162
9172
9182
9192
9202
9210
9220
9230
9240
9251
9261
9270
9282
9292
9302
9312
9322
9332
9342
9350
/++ 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) { version = Have_fluent_asserts_core; } 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) @safe { 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() @safe { 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..."); } } else { /// Used to display the stack class StackResult { 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() @safe { string result = "Stack trace:\n-------------------\n...\n"; foreach (frame; getFrames) { result ~= frame.toString ~ "\n"; } return result ~ "..."; } } } } /// 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 @safe { 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; } version(Have_fluent_asserts_core) { void print(ResultPrinter printer) @safe { 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) { version(Have_fluent_asserts_core): 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(""); }