Skip to content

Commit

Permalink
add initial display tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Simn committed Apr 22, 2016
1 parent a56bd9d commit b735417
Show file tree
Hide file tree
Showing 9 changed files with 379 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,4 @@ tests/misc/projects/Issue4070/cpp/
/tests/misc/eventLoop/dump
/tests/misc/eventLoop/eventLoop.py
/tests/misc/eventLoop/php
tests/display/.vscode/
4 changes: 4 additions & 0 deletions tests/RunCi.hx
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,7 @@ class RunCi {
static var sysDir(default, never) = cwd + "sys/";
static var optDir(default, never) = cwd + "optimization/";
static var miscDir(default, never) = cwd + "misc/";
static var displayDir(default, never) = cwd + "display/";
static var gitInfo(get, null):{repo:String, branch:String, commit:String, timestamp:Float, date:String};
static function get_gitInfo() return if (gitInfo != null) gitInfo else gitInfo = {
repo: switch (ci) {
Expand Down Expand Up @@ -915,6 +916,9 @@ class RunCi {
case Macro:
runCommand("haxe", ["compile-macro.hxml"].concat(args));

changeDirectory(displayDir);
runCommand("haxe", ["build.hxml"]);

changeDirectory(miscDir);
getCsDependencies();
getPythonDependencies();
Expand Down
4 changes: 4 additions & 0 deletions tests/display/build.hxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-cp src
-main Main
--interp
-D use-rtti-doc
62 changes: 62 additions & 0 deletions tests/display/src/DisplayTestCase.hx
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
}
}
}
118 changes: 118 additions & 0 deletions tests/display/src/DisplayTestContext.hx
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;
}
}
62 changes: 62 additions & 0 deletions tests/display/src/File.hx
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));
}
}
52 changes: 52 additions & 0 deletions tests/display/src/Macro.hx
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};
}
}
24 changes: 24 additions & 0 deletions tests/display/src/Main.hx
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);
}
}
Loading

0 comments on commit b735417

Please sign in to comment.