1 module support;
2 
3 import dmd.frontend : DiagnosticReporter;
4 
5 /// UDA used to indicate a function should be run before each test.
6 enum beforeEach;
7 
8 /// UDA used to indicate a function should be run after each test.
9 enum afterEach;
10 
11 /// Returns: the default import paths, i.e. for Phobos and druntime.
12 string[] defaultImportPaths()
13 {
14     import std.path : buildNormalizedPath, buildPath, dirName;
15     import std.process : environment;
16 
17     enum dlangDir = __FILE_FULL_PATH__.dirName.buildNormalizedPath("..", "..", "..");
18     enum druntimeDir = dlangDir.buildPath("druntime", "import");
19     enum phobosDir = dlangDir.buildPath("phobos");
20 
21     return [
22         environment.get("DRUNTIME_PATH", druntimeDir),
23         environment.get("PHOBOS_PATH", phobosDir)
24     ];
25 }
26 
27 /**
28  * Strips indentation and extra newlines in delimited strings.
29  *
30  * This is indented to be used on delimited string literals. It will strip the
31  * indentation and remove the first and the last newlines.
32  *
33  * Params:
34  *  str = the delimited string to strip
35  *
36  * Return: the stripped string
37  */
38 string stripDelimited(string str)
39 {
40     import std..string : chomp, outdent;
41     import dmd.root..string : stripLeadingLineTerminator;
42 
43     return str
44         .stripLeadingLineTerminator
45         .outdent
46         .chomp;
47 }
48 
49 /**
50  * Returns `true` if the given code compiles.
51  *
52  * This will run the frontend up to, including, the semantic analysis.
53  *
54  * Params:
55  *  code = the code to compile
56  *  filename = the filename to use when compiling the code
57  *
58  * Returns: `true` if the given code compiles
59  */
60 bool compiles(string code, string filename = "test.d")
61 {
62     import dmd.globals : global;
63     import std.algorithm : each;
64 
65     import dmd.frontend : addImport, fullSemantic, parseModule;
66 
67     defaultImportPaths.each!addImport;
68 
69     auto t = parseModule(filename, code);
70 
71     if (t.diagnostics.hasErrors)
72         return false;
73 
74     t.module_.fullSemantic();
75 
76     return global.errors == 0;
77 }
78 
79 class NoopDiagnosticReporter : DiagnosticReporter
80 {
81     import core.stdc.stdarg : va_list;
82     import dmd.globals : Loc;
83 
84     override int errorCount() { return 0; }
85     override int warningCount() { return 0; }
86     override int deprecationCount() { return 0; }
87     override bool error(const ref Loc loc, const(char)* format, va_list, const(char)* p1, const(char)* p2) { return true; }
88     override bool errorSupplemental(const ref Loc loc, const(char)* format, va_list, const(char)* p1, const(char)* p2) { return true; }
89     override bool warning(const ref Loc loc, const(char)* format, va_list, const(char)* p1, const(char)* p2) { return true; }
90     override bool warningSupplemental(const ref Loc loc, const(char)* format, va_list, const(char)* p1, const(char)* p2) { return true; }
91     override bool deprecation(const ref Loc loc, const(char)* format, va_list, const(char)* p1, const(char)* p2) { return true; }
92     override bool deprecationSupplemental(const ref Loc loc, const(char)* format, va_list, const(char)* p1, const(char)* p2) { return true; }
93 }