WIP TESTING + BENCHMARK CODE

This commit is contained in:
NeeEoo
2024-04-23 03:25:17 +02:00
parent b96e6c8149
commit f512ac4cde
16 changed files with 669 additions and 1 deletions
-1
View File
@@ -185,7 +185,6 @@ class Parser {
public function parseString( s : String, ?origin : String = "hscript" ) {
initParser(origin);
if(s == "") s = "0;"; // fixing crash with empty file
input = s;
readPos = 0;
var a = new Array();
+1
View File
@@ -0,0 +1 @@
bin/*
+9
View File
@@ -0,0 +1,9 @@
# Haxe project
This is an example Haxe project scaffolded by Visual Studio Code.
Without further changes the structure is following:
* `src/Main.hx`: Entry point Haxe source file
* `build.hxml`: Haxe command line file used to build the project
* `README.md`: This file
+25
View File
@@ -0,0 +1,25 @@
# Generic Haxe stuffs to make the project compile
-cp src
-cp ../
-D analyzer-optimize
-main Main
# Libraries (MAKE SURE TO KEEP THIS IN SYNC WITH ALL BUILD FILES)
# --library hxcpp-debug-server
# Defines (MAKE SURE TO KEEP THIS IN SYNC WITH ALL BUILD FILES)
--define hscriptPos
--define HXCPP_CHECK_POINTER
--define HXCPP_STACK_LINE
--define HXCPP_DEBUG_LINK
--dce no
# File Specific Defines
--define linux
# Copying the assets from source code to bin folder
--cmd rm -rf bin/cpp/assets
--cmd cp -r assets bin/cpp/assets
--cpp bin/cpp
--cmd cd bin/cpp
--cmd ./Main
+27
View File
@@ -0,0 +1,27 @@
# Generic Haxe stuffs to make the project compile
-cp src
-cp ../
-D analyzer-optimize
-main Main
# Libraries (MAKE SURE TO KEEP THIS IN SYNC WITH ALL BUILD FILES)
# --library hscript-improved
# --library hxcpp-debug-server
# Defines (MAKE SURE TO KEEP THIS IN SYNC WITH ALL BUILD FILES)
--define hscriptPos
--define HXCPP_CHECK_POINTER
--define HXCPP_STACK_LINE
--define HXCPP_DEBUG_LINK
--dce no
# File Specific Defines
--define macos
--define mac
# Copying the assets from source code to bin folder
--cmd rm -rf bin/cpp/assets
--cmd cp -r assets bin/cpp/assets
--cpp bin/cpp
--cmd cd bin/cpp
--cmd ./Main
+35
View File
@@ -0,0 +1,35 @@
#if BENCHMARK
import benchmark.*;
#else
import tests.*;
#end
class Main {
public static var SHOW_KNOWN_BUGS:Bool = false;
static function main() {
#if BENCHMARK
Sys.println("Running benchmark");
new Benchmark("Test", 1000);
#else
Sys.println("Beginning tests");
runTest("Array", new ArrayCase());
runTest("BinOp", new BinOpCase());
runTest("EvalOrder", new EvalOrderCase());
runTest("Math", new MathCase());
runTest("Misc", new MiscCase());
Util.printTestResults();
#end
}
#if !BENCHMARK
static function runTest(name:String, test:TestCase) {
Util.startUnitTest("Math");
test.setup();
test.run();
test.teardown();
Util.endUnitTest();
}
#end
}
+124
View File
@@ -0,0 +1,124 @@
import hscript.Expr.Error;
using StringTools;
class Util {
public static function assert(value:Bool, message:String) {
if (value) {
passedTestUnits++;
} else {
Sys.println("Assertion failed: " + message);
failedTestUnits++;
}
}
public static function assertEq(value:Dynamic, expected:Dynamic, message:String) {
if (value == expected) {
passedTestUnits++;
} else {
Sys.println("Assertion failed: " + message + " Expected: " + expected + " Got: " + value);
failedTestUnits++;
}
}
public static function assertNeq(value:Dynamic, expected:Dynamic, message:String) {
if (value != expected) {
passedTestUnits++;
} else {
Sys.println("Assertion failed: " + message + " Expected: " + expected + " Got: " + value);
failedTestUnits++;
}
}
static var currentTestPath:Array<String> = [];
static var totalTestUnits:Int = 0;
static var passedTestUnits:Int = 0;
static var failedTestUnits:Int = 0;
public static function startUnitTest(path:String) {
//Sys.println("Running unit tests " + path);
currentTestPath.push(path);
totalTestUnits++;
}
public static function endUnitTest() {
var path = currentTestPath.pop();
//Sys.println("Finished unit tests " + path);
}
public static function printTestResults() {
Sys.println("-----------------------------------------------------------");
Sys.println("Total Units: " + totalTestUnits);
Sys.println("Total tests passed: " + passedTestUnits);
Sys.println("Total tests failed: " + failedTestUnits);
//Sys.println("Finished unit tests " + currentTestPath.pop());
}
public static function parse(str:String) {
var p = new Parser();
p.allowTypes = true;
p.allowMetadata = true;
p.allowJSON = true;
return p.parseString(str);
}
public static function getInterp() {
var interp = new Interp();
//interp.importEnabled = true;
//interp.allowStaticVariables = true;
//interp.allowPublicVariables = true;
interp.variables.set("Math", Math);
interp.variables.set("Std", Std);
interp.variables.set("StringTools", StringTools);
return interp;
}
public static inline function getTime():Float {
return untyped __global__.__time_stamp();
}
// expandScientificNotation but its WAY too long to write out
public static function exScienceN(value:Float):String {
var parts = Std.string(value).split("e");
var coefficient = Std.parseFloat(parts[0]);
var exponent = parts.length > 1 ? Std.parseInt(parts[1]) : 0;
var result = "";
if (exponent > 0) {
result += StringTools.replace(Std.string(coefficient), ".", "");
var decimalLength = Std.string(coefficient).split(".")[1].length;
var additionalZeros:Int = Std.int(Math.abs(exponent - decimalLength));
result += StringTools.lpad("", "0", additionalZeros); // repeat
} else {
result += "0.";
var leadingZeros:Int = Std.int(Math.abs(exponent) - 1);
result += StringTools.lpad("", "0", leadingZeros); // repeat
result += StringTools.replace(Std.string(coefficient), ".", "");
}
return result;
}
public static function convertToReadableTime(seconds:Float) {
if (seconds >= 1) return seconds + " s";
var milliseconds = seconds * 1000; // 1 second = 1,000 ms
if (milliseconds >= 1) return milliseconds + " ms";
var microseconds = seconds * 1000000; // 1 second = 1,000,000 μs
if (microseconds >= 1) return microseconds + " μs";
var nanoseconds = seconds * 1000000000; // 1 second = 1,000,000,000 ns
return nanoseconds + " ns";
}
public static function errorHandler(error:hscript.Error) {
var fileName = error.origin;
var fn = '$fileName:${error.line}: ';
var err = error.toString();
if (err.startsWith(fn)) err = err.substr(fn.length);
Sys.println(fn + err);
//Logs.traceColored([
// Logs.logText(fn, GREEN),
// Logs.logText(err, RED)
//], ERROR);
}
}
+68
View File
@@ -0,0 +1,68 @@
package benchmark;
class Benchmark {
public var times:Array<Float> = [];
public function new(name:String, iterations:Int) {
times = 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;
}
times.sort(Reflect.compare);
var total:Float = 0;
for (time in times)
total += time;
Sys.println('--------------------$name BENCHMARK--------------------');
Sys.println('Running $iterations times...');
// Sys.println('Lowest Time: ${Util.exScienceN(times[0])}');
// Sys.println('Average Time: ${Util.exScienceN(total/iterations)}');
// Sys.println('Highest Time: ${Util.exScienceN(times[times.length-1])}');
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])}');
graph();
Sys.println('--------------------$name BENCHMARK--------------------');
}
public function graph() {
var size:{width:Int, height:Int} = {width: 20, height: 14};
var collumRange:Float = times[times.length-1]-times[0];
var counts:Array<Int> = cast new haxe.ds.Vector<Int>(size.width);
for (time in times) {
var index:Int = Std.int((time - times[0]) / (collumRange / size.width));
counts[index]++;
}
var normalizedCounts:Array<Float> = [for (count in counts) count / times.length];
var gridFilling:Array<Int> = [for (count in normalizedCounts) Math.round(count*size.height)];
trace(normalizedCounts,gridFilling);
for (y in 0...size.height) {
for (x in 0...size.width) {
Sys.print("*");
}
Sys.print("\n");
}
}
// public static function remapToRange(value:Float, start1:Float, stop1:Float, start2:Float, stop2:Float):Float
// {
// return start2 + (value - start1) * ((stop2 - start2) / (stop1 - start1));
// }
public function benchmark() {
var array:Array<Float> = [];
for (i in 0...10000)
array.push(Math.random());
}
}
+4
View File
@@ -0,0 +1,4 @@
import hscript.Interp;
import hscript.Parser;
import Util;
+19
View File
@@ -0,0 +1,19 @@
package tests;
class ArrayCase extends TestCase {
override function setup() {
super.setup();
}
override function run() {
assertEq("[].length", 0);
assertEq("[1].length", 1);
assertEq("[1,2,3].length", 3);
assertEq("var a = [];\na[4] = 1;\na.length", 5);
assertEq("var a = [];\na[4] = 1;\na[a.length] = 1;\na.length", 6);
}
override function teardown() {
super.teardown();
}
}
+72
View File
@@ -0,0 +1,72 @@
package tests;
class BinOpCase extends TestCase {
override function setup() {
super.setup();
headerCode = "
var a = 1;
var b = 2;
var c = 3;
";
//tailCode = "";
}
override function run() {
var a = 1;
var b = 2;
var c = 3;
assertEq("a + b", a + b);
assertEq("a - b", a - b);
assertEq("a * b", a * b);
assertEq("a / b", a / b);
assertEq("a % b", a % b);
assertEq("a & b", a & b);
assertEq("a | b", a | b);
assertEq("a ^ b", a ^ b);
assertEq("5 ^ 3", 5 ^ 3);
assertEq("a << b", a << b);
assertEq("a >> b", a >> b);
assertEq("a >>> b", a >>> b);
assertEq("a == b", a == b);
assertEq("a != b", a != b);
assertEq("a >= b", a >= b);
assertEq("a <= b", a <= b);
assertEq("a > b", a > b);
assertEq("a < b", a < b);
//assertEq("a || b", a || b);
//assertEq("a && b", a && b);
//assertEq("a is b", false);
// Order of operations
assertEq("a + b * c", a + b * c);
assertEq("a * b + c", a * b + c);
assertEq("a * (b + c)", a * (b + c));
assertEq("(a + b) * c", (a + b) * c);
assertEq("a / b / c", a / b / c);
assertEq("a % b % c", a % b % c);
assertEq("a & b & c", a & b & c);
assertEq("a | b | c", a | b | c);
assertEq("a ^ b ^ c", a ^ b ^ c);
assertEq("a << b << c", a << b << c);
assertEq("a >> b >> c", a >> b >> c);
assertEq("a >>> b >>> c", a >>> b >>> c);
// Precedence
assertEq("a + b + c", a + b + c);
assertEq("a + b - c", a + b - c);
assertEq("a * b / c", a * b / c);
assertEq("a / b * c", a / b * c);
assertEq("a % b | c", a % b | c);
assertEq("a & b ^ c", a & b ^ c);
assertEq("a << b >> c", a << b >> c);
assertEq("a >>> b << c", a >>> b << c);
}
override function teardown() {
super.teardown();
}
}
+178
View File
@@ -0,0 +1,178 @@
package tests;
class EvalOrderCase extends TestCase {
override function setup() {
super.setup();
headerCode = '
var a = 1;
var b = 2;
var c = 3;
function func(i1:Dynamic, i2:Dynamic, i3:Dynamic) {
return i1 + ";" + i2 + ";" + i3;
}
';
//tailCode = "";
}
override function run() {
var a = 1;
var b = 2;
var c = 3;
function func(i1:Dynamic, i2:Dynamic, i3:Dynamic) {
return i1 + ";" + i2 + ";" + i3;
}
assertEq("func(a, b, c)", func(a, b, c));
clearPrevious = true;
var i = 0;
assertEq("var i = 0; func(i++, i++, i++)", func(i++, i++, i++));
var i = 0;
assertEq("var i = 0; var a = [i++, i++, i++]; a.join(';')", [i++, i++, i++].join(";"));
var i = 0;
var obj = {
a: i++,
b: i++,
c: i++
}
assertEq("var i = 0; var obj = {
a: i++,
b: i++,
c: i++
}; func(obj.a, obj.b, obj.c)", func(obj.a, obj.b, obj.c));
var i = 0;
assertEq("var i = 0; func(i++, [i++, i++].join(';'), i++)", func(i++, [i++, i++].join(";"), i++));
clearPrevious = true;
headerCode += '
var buf:Array<Int> = [];
function a() {
trace("cock");
trace(buf);
trace(buf.push);
buf.push(1);
return 1;
}
function b() {
buf.push(2);
return 2;
}
function c() {
buf.push(3);
return 3;
}
function d() {
buf.push(4);
return 4;
}
function e() {
buf.push(5);
return 5;
}
function f() {
buf.push(6);
return 6;
}
function begin() {
buf = [];
return function() {
return buf.join("_");
}
}
function begin2() {
buf = [];
return () -> {
return buf.join("_");
}
}
';
var buf:Array<Int> = [];
function a() {
buf.push(1);
return 1;
}
function b() {
buf.push(2);
return 2;
}
function c() {
buf.push(3);
return 3;
}
function d() {
buf.push(4);
return 4;
}
function e() {
buf.push(5);
return 5;
}
function f() {
buf.push(6);
return 6;
}
function begin() {
buf = [];
return function() {
return buf.join("_");
}
}
function begin2() {
buf = [];
return () -> {
return buf.join("_");
}
}
if(Main.SHOW_KNOWN_BUGS) {
var end = begin();
(a() + b()) >= 0 && (c() + d()) >= 0;
assertEq('var end = begin();
(a() + b()) >= 0 && (c() + d()) >= 0;
end()', end());
}
var end = begin();
var _ = (a() + b()) >= 0 && (c() + d()) >= 0;
assertEq('var end = begin();
var test = (a() + b()) >= 0 && (c() + d()) >= 0;
trace(buf);
end()', end());
var end = begin2();
var _ = (a() + b()) >= 0 && (c() + d()) >= 0;
assertEq('var end = begin2();
var test = (a() + b()) >= 0 && (c() + d()) >= 0;
trace(buf, a());
end()', end());
}
override function teardown() {
super.teardown();
}
}
+23
View File
@@ -0,0 +1,23 @@
package tests;
class MathCase extends TestCase {
override function setup() {
super.setup();
}
override function run() {
assertEq("Math.PI", Math.PI);
assertEq("1 + 2", 3);
assertEq("1 + 2 + 3", 6);
assertEq("1 + 2 + 3 + 4", 10);
assertEq("(1 + 2) + 3", 6);
assertEq("(1 + 2) + 3 + 4", 10);
assertEq("(1 + 2) * 3", 9);
assertEq("(1 + 2) * 3 * 4", 36);
assertEq("((1 + 2) * 3 * 4) / 2", 18);
}
override function teardown() {
super.teardown();
}
}
+18
View File
@@ -0,0 +1,18 @@
package tests;
class MiscCase extends TestCase {
override function setup() {
super.setup();
}
override function run() {
assertEq("", null);
assertEq("true", true);
assertEq("false", false);
assertEq("null", null);
}
override function teardown() {
super.teardown();
}
}
+41
View File
@@ -0,0 +1,41 @@
package tests;
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() {}
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) {
if (clearPrevious)
return getNewInterp().execute(Util.parse(headerCode + script + tailCode));
else
@:privateAccess return interp.exprReturn(Util.parse(headerCode + script + tailCode));
}
}
+25
View File
@@ -0,0 +1,25 @@
# Generic Haxe stuffs to make the project compile
-cp src
-cp ../
-D analyzer-optimize
-main Main
# Libraries (MAKE SURE TO KEEP THIS IN SYNC WITH ALL BUILD FILES)
# --library hscript-improved
# --library hxcpp-debug-server
# Defines (MAKE SURE TO KEEP THIS IN SYNC WITH ALL BUILD FILES)
--define hscriptPos
--define HXCPP_CHECK_POINTER
--define HXCPP_STACK_LINE
--define HXCPP_DEBUG_LINK
--dce no
# File Specific Defines
--define windows
# Copying the assets from source code to bin folder
--cmd Xcopy assets\ bin\cpp\assets\ /E /H /C /I /Y
--cpp bin/cpp
--cmd cd bin/cpp
--cmd Main.exe