Added more tests + benchmark works

This commit is contained in:
NeeEoo
2024-04-23 06:28:28 +02:00
parent b105ac0453
commit 049daf4b0d
8 changed files with 262 additions and 60 deletions
+36
View File
@@ -0,0 +1,36 @@
package;
@:access(hscript.Interp)
@:access(hscript.Parser)
class HScriptRunner {
public var interp:Interp;
public var headerCode:String = "";
public var tailCode:String = "";
public var clearPrevious:Bool = true;
public function new() {}
public function getNewInterp() {
var interp = Util.getInterp();
interp.errorHandler = Util.errorHandler;
return interp;
}
public function setup() {
interp = getNewInterp();
}
public function run() {}
public function teardown() {}
public function execute(script:String):Dynamic {
var interp = clearPrevious ? getNewInterp() : this.interp;
var expr = Util.parse(headerCode + script + tailCode);
if(expr == null)
return "ERROR";
if (clearPrevious)
return interp.execute(expr);
else
return interp.exprReturn(expr);
}
}
+3 -1
View File
@@ -11,7 +11,8 @@ class Main {
#if BENCHMARK
Sys.println("Running benchmark");
new Benchmark("Test", 1000);
//new Benchmark("Test", 1000);
new TestBenchmark();
#else
Sys.println("Beginning tests");
if(!Main.SHOW_KNOWN_BUGS) {
@@ -34,6 +35,7 @@ class Main {
runTest("String", new StringCase());
runTest("StringBuf", new StringBufCase());
runTest("StringTools", new StringToolsCase());
runTest("SwitchStatement", new SwitchCase());
// TODO: UnicodeCase.hx?
// TODO: UnicodeStringCase.hx?
Util.printTestResults();
+20 -7
View File
@@ -75,14 +75,14 @@ class Util {
}
public static function printTestResults() {
Sys.println("-----------------------------RESULTS-----------------------------");
Sys.println(Util.getTitle('RESULTS'));
Sys.println("Total Units: " + totalTestUnits);
Sys.println("Total tests passed: " + passedTestUnits);
Sys.println("Total tests failed: " + failedTestUnits);
if(skippedKnownBugs > 0)
Sys.println("Skipped known bugs: " + skippedKnownBugs);
//Sys.println("Finished unit tests " + currentTestPath.pop());
Sys.println("-----------------------------RESULTS-----------------------------");
Sys.println(Util.getTitle('RESULTS'));
}
public static function parse(str:String) {
@@ -162,9 +162,8 @@ class Util {
}
public static function deepCompareArrays(a1: Array<Dynamic>, a2: Array<Dynamic>): Bool {
if (a1.length != a2.length) {
if (a1.length != a2.length)
return false;
}
for (i in 0...a1.length) {
var item1 = a1[i];
@@ -173,11 +172,25 @@ class Util {
if (Std.isOfType(item1, Array) && Std.isOfType(item2, Array)) {
if (!deepCompareArrays(item1, item2))
return false;
} else if (item1 != item2) {
} else if (item1 != item2)
return false;
}
}
return true;
}
public static function roundDecimal(Value:Float, Precision:Int):Float {
var mult:Float = 1;
for (i in 0...Precision)
mult *= 10;
return Math.fround(Value * mult) / mult;
}
public inline static function roundWith(Value:Float, Mult:Int):Float {
return Math.fround(Value * Mult) / Mult;
}
public static function getTitle(title:String, ?dashsLen:Int = 46) {
var l = StringTools.lpad("", "-", Std.int((dashsLen - title.length - 2)/2));
return l + ' $title ' + l;
}
}
+55 -20
View File
@@ -1,36 +1,71 @@
package benchmark;
class Benchmark {
public var times:Array<Float> = [];
import hscript.Expr;
class Benchmark extends HScriptRunner {
public var haxeTimes:Array<Float> = [];
public var haxeTotalTime:Float = 0;
public var hscriptTimes:Array<Float> = [];
public var hscriptTotalTime:Float = 0;
public function new(name:String, iterations:Int) {
times = cast new haxe.ds.Vector<Float>(iterations);
super();
haxeTimes = cast new haxe.ds.Vector<Float>(iterations);
hscriptTimes = cast new haxe.ds.Vector<Float>(iterations);
for (i in 0...iterations) {
var startTime:Float = Util.getTime();
benchmark();
var endTime:Float = Util.getTime();
times[i] = endTime-startTime;
reset();
var haxeStartTime:Float = Util.getTime();
haxeBenchmark();
var haxeEndTime:Float = Util.getTime();
haxeTimes[i] = haxeEndTime-haxeStartTime;
reset();
var hscriptStartTime:Float = Util.getTime();
hscriptBenchmark();
var hscriptEndTime:Float = Util.getTime();
hscriptTimes[i] = hscriptEndTime-hscriptStartTime;
}
times.sort(Reflect.compare);
var total:Float = 0;
for (time in times)
total += time;
haxeTimes.sort(Reflect.compare);
hscriptTimes.sort(Reflect.compare);
Sys.println('--------------------$name BENCHMARK--------------------');
for (time in haxeTimes) haxeTotalTime += time;
for (time in hscriptTimes) hscriptTotalTime += time;
if (total == 0 || times.length <= 0) {
Sys.println(Util.getTitle('$name BENCHMARK'));
if ((haxeTotalTime == 0 || hscriptTotalTime == 0) || (haxeTimes.length <= 0 || hscriptTimes.length <= 0)) {
Sys.println('BENCHMARK UNNOTICABLE, TOOK 0 SECONDS');
} else {
Sys.println('Running $iterations times...');
Sys.println('Lowest Time: ${Util.convertToReadableTime(times[0])}');
Sys.println('Average Time: ${Util.convertToReadableTime(total/iterations)}');
Sys.println('Highest Time: ${Util.convertToReadableTime(times[times.length-1])}');
var haxeWon = hscriptTotalTime > haxeTotalTime;
Sys.println('${haxeWon ? "Haxe" : "Hscript"} was faster overall (Faster by: ${Util.roundWith((haxeWon ? hscriptTotalTime/haxeTotalTime : haxeTotalTime/hscriptTotalTime), 100)}x)');
Sys.println('Haxe average time: ${Util.convertToReadableTime(haxeTotalTime/iterations)} (Highest: ${haxeTimes[haxeTimes.length-1]})');
Sys.println('Hscript average time: ${Util.convertToReadableTime(hscriptTotalTime/iterations)} (Highest: ${hscriptTimes[haxeTimes.length-1]})');
}
Sys.println('--------------------$name BENCHMARK--------------------');
Sys.println(Util.getTitle('$name BENCHMARK'));
}
public function benchmark() {}
public function reset() {}
public var expr:Expr;
public inline function cacheExpr(script:String) {
interp = getNewInterp();
interp.variables.set("self", this);
interp.scriptObject = this;
expr = Util.parse(headerCode + script + tailCode);
}
public override function execute(script:String):Dynamic {
if (expr == null)
cacheExpr(script);
return interp.execute(expr);
}
public function haxeBenchmark() {}
public function hscriptBenchmark() {}
}
+24
View File
@@ -0,0 +1,24 @@
package benchmark;
@:dce(off)
class TestBenchmark extends Benchmark {
public function new() {
super("Test", 5000);
}
public override function reset() {
super.reset();
a = [];
if(interp != null)
interp.variables.remove("a");
}
public var a:Array<Float> = [];
public override function haxeBenchmark() {
for (i in 0...1000) a.push(i);
}
public override function hscriptBenchmark() {
execute("var a:Array<Float> = []; for (i in 0...1000) a.push(i);");
}
}
+89
View File
@@ -64,6 +64,95 @@ var c = 3;
assertEq("a << b >> c", a << b >> c);
assertEq("a >>> b << c", a >>> b << c);
headerCode = "
var a = null;
var b = 'hello';
var c = 'world';
var d = '!';
";
var a = null;
var b = 'hello';
var c = 'world';
var d = '!';
assertEq("a + b", a + b);
#if (haxe >= "4.3.0")
assertEq("a ?? b", a ?? b);
assertEq("a ?? b ?? c", a ?? b ?? c);
assertEq("a ?? b ?? c ?? d", a ?? b ?? c ?? d);
#else
Sys.println("Tests are inaccurate with Haxe 4.2.x");
assertEq("a ?? b", nc(a, b));
assertEq("a ?? b ?? c", nc(a, nc(b, c)));
assertEq("a ?? b ?? c ?? d", nc(a, nc(b, nc(c, d))));
#end
var tests:Array<Array<Dynamic>> = [
[null, "null"],
[{}, "{}"],
[{a: 1}, "{a: 1}"],
[{a: {b: 1}}, "{a: {b: 1}}"],
[{a: {b: {c: 1}}}, "{a: {b: {c: 1}}}"],
[{a: {b: {c: {d: 1}}}}, "{a: {b: {c: {d: 1}}}}"]
];
for(code in tests) {
headerCode = 'var a = ${code[1]};';
var a = code[0];
#if (haxe >= "4.3.0")
assertEq("a?.b", a?.b);
assertEq("a?.b?.c", a?.b?.c);
assertEq("a?.b?.c?.d", a?.b?.c?.d);
#else
assertEq("a?.b", nf(a, b));
assertEq("a?.b?.c", nf(nf(a, b), c));
assertEq("a?.b?.c?.d", nf(nf(nf(a, b), c), d));
#end
}
headerCode = "
var a = null;
var b = 'hello';
";
var a = null;
var b = 'hello';
#if (haxe >= "4.3.0")
a ??= b;
assertEq("a ?"+"?= b; a", a);
#else
if(a == null) a = b;
assertEq("a ?"+"?= b; a", a);
#end
headerCode = "
var a = 'test';
var b = 'hello';
";
var a = 'test';
var b = 'hello';
#if (haxe >= "4.3.0")
a ??= b;
assertEq("a ?"+"?= b; a", a);
#else
if(a == null) a = b;
assertEq("a ?"+"?= b; a", a);
#end
}
inline function nc(a:Dynamic, b:Dynamic):Dynamic {
return (a == null) ? b : a;
}
inline function nf(a:Dynamic, b:String):Dynamic {
return (a == null) ? null : Reflect.field(a, b);
}
override function teardown() {
+33
View File
@@ -0,0 +1,33 @@
package tests;
class SwitchCase extends TestCase {
override function setup() {
super.setup();
}
override function run() {
assertEq("switch(1) { case 1: 1; case 2: 2; default: -1; }", switch(1) { case 1: 1; case 2: 2; default: -1; });
assertEq("switch(3) { case 1: 1; case 2: 2; case 3: 3; default: -1; }", switch(3) { case 1: 1; case 2: 2; case 3: 3; default: -1; });
assertEq("switch(3) { case 1: 1; case 2: 2; case 3: 3; default: -1; }", switch(3) { case 1: 1; case 2: 2; case 3: 3; default: -1; });
assertEq("switch(6) { case 1: 1; case 2: 2; case 3: 3; default: -1; }", switch(6) { case 1: 1; case 2: 2; case 3: 3; default: -1; });
// TODO: add https://haxe.org/manual/lf-pattern-matching-enums.html
// TODO: add https://haxe.org/manual/lf-pattern-matching-variable-capture.html (including case _)
// TODO: add https://haxe.org/manual/lf-pattern-matching-structure.html
// TODO: add https://haxe.org/manual/lf-pattern-matching-array.html
// TODO: add https://haxe.org/manual/lf-pattern-matching-guards.html
// TODO: add https://haxe.org/manual/lf-pattern-matching-tuples.html
// TODO: add https://haxe.org/manual/lf-pattern-matching-extractors.html
// TODO: detect https://haxe.org/manual/lf-pattern-matching-exhaustiveness.html
// TODO: maybe? https://haxe.org/manual/lf-pattern-matching-unused.html
// TODO: add https://haxe.org/manual/lf-pattern-matching-single.html
assertEq("switch(5) { case 1|4: 'error'; case 5: 0; default: -1; }", switch(5) { case 1|4: 'error'; case 5: 0; default: -1; });
assertEq("switch(5) { case 1|4: 'error'; default: -1; }", switch(5) { case 1|4: 'error'; default: -1; });
assertEq("switch(5) { case 1,4: 'error'; case 5: 0; default: -1; }", switch(5) { case 1,4: 'error'; case 5: 0; default: -1; });
}
override function teardown() {
super.teardown();
}
}
+2 -32
View File
@@ -2,46 +2,16 @@ package tests;
@:access(hscript.Interp)
@:access(hscript.Parser)
class TestCase {
public var interp:Interp;
public var headerCode:String = "";
public var tailCode:String = "";
public var clearPrevious:Bool = true;
public function new() {}
public function getNewInterp() {
var interp = Util.getInterp();
interp.errorHandler = Util.errorHandler;
return interp;
}
public function setup() {
interp = getNewInterp();
}
public function run() {}
public function teardown() {}
class TestCase extends HScriptRunner {
public function assertEq(script:String, expected:Dynamic, ?message:String) {
if(message == null)
message = script;
Util.assertEq(execute(headerCode + script + tailCode), expected, message);
}
public function assertNeq(script:String, expected:Dynamic, ?message:String) {
if(message == null)
message = script;
Util.assertNeq(execute(headerCode + script + tailCode), expected, message);
}
public function execute(script:String):Dynamic {
var interp = clearPrevious ? getNewInterp() : this.interp;
var expr = Util.parse(headerCode + script + tailCode);
if(expr == null)
return "ERROR";
if (clearPrevious)
return interp.execute(expr);
else
return interp.exprReturn(expr);
}
}