forked from SumRndmDde/evil-haxe
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
379 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
-cp src | ||
-main Main | ||
--interp | ||
-D use-rtti-doc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
@:autoBuild(Macro.buildTestCase()) | ||
class DisplayTestCase { | ||
var ctx:DisplayTestContext; | ||
var methods:Array<Void->Void>; | ||
var numTests:Int; | ||
var numFailures:Int; | ||
var testName:String; | ||
|
||
// api | ||
inline function pos(name) return ctx.pos(name); | ||
inline function field(pos) return ctx.field(pos); | ||
inline function toplevel(pos) return ctx.toplevel(pos); | ||
inline function type(pos) return ctx.type(pos); | ||
inline function position(pos) return ctx.position(pos); | ||
inline function usage(pos) return ctx.usage(pos); | ||
inline function range(pos1, pos2) return ctx.range(pos1, pos2); | ||
|
||
function assert(v:Bool) if (!v) throw "assertion failed"; | ||
|
||
function eq(expected:String, actual:String, ?pos:haxe.PosInfos) { | ||
numTests++; | ||
if (expected != actual) { | ||
numFailures++; | ||
report("Assertion failed", pos); | ||
report("Expected: " + expected, pos); | ||
report("Actual: " + actual, pos); | ||
} | ||
} | ||
|
||
function arrayEq(expected:Array<String>, actual:Array<String>, ?pos:haxe.PosInfos) { | ||
numTests++; | ||
var leftover = expected.copy(); | ||
for (actual in actual) { | ||
if (!leftover.remove(actual)) { | ||
numFailures++; | ||
report("Result not part of expected Array:", pos); | ||
report(actual, pos); | ||
} | ||
} | ||
for (leftover in leftover) { | ||
numFailures++; | ||
report("Expected result was not part of actual Array:", pos); | ||
report(leftover, pos); | ||
return; | ||
} | ||
} | ||
|
||
function report(message, pos:haxe.PosInfos) { | ||
haxe.Log.trace(message, pos); | ||
} | ||
|
||
public function run() { | ||
for (method in methods) { | ||
method(); | ||
} | ||
return { | ||
testName: testName, | ||
numTests: numTests, | ||
numFailures: numFailures | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
using StringTools; | ||
|
||
class HaxeInvocationException { | ||
|
||
public var message:String; | ||
public var fieldName:String; | ||
public var arguments:Array<String>; | ||
public var source:String; | ||
|
||
public function new(message:String, fieldName:String, arguments:Array<String>, source:String) { | ||
this.message = message; | ||
this.fieldName = fieldName; | ||
this.arguments = arguments; | ||
this.source = source; | ||
} | ||
} | ||
|
||
class DisplayTestContext { | ||
var source:File; | ||
var markers:Map<Int,Int>; | ||
var fieldName:String; | ||
|
||
public function new(path:String, fieldName:String, source:String, markers:Map<Int,Int>) { | ||
this.fieldName = fieldName; | ||
this.source = new File(path, source); | ||
this.markers = markers; | ||
} | ||
|
||
public function pos(id:Int):Int { | ||
var r = markers[id]; | ||
if (r == null) throw "No such marker: " + id; | ||
return r; | ||
} | ||
|
||
public function range(pos1:Int, pos2:Int) { | ||
return normalizePath(source.formatPosition(pos(pos1), pos(pos2))); | ||
} | ||
|
||
public function field(pos:Int):String { | ||
return callHaxe('$pos'); | ||
} | ||
|
||
public function toplevel(pos:Int):String { | ||
return callHaxe('$pos'); | ||
} | ||
|
||
public function type(pos:Int):String { | ||
return extractType(callHaxe('$pos@type')); | ||
} | ||
|
||
public function positions(pos:Int):Array<String> { | ||
return extractPositions(callHaxe('$pos@position')); | ||
} | ||
|
||
public function position(pos:Int):String { | ||
return positions(pos)[0]; | ||
} | ||
|
||
public function usage(pos:Int):Array<String> { | ||
return extractPositions(callHaxe('$pos@usage')); | ||
} | ||
|
||
function callHaxe(displayPart:String):String { | ||
var args = [ | ||
"-cp", "src", | ||
"-D", "display-stdin", | ||
"--display", | ||
source.path + "@" + displayPart, | ||
]; | ||
var stdin = source.content; | ||
var proc = new sys.io.Process("haxe", args); | ||
proc.stdin.writeString(stdin); | ||
proc.stdin.close(); | ||
var stdout = proc.stdout.readAll(); | ||
var stderr = proc.stderr.readAll(); | ||
var exit = proc.exitCode(); | ||
var success = exit == 0; | ||
var s = stderr.toString(); | ||
if (!success || s == "") { | ||
throw new HaxeInvocationException(s, fieldName, args, stdin); | ||
} | ||
return s; | ||
} | ||
|
||
static function extractType(result:String) { | ||
var xml = Xml.parse(result); | ||
xml = xml.firstElement(); | ||
if (xml.nodeName != "type") { | ||
return null; | ||
} | ||
return StringTools.trim(xml.firstChild().nodeValue); | ||
} | ||
|
||
static function extractPositions(result:String) { | ||
var xml = Xml.parse(result); | ||
xml = xml.firstElement(); | ||
if (xml.nodeName != "list") { | ||
return null; | ||
} | ||
var ret = []; | ||
for (xml in xml.elementsNamed("pos")) { | ||
ret.push(normalizePath(xml.firstChild().nodeValue.trim())); | ||
} | ||
return ret; | ||
} | ||
|
||
static function normalizePath(p:String):String { | ||
if (!haxe.io.Path.isAbsolute(p)) { | ||
p = Sys.getCwd() + p; | ||
} | ||
if (Sys.systemName() == "Windows") { | ||
// on windows, haxe returns lowercase paths with backslashes | ||
p = p.replace("/", "\\"); | ||
p = p.toLowerCase(); | ||
} | ||
return p; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
class File { | ||
public var content(default,null):String; | ||
public var path(default,null):String; | ||
var lines:Array<Int>; | ||
|
||
public function new(path:String, content:String) { | ||
this.path = path; | ||
this.content = content; | ||
initLines(); | ||
} | ||
|
||
function initLines() { | ||
lines = []; | ||
// составляем массив позиций начала строк | ||
var s = 0, p = 0; | ||
while (p < content.length) { | ||
inline function nextChar() return StringTools.fastCodeAt(content, p++); | ||
inline function line() { lines.push(s); s = p; }; | ||
switch (nextChar()) { | ||
case "\n".code: | ||
line(); | ||
case "\r".code: | ||
p++; | ||
line(); | ||
} | ||
} | ||
} | ||
|
||
function findLine(pos:Int):{line:Int, pos:Int} { | ||
function loop(min, max) { | ||
var mid = (min + max) >> 1; | ||
var start = lines[mid]; | ||
return | ||
if (mid == min) | ||
{line: mid, pos: pos - start}; | ||
else if (start > pos) | ||
loop(min, mid); | ||
else | ||
loop(mid, max); | ||
} | ||
return loop(0, lines.length); | ||
} | ||
|
||
public function formatPosition(min:Int, max:Int):String { | ||
var start = findLine(min); | ||
var end = findLine(max); | ||
var pos = | ||
if (start.line == end.line) { | ||
if (start.pos == end.pos) | ||
'character ${start.pos}'; | ||
else | ||
'characters ${start.pos}-${end.pos}'; | ||
} else { | ||
'lines ${start.line + 1}-${end.line + 1}'; | ||
} | ||
return '$path:${start.line + 1}: $pos'; | ||
} | ||
|
||
public static inline function read(path:String) { | ||
return new File(path, sys.io.File.getContent(path)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import haxe.macro.Context; | ||
import haxe.macro.Expr; | ||
|
||
class Macro { | ||
static function buildTestCase():Array<Field> { | ||
var fields = Context.getBuildFields(); | ||
var markerRe = ~/{-(\d+)-}/g; | ||
var testCases = []; | ||
var c = Context.getLocalClass().get(); | ||
for (field in fields) { | ||
var markers = []; | ||
var posAcc = 0; | ||
var doc = (c.pack.length > 0 ? "package " + c.pack.join(".") + ";\n" : "") + field.doc; | ||
var src = markerRe.map(doc, function(r) { | ||
var p = r.matchedPos(); | ||
var name = r.matched(1); | ||
var pos = p.pos - posAcc; | ||
posAcc += p.len; | ||
markers.push(macro $v{Std.parseInt(name)} => $v{pos}); | ||
return ""; | ||
}); | ||
testCases.push(macro function() { | ||
ctx = new DisplayTestContext($v{Context.getPosInfos(c.pos).file}, $v{field.name}, $v{src}, $a{markers}); | ||
$i{field.name}(); | ||
}); | ||
} | ||
|
||
fields.push((macro class { | ||
public function new() { | ||
testName = $v{c.name}; | ||
numTests = 0; | ||
numFailures = 0; | ||
this.methods = $a{testCases}; | ||
} | ||
}).fields[0]); | ||
|
||
return fields; | ||
} | ||
|
||
macro static public function getCases(pack:String) { | ||
var path = Context.resolvePath(pack); | ||
var cases = []; | ||
for (file in sys.FileSystem.readDirectory(path)) { | ||
var p = new haxe.io.Path(file); | ||
if (p.ext == "hx") { | ||
var tp = {pack: [pack], name: p.file}; | ||
cases.push(macro new $tp()); | ||
} | ||
} | ||
return macro $a{cases}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
class Main { | ||
static function main() { | ||
var tests = Macro.getCases("cases"); | ||
var numTests = 0; | ||
var numFailures = 0; | ||
for (test in tests) { | ||
try { | ||
var result = test.run(); | ||
numTests += result.numTests; | ||
numFailures += result.numFailures; | ||
Sys.println('${result.testName}: ${result.numTests} tests, ${result.numFailures} failures'); | ||
} catch(e:DisplayTestContext.HaxeInvocationException) { | ||
Sys.println("Error: " + e.message); | ||
Sys.println("Field name: " + e.fieldName); | ||
Sys.println("Arguments: " + e.arguments.join(" ")); | ||
Sys.println("Source: " + e.source); | ||
numTests++; | ||
numFailures++; | ||
} | ||
} | ||
Sys.println('Finished with $numTests tests, $numFailures failures'); | ||
Sys.exit(numFailures == 0 ? 0 : 1); | ||
} | ||
} |
Oops, something went wrong.