Update Files

This commit is contained in:
2025-01-22 16:18:30 +01:00
parent ed4603cf95
commit a36294b518
16718 changed files with 2960346 additions and 0 deletions

View File

@ -0,0 +1,7 @@
# hxcpp tests
The tests here are hxcpp specific. Notice that there are more target independent tests available in the [haxe repo](https://github.com/HaxeFoundation/haxe).
## Running the tests
haxe --run RunTests

View File

@ -0,0 +1,209 @@
class RunTests
{
static var baseDir:String;
static var errors = new Array<String>();
static var cppAst:Array<String> = [];
static var sysArgs = new Array<String>();
static var binDir = "";
static var ext = "";
static var m64 = true;
static var m64Def = "HXCPP_M64";
static var windows = false;
static var sep = "/";
public static function cffi()
{
setDir("cffi/project");
command("haxelib", ["run", "hxcpp", "build.xml", "-debug", '-D$m64Def']);
setDir("cffi");
command("haxe", ["compile.hxml", "-debug"] );
command("haxe", ["compile-utf8.hxml", "-debug"] );
command("haxe", ["compile-neko.hxml", "-debug"] );
copy('project/ndll/$binDir/prime$ext', 'bin/neko/prime.ndll');
setDir("cffi");
command("bin" + sep + "cpp" + sep + "TestMain-debug",[]);
command("bin" + sep + "cpp-utf8" + sep + "TestMain-debug",[]);
if (m64Def=="HXCPP_M64")
{
setDir("cffi/bin/neko");
command("neko", ["TestMain.n"]);
}
}
public static function runHaxe()
{
setDir("haxe");
command("haxe", ["compile.hxml", "-debug", "-D", m64Def].concat(cppAst) );
command("bin" + sep + "TestMain-debug",[]);
}
public static function runTelemetry()
{
setDir("telemetry");
// Telemetry should work in debug and non-debug modes
// TODO: do we need m64Def?
command("haxe", ["compile.hxml", "-debug"].concat(cppAst) );
command("bin" + sep + "TestMain-debug",[]);
command("haxe", ["compile.hxml"].concat(cppAst) );
command("bin" + sep + "TestMain",[]);
}
public static function debugger()
{
setDir("debugger");
command("haxe", ["compile.hxml"] );
command("bin" + sep + "App-debug",[]);
}
public static function opMatrix()
{
setDir("opMatrix");
command("haxe", ["--run","MkOps.hx"] );
}
public static function cppia()
{
setDir("cppia");
command("haxe", ["compile-host.hxml"] );
command("haxe", ["compile-client.hxml"] );
command("bin" + sep + "CppiaHost",[ "bin" + sep + "client.cppia" ]);
command("bin" + sep + "CppiaHost",[ "bin" + sep + "client.cppia", "-jit" ]);
}
public static function native()
{
setDir("native");
command("haxe", ["compile.hxml"] );
command("bin" + sep + "Native",[]);
}
public static function std32()
{
setDir("std");
command("haxe", ["compile32.hxml"] );
command("cpp32"+sep+"Test",[]);
}
public static function std64()
{
setDir("std");
command("haxe", ["compile64.hxml"] );
command("cpp64"+sep+"Test",[]);
}
public static function setDir(name:String)
{
Sys.println("Enter " + baseDir + "/" + name);
Sys.setCwd(baseDir + "/" + name);
}
public static function command(prog:String, args:Array<String>)
{
Sys.println( prog + " " + args.join(" ") );
var code = Sys.command(prog,args);
if (code!=0)
throw( "failed:" + prog + " " + args.join(" ") );
}
public static function run(name:String, func:Void->Void)
{
var args = sysArgs;
if (args.length>0 && args.indexOf(name)<0)
{
Sys.println("Skip test " + name);
return;
}
try
{
func();
}
catch(e:Dynamic)
{
trace('Error running $name : $e');
errors.push('Error running $name : $e');
}
}
public static function copy(from:String, to:String)
{
if (windows)
{
from = from.split("/").join("\\");
to = to.split("/").join("\\");
}
command( windows ? "copy" : "cp", [ from, to ] );
}
public static function main()
{
var systemName = Sys.systemName().toLowerCase();
switch(systemName.substr(0,3) )
{
case "mac":
m64 = true;
binDir = "Mac64";
ext = ".dylib";
case "lin":
m64 = true;
binDir = "Linux64";
ext = ".dso";
case "win":
m64 = true;
binDir = "Windows64";
ext = ".dll";
windows = true;
sep = "\\";
default:
throw 'Unknown system "$systemName"';
}
sysArgs = Sys.args();
if (sysArgs.remove("-cppast"))
cppAst = ["-D", "cppast"];
m64Def = m64 ? "HXCPP_M64" : "HXCPP_M32";
baseDir = Sys.getCwd();
run("cppia", cppia);
run("cffi", cffi);
//run("opMatrix", opMatrix);
run("haxe", runHaxe);
run("telemetry", runTelemetry);
run("std32", std32);
run("std64", std64);
run("native", native);
run("debugger", debugger);
Sys.println("");
if (errors.length==0)
{
Sys.println("All good!");
Sys.exit(0);
}
Sys.println("There were errors:");
for(error in errors)
Sys.println(error);
Sys.exit(-1);
}
}

View File

@ -0,0 +1,4 @@
-cp src
-main TestMain
-neko bin/neko/TestMain.n
-cp ../unit

View File

@ -0,0 +1,5 @@
-cp src
-main TestMain
-cpp bin/cpp-utf8
-cp ../unit
-D disable_unicode_strings

View File

@ -0,0 +1,4 @@
-cp src
-main TestMain
-cpp bin/cpp
-cp ../unit

View File

@ -0,0 +1,381 @@
#ifndef STATIC_LINK
#define IMPLEMENT_API
#endif
#if defined(HX_WINDOWS) || defined(HX_MACOS) || defined(HX_LINUX)
// Include neko glue....
#define NEKO_COMPATIBLE
#endif
#include <hx/CFFIPrime.h>
#include <math.h>
#include <vector>
#include <string>
int addInts(int a, int b)
{
return a+b;
}
DEFINE_PRIME2(addInts);
void printString(const char *inMessage)
{
printf("Message : %s.\n", inMessage);
}
DEFINE_PRIME1v(printString);
std::vector<AutoGCRoot *> roots;
void setRoot(int inRoot, value inValue)
{
if (roots.size()<=inRoot)
roots.resize(inRoot+1);
if (roots[inRoot]==0)
roots[inRoot] = new AutoGCRoot(inValue);
else
roots[inRoot]->set(inValue);
}
DEFINE_PRIME2v(setRoot);
value getRoot(int inRoot)
{
if (inRoot>=roots.size() || !roots[inRoot])
return alloc_null();
return roots[inRoot]->get();
}
DEFINE_PRIME1(getRoot);
void clearRoots()
{
for(int i=0;i<roots.size();i++)
{
delete roots[i];
roots[i] = 0;
}
}
DEFINE_PRIME0v(clearRoots);
double distance3D(int x, int y, int z)
{
return sqrt( (double)(x*x + y*y+ z*z) );
}
DEFINE_PRIME3(distance3D);
void fields(value object)
{
if ( val_is_null(object))
printf("null fields\n");
else
printf("x : %f\n", val_field_numeric(object, val_id("x")) );
}
DEFINE_PRIME1v(fields);
HxString stringVal(HxString inString)
{
printf("String : %s (%d)\n", inString.c_str(), inString.size());
return HxString("Ok");
}
DEFINE_PRIME1(stringVal);
HxString getNullString()
{
return 0;
}
DEFINE_PRIME0(getNullString);
// Conflict with name - use anon-namespace
namespace {
value select(int which, value object0, value object1, value object2, value object3)
{
switch(which)
{
case 0: return object0;
case 1: return object1;
case 2: return object2;
case 3: return object3;
default: return alloc_null();
}
}
DEFINE_PRIME5(select);
}
float floats(bool add, float firstVal, float secondVal)
{
return add ? firstVal + secondVal : firstVal - secondVal;
}
DEFINE_PRIME3(floats);
int multi5(int i0, int i1, int i2, int i3, int i4)
{
return i0 + i1 + i2 + i3 + i4;
}
DEFINE_PRIME5(multi5);
int multi6(int i0, int i1, int i2, int i3, int i4, int i5)
{
return i0 + i1 + i2 + i3 + i4 + i5;
}
DEFINE_PRIME6(multi6);
int multi7(int i0, int i1, int i2, int i3, int i4, int i5, int i6)
{
return i0 + i1 + i2 + i3 + i4 + i5 + i6;
}
DEFINE_PRIME7(multi7);
int multi8(int i0, int i1, int i2, int i3, int i4, int i5, int i6, int i7)
{
return i0 + i1 + i2 + i3 + i4 + i5 + i6 + i7;
}
DEFINE_PRIME8(multi8);
int multi9(int i0, int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8)
{
return i0 + i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8;
}
DEFINE_PRIME9(multi9);
int multi10(int i0, int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9)
{
return i0 + i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9;
}
DEFINE_PRIME10(multi10);
int multi11(int i0, int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10)
{
return i0 + i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10;
}
DEFINE_PRIME11(multi11);
int multi12(int i0, int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10, int i11)
{
return i0 + i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11;
}
DEFINE_PRIME12(multi12);
HxString addStrings(HxString s0, HxString s1)
{
if (hxs_encoding(s0)!=hx::StringUtf16 && hxs_encoding(s1)!=hx::StringUtf16)
{
std::string w0 = hxs_utf8(s0,0);
std::string w1 = hxs_utf8(s1,0);
std::string result = w0+w1;
return alloc_hxs_utf8( result.c_str(), result.size() );
}
std::wstring w0 = hxs_wchar(s0,0);
std::wstring w1 = hxs_wchar(s1,0);
std::wstring result = w0+w1;
return alloc_hxs_wchar( result.c_str(), result.size() );
}
DEFINE_PRIME2(addStrings);
// Old-style CFFI
value isBool(value inVal)
{
return alloc_bool( val_is_bool(inVal) );
}
DEFINE_PRIM(isBool,1);
value isNull(value inVal)
{
return alloc_bool( val_is_null(inVal) );
}
DEFINE_PRIM(isNull,1);
value allocNull()
{
return alloc_null();
}
DEFINE_PRIM(allocNull,0);
value appendString(value bufVal, value stringVal)
{
buffer buf = val_to_buffer(bufVal);
val_buffer(buf,stringVal);
return buffer_val(buf);
}
DEFINE_PRIM(appendString,2);
value bufferToString(value bufVal)
{
buffer buf = val_to_buffer(bufVal);
return buffer_to_string(buf);
}
DEFINE_PRIM(bufferToString, 1);
value valToString(value a, value b)
{
buffer buf = alloc_buffer("String:");
val_buffer(buf,a);
val_buffer(buf,b);
return buffer_to_string(buf);
}
DEFINE_PRIM(valToString, 2);
value valIsBuffer(value bufVal)
{
return alloc_bool( val_is_buffer(bufVal) );
}
DEFINE_PRIM(valIsBuffer, 1);
value subBuffer(value inString, value inLen)
{
buffer buf = alloc_buffer("Cold as ");
const char *string = val_string(inString);
buffer_append_sub(buf,string, val_int(inLen) );
return buffer_to_string(buf);
}
DEFINE_PRIM(subBuffer, 2);
value charString(value inC0, value inC1, value inC2)
{
buffer buf = alloc_buffer("A ");
buffer_append_char(buf,val_int(inC0));
buffer_append_char(buf,val_int(inC1));
buffer_append_char(buf,val_int(inC2));
return buffer_to_string(buf);
}
DEFINE_PRIM(charString, 3);
value byteDataSize(value byteData)
{
CffiBytes bytes = getByteData(byteData);
if (bytes.data==0)
return alloc_null();
return alloc_int(bytes.length);
}
DEFINE_PRIM(byteDataSize, 1);
value byteDataByte(value byteData, value inIndex)
{
CffiBytes bytes = getByteData(byteData);
if (bytes.data==0)
return alloc_null();
return alloc_int(bytes.data[ val_int(inIndex) ]);
}
DEFINE_PRIM(byteDataByte, 2);
int myFreeCount = 0;
DEFINE_KIND(myKind);
void destroyMyKind(value inAbstract)
{
//printf("destroyMyKind\n");
// In this case, the data belongs to the abstract
myFreeCount++;
}
void freeMyKind(value inAbstract)
{
//printf("freeMyKind\n");
void *data = val_to_kind(inAbstract,myKind);
// In this case, we own the data, so must delete it
delete (int *)data;
myFreeCount++;
}
value allocAbstract()
{
if (!myKind)
myKind = alloc_kind();
void *data = new int(99);
value abs = alloc_abstract(myKind, data);
val_gc(abs, freeMyKind);
return abs;
}
DEFINE_PRIM(allocAbstract, 0);
value createAbstract()
{
if (!myKind)
myKind = alloc_kind();
value abs = create_abstract(myKind, sizeof(int), destroyMyKind);
int *data = (int *)val_get_handle(abs,myKind);
*data = 99;
return abs;
}
DEFINE_PRIM(createAbstract, 0);
value getAbstract(value inAbstract)
{
void *data = val_to_kind(inAbstract,myKind);
if (!data)
return alloc_int(-1);
return alloc_int(*(int *)data);
}
DEFINE_PRIM(getAbstract, 1);
value getAbstractFreeCount()
{
return alloc_int(myFreeCount);
}
DEFINE_PRIM(getAbstractFreeCount, 0);
value freeAbstract(value inAbstract)
{
free_abstract(inAbstract);
return alloc_null();
}
DEFINE_PRIM(freeAbstract, 1);
value createAnon()
{
value v = alloc_empty_object();
alloc_field(v,val_id("TInt"),alloc_int(7));
alloc_field(v,val_id("TFloat"),alloc_float(7.2));
alloc_field(v,val_id("TBool"),alloc_bool(true));
buffer buf = alloc_buffer_len(4);
int data = 0xdeadbeef;
memcpy(buffer_data(buf),&data,sizeof(int));
alloc_field(v,val_id("TClass(Array)"),buffer_val(buf));
return v;
}
DEFINE_PRIM(createAnon,0);

View File

@ -0,0 +1,15 @@
<xml>
<include name="${HXCPP}/toolchain/haxe-target.xml"/>
<files id="prime">
<depend files="hxcpp-depends"/>
<file name="Project.cpp" />
</files>
<target id="default" output="${LIBPREFIX}prime${HX_TARGET_SUFFIX}" tool="linker" toolid="${STD_MODULE_LINK}">
<outdir name="${NDLLDIR}/${BINDIR}" />
<files id="prime"/>
</target>
</xml>

View File

@ -0,0 +1,20 @@
#if macro
import haxe.macro.Expr;
#end
class Loader
{
#if cpp
public static function __init__()
{
cpp.Lib.pushDllSearchPath( "project/ndll/" + cpp.Lib.getBinDirectory() );
}
#end
public static inline macro function load(inName2:Expr, inSig:Expr)
{
return macro cpp.Prime.load("prime", $inName2, $inSig, false);
}
}

View File

@ -0,0 +1,18 @@
import haxe.PosInfos;
class TestBase extends haxe.unit.TestCase
{
public function assertClose(inWant:Float, inGot:Float, ?c : PosInfos )
{
assertTrue( Math.abs(inWant-inGot) < 0.001, c );
}
public function assertEq<T>(inWant:T, inGot:T, ?c : PosInfos )
{
var same = inWant==inGot;
if (!same)
trace('Expected $inWant, got $inGot');
assertTrue(same, c);
}
}

View File

@ -0,0 +1,193 @@
#if cpp
import cpp.Lib;
import cpp.vm.Gc;
#elseif neko
import neko.Lib;
import neko.vm.Gc;
#end
import Loader;
import haxe.io.BytesData;
class TestCffi extends TestBase
{
static var isBool:Dynamic->Bool = Lib.load("prime", "isBool", 1);
static var isNull:Dynamic->Bool = Lib.load("prime", "isNull", 1);
static var allocNull:Void->Dynamic = Lib.load("prime", "allocNull", 0);
static var appendString:BytesData->String->BytesData = Lib.load("prime", "appendString", 2);
static var bufferToString:BytesData->String = Lib.load("prime", "bufferToString", 1);
static var valIsBuffer:Dynamic->Bool = Lib.load("prime", "valIsBuffer", 1);
static var valToString:Dynamic->Dynamic->String = Lib.load("prime", "valToString", 2);
static var subBuffer:String->Int->String = Lib.load("prime", "subBuffer", 2);
static var charString:Int->Int->Int->String = Lib.load("prime", "charString", 3);
static var byteDataSize:haxe.io.Bytes->Int = Lib.load("prime", "byteDataSize", 1);
static var byteDataByte:haxe.io.Bytes->Int->Int = Lib.load("prime", "byteDataByte", 2);
static var setRoot:Int->Dynamic->Void = Lib.load("prime", "setRoot", 2);
static var getRoot:Int->Dynamic = Lib.load("prime", "getRoot", 1);
static var clearRoots:Void->Void = Lib.load("prime", "clearRoots", 0);
static var createAbstract:Void->Dynamic = Lib.load("prime", "createAbstract", 0);
static var allocAbstract:Void->Dynamic = Lib.load("prime", "allocAbstract", 0);
static var getAbstract:Dynamic->Int = Lib.load("prime", "getAbstract", 1);
static var freeAbstract:Dynamic->Void = Lib.load("prime", "freeAbstract", 1);
static var getAbstractFreeCount:Void->Int = Lib.load("prime", "getAbstractFreeCount", 0);
static var createAnon:Void->Dynamic = Lib.load("prime", "createAnon", 0);
static var cppObjectAsDynamic:cpp.Callable<Int->cpp.Object>;
inline function getObjectAsString() : String
{
// Just test to see if this compiles
if (cppObjectAsDynamic!=null)
return cppObjectAsDynamic(1);
return null;
}
public function testCffi()
{
cpp.Prime.nekoInit("prime");
assertTrue( isBool!=null );
assertTrue( isBool(true) );
assertTrue( isBool(false) );
assertFalse( isBool(21) );
assertFalse( isBool("Hello") );
assertFalse( isBool(null) );
assertTrue( isNull!=null );
assertTrue( isNull(null) );
assertFalse( isNull(false) );
assertFalse( isNull(32) );
assertFalse( isNull("") );
assertTrue( allocNull!=null );
assertEquals(null, allocNull() );
assertTrue( appendString!=null );
assertTrue( bufferToString!=null );
assertTrue( getRoot!=null );
assertTrue( setRoot!=null );
assertTrue( createAnon!=null );
assertFalse( valIsBuffer(null) );
assertFalse( valIsBuffer(1) );
assertFalse( valIsBuffer({}) );
assertFalse( valIsBuffer("String Buf") );
if (cppObjectAsDynamic!=null)
assertTrue( getObjectAsString()==null);
var anon = createAnon();
for(f in Reflect.fields(anon))
{
#if cpp
var value:Dynamic = Reflect.field(anon, f);
//trace(f + " " + Type.typeof(value) );
assertTrue( Std.string(Type.typeof(value)) == f );
#end
}
for(i in 0...100)
setRoot(i,[i]);
Gc.run(true);
var base = "Hello ";
var bytes = haxe.io.Bytes.ofString(base).getData();
#if !neko
assertTrue( valIsBuffer(bytes) );
// Can't acess neko buffer from haxe code
bytes = appendString(bytes,"World");
var result = bufferToString(bytes);
assertEq(result,"Hello World");
#end
assertEq(valToString(null,1),"String:null1");
assertEq(valToString("x",1.1),"String:x1.1");
assertEq(valToString("Hello"," World"),"String:Hello World");
assertEq(valToString([1],[]),"String:[1][]");
assertEq(subBuffer("hello",4),"Cold as hell");
#if !neko
assertEq(charString(99,97,116),"A cat");
#end
var bytes = haxe.io.Bytes.ofString("String Buffer");
assertEq( byteDataSize(bytes), 13 );
assertEq( byteDataByte(bytes,1), 't'.code );
assertEq( getAbstractFreeCount(), 0 );
var createdAbs = createAbstract();
assertTrue( createdAbs!=null );
assertEq( getAbstract(createdAbs), 99 );
// Explicitly freeing abstract does not call finalizer
freeAbstract( createdAbs );
assertEq( getAbstractFreeCount(), 0 );
assertEq( getAbstract(createdAbs), -1 );
assertEq( getAbstractFreeCount(), 0 );
createdAbs = null;
Gc.run(true);
assertEq( getAbstractFreeCount(), 0 );
var allocatedAbs = allocAbstract();
assertTrue( allocatedAbs!=null );
assertEq( getAbstract(allocatedAbs), 99 );
assertEq( getAbstractFreeCount(), 0 );
freeAbstract( allocatedAbs );
assertEq( getAbstract(allocatedAbs), -1 );
assertEq( getAbstractFreeCount(), 0 );
allocatedAbs = null;
createDeepAbstracts(2);
clearStack(12);
Gc.run(true);
var freeCount = getAbstractFreeCount();
if (freeCount!=2)
{
Sys.println('\nWarning: $freeCount != 2');
}
for(i in 0...100)
assertEq( getRoot(i)+"", [i]+"" );
clearRoots();
for(i in 0...100)
assertEq( getRoot(i), null );
assertEq( getAbstractFreeCount(), 2 );
}
function clearStack(count:Int, ?nothing:Dynamic):Dynamic
{
if (count==0)
return 0;
return clearStack(count-1);
}
// Try to hide references from GC stack marking
function createDeepAbstracts(inDepth:Int)
{
if (inDepth==0)
{
createAbstract();
allocAbstract();
}
else
createDeepAbstracts(inDepth-1);
}
}

View File

@ -0,0 +1,17 @@
class TestMain
{
public static function main()
{
var r = new haxe.unit.TestRunner();
r.add(new TestCffi());
r.add(new TestPrime());
var t0 = haxe.Timer.stamp();
var success = r.run();
trace(" Time : " + (haxe.Timer.stamp()-t0)*1000 );
Sys.exit(success ? 0 : 1);
}
}

View File

@ -0,0 +1,78 @@
class TestPrime extends TestBase
{
static var add = Loader.load("addInts", "iii" );
#if cpp
static var printString = Loader.load("printString", "cv" );
#end
static var distance3d = Loader.load("distance3D", "iiid" );
static var select = Loader.load("select", "iooooo" );
static var floats = Loader.load("floats", "bfff" );
static var stringVal = Loader.load("stringVal", "ss" );
static var multi5 = Loader.load("multi5", "iiiiii" );
static var multi6 = Loader.load("multi6", "iiiiiii" );
static var multi7 = Loader.load("multi7", "iiiiiiii" );
static var multi8 = Loader.load("multi8", "iiiiiiiii" );
static var multi9 = Loader.load("multi9", "iiiiiiiiii" );
static var multi10 = Loader.load("multi10","iiiiiiiiiii" );
static var multi11 = Loader.load("multi11","iiiiiiiiiiii" );
static var multi12 = Loader.load("multi12","iiiiiiiiiiiii" );
static var getNullString = Loader.load("getNullString","s" );
static var addStrings = Loader.load("addStrings", 'sss');
// Non-static test
var fields = Loader.load("fields", "ov" );
public function testPrime()
{
cpp.Prime.nekoInit("prime");
assertTrue(add!=null);
assertEquals(7, add(2,5));
#if cpp
printString("Hello World");
#end
var len = distance3d(3,4,5);
assertClose(50,len*len);
fields( { x:11, name:"Hello" } );
fields( null );
assertEquals("Ok", stringVal("HxString"));
assertEquals(null, getNullString());
assertEquals( ""+[1], ""+select(0, [1], "Hello", {x:1}, add) );
var shouldBeNull:String = "" + select(0, null, "Hello", {x:1}, add);
trace( "null ?" + shouldBeNull + "/" + shouldBeNull.length );
assertEquals( "null", shouldBeNull );
//assertEquals( "null", ""+select(0, null, "Hello", {x:1}, add) );
assertEquals( ""+"Hello", ""+select(1, [1], "Hello", {x:1}, add));
assertEquals( ""+{x:1}, ""+select(2, [1], "Hello", {x:1}, add) );
assertEquals( ""+add, ""+select(3, [1], "Hello", {x:1}, add) );
assertClose( 7.3, floats(true,4.2,3.1) );
assertClose( 1.1, floats(false,4.2,3.1) );
assertEquals( 5, multi5(1,1,1,1,1) );
assertEquals( 6, multi6(1,1,1,1,1,1) );
assertEquals( 7, multi7(1,1,1,1,1,1,1) );
assertEquals( 8, multi8(1,1,1,1,1,1,1,1) );
assertEquals( 9, multi9(1,1,1,1,1,1,1,1,1) );
assertEquals( 10, multi10(1,1,1,1,1,1,1,1,1,1) );
assertEquals( 11, multi11(1,1,1,1,1,1,1,1,1,1,1) );
assertEquals( 12, multi12(1,1,1,1,1,1,1,1,1,1,1,1) );
var s0 = "hello";
var s1 = "";
assertTrue( addStrings(s0,s0) == s0+s0 );
var s01 = addStrings(s0,s1);
assertTrue( s01 == s0+s1 );
var s11 = addStrings(s1,s1);
assertTrue( s11 == s1+s1 );
}
}

View File

@ -0,0 +1,167 @@
class ClientOne implements pack.HostInterface
{
public function new() { }
public function getOne() : Int return 1;
public function getOneString() : String return "1";
}
class Client
{
public static var clientBool0 = true;
public static var clientBool1 = false;
public static var clientBool2 = true;
public static var clientBool3 = false;
public static function main()
{
Common.status = "running";
// See if it compiles
if (sys.thread.Thread.current()==null)
{
Common.status = "Cppia Thread.current not working.";
return;
}
if (Common.hostImplementation.getOne()!=1)
{
Common.status = "Bad call to getOne";
return;
}
if (Common.hostImplementation.getOneString()!="1")
{
Common.status = "Bad call to getOneString";
return;
}
var c = new ClientExtends();
if (!c.ok())
{
Common.status = "Bad client extension";
return;
}
if (c.whoStartedYou()!="HostBase")
{
Common.status = "Bad class fallthrough - got " + c.whoStartedYou();
return;
}
if (c.whoOverridesYou()!="ClientExtends")
{
Common.status = "Bad class override - got " + c.whoOverridesYou();
return;
}
if (!c.testPointers())
{
Common.status = "Could not move native pointers";
return;
}
var hostInterface:IHostInterface = c;
if (hostInterface.whoStartedYou()!="HostBase")
{
Common.status = "Bad interface fallthrough";
return;
}
if (hostInterface.whoOverridesYou()!="ClientExtends")
{
Common.status = "Bad interface override";
return;
}
if (hostInterface.hostImplOnly(1,"two",3)!="1two3")
{
Common.status = "Bad hostImplOnly implementation";
return;
}
if (!c.testOne())
{
Common.status = "Bad ClientExtends getOne";
return;
}
var clientInterface:IClientInterface = c;
if (clientInterface.whoStartedYou()!="HostBase")
{
Common.status = "Bad client interface fallthrough";
return;
}
if (clientInterface.uniqueClientFunc()!="uniqueClientFunc")
{
Common.status = "Bad new client interface call";
return;
}
if (clientInterface.whoOverridesYou()!="ClientExtends")
{
Common.status = "Bad client interface override";
return;
}
var clientHostInterface:IClientHostInterface = c;
if (clientHostInterface.whoStartedYou()!="HostBase")
{
Common.status = "Bad client interface fallthrough";
return;
}
if (clientHostInterface.whoOverridesYou()!="ClientExtends")
{
Common.status = "Bad client interface override";
return;
}
if (clientHostInterface.whoAreYou()!="ClientExtends")
{
Common.status = "Bad client/host interface";
return;
}
var c:ClientIHostImpl = new ClientIHostImpl();
if (c.hostImplOnly(0,null,0)!="client" || c.whoStartedYou()!="client" || c.whoOverridesYou()!="client")
{
Common.status = "Trouble implementing host interface";
return;
}
var c:ClientExtends = new ClientExtends2();
if (c.getGeneration()!=2)
{
Common.status = "Error calling cppia super function";
return;
}
var c = new ClientExtends2();
if (c.testOne())
{
Common.status = "ClientExtends2 getOne should fail";
return;
}
if (!c.testOneExtended())
{
Common.status = "ClientExtends2 testOneExtended failed";
return;
}
if (!c.testFour())
{
Common.status = "ClientExtends2 testFour error";
return;
}
var hostBools = HostBase.hostBool0 + "/" + HostBase.hostBool1+ "/" + HostBase.hostBool2+ "/" + HostBase.hostBool3;
var clientBools = clientBool0 + "/" + clientBool1+ "/" + clientBool2+ "/" + clientBool3;
if (hostBools!=clientBools)
{
Common.status = "Error in bool representation:" + hostBools + "!=" + clientBools;
return;
}
Common.clientImplementation = new ClientOne();
Common.status = "ok";
Common.callback = () -> Common.callbackSet = 2;
}
}

View File

@ -0,0 +1,62 @@
class ClientExtends extends HostBase implements IClientInterface implements IClientHostInterface
{
public function new()
{
super();
}
public function ok():Bool
{
return getVal()==1.25;
}
public function testOne()
{
return getOne()==1;
}
public function testOneExtended()
{
return getOne()==111;
}
#if (hxcpp_api_level>=400)
public function testPointers() : Bool
{
pointerDest = pointerSrc;
return getDestVal()==4;
}
override public function getGeneration()
{
return super.getGeneration() + 1;
}
#else
override public function getGeneration()
{
return super.getGeneration() + 1;
}
#end
override public function whoStartedYou() : String return super.whoStartedYou();
// override IHostInteface
override public function whoOverridesYou() return "ClientExtends";
// new IClientInterface
public function uniqueClientFunc() return "uniqueClientFunc";
// IClientHostInterface
public function whoAreYou() return "ClientExtends";
public function getOne() return 1;
public function getTwo() return 2;
public function getThree() return 3;
override public function update() return "ClientExtends update";
}

View File

@ -0,0 +1,25 @@
class ClientExtends2 extends ClientExtends
{
public function new()
{
super();
}
override public function getGeneration()
{
return super.getGeneration()+1;
}
public function getFour() return 4;
public function testFour() : Bool
{
return getFour()==4;
}
override public function getOne() return 111;
override public function update() return "ClientExtends2 update";
}

View File

@ -0,0 +1,8 @@
class ClientIHostImpl implements IHostInterface
{
public function new() { }
public function hostImplOnly(i:Int, s:String, f:Float) : String return "client";
public function whoStartedYou() : String return "client";
public function whoOverridesYou() : String return "client";
}

View File

@ -0,0 +1,10 @@
class Common
{
public static var status:String = "tests not run";
public static var hostImplementation:pack.HostInterface;
public static var clientImplementation:pack.HostInterface;
public static var callbackSet:Int = 0;
public static var callback: Void->Void;
}

View File

@ -0,0 +1,90 @@
import cpp.cppia.Host;
import HostBase;
class HostOne implements pack.HostInterface
{
public static var called = 0;
public function new()
{
}
public function getOne() : Int
{
called ++;
return 1;
}
public function getOneString() : String
{
called++;
return "1";
}
}
class CppiaHost
{
public static function main()
{
Common.hostImplementation = new HostOne();
Common.callback = () -> Common.callbackSet = 1;
/*
if (new HostExtends().getYou().extendOnly != 1)
{
Sys.println("extend-overide type failed");
Sys.exit(-1);
}
*/
Host.main();
Sys.println("TestStatus: " + Common.status );
if (Common.status!="ok")
{
Sys.println("failed");
Sys.exit(-1);
}
else
{
if (HostOne.called!=2)
{
Sys.println("No client implementation call - failed");
Sys.exit(-1);
}
if (Common.clientImplementation==null)
{
Sys.println("No client implementation - failed");
Sys.exit(-1);
}
if (Common.clientImplementation.getOne()!=1)
{
Sys.println("Bad client Int implementation - failed");
Sys.exit(-1);
}
if (Common.clientImplementation.getOneString()!="1")
{
Sys.println("Bad client String implementation - failed");
Sys.exit(-1);
}
var hostBase:HostBase = Type.createInstance(Type.resolveClass("ClientExtends2"),[]);
if (!hostBase.testUpdateOverride())
{
Sys.println("Bad update override");
Sys.exit(-1);
}
Common.callback();
if (Common.callbackSet!=2)
{
Sys.println("Bad cppia closure");
Sys.exit(-1);
}
}
}
}

View File

@ -0,0 +1,59 @@
#if (hxcpp_api_level>=400)
import cpp.Native;
#end
class HostBase implements IHostInterface
{
static var hostInit = 10;
public static var hostBool0 = true;
public static var hostBool1 = false;
public static var hostBool2 = true;
public static var hostBool3 = false;
var floatVal:Float;
var pointerSrc:cpp.Star<Int>;
var pointerDest:cpp.Star<Int>;
public function new()
{
floatVal = 1.25;
#if (hxcpp_api_level>=400)
pointerSrc = Native.malloc( Native.sizeof(Int) );
Native.set(pointerSrc,4);
pointerDest = null;
#end
}
public function getDestVal() : Int
{
#if (hxcpp_api_level>=400)
if (pointerDest==null)
return -1;
return Native.get(pointerDest);
#else
return 4;
#end
}
public function getYou() : HostBase
{
return this;
}
public function testUpdateOverride() : Bool
{
return update()=="ClientExtends2 update";
}
public function getVal() return floatVal;
public function getGeneration() return 0;
public function update() return "HostBase update";
// IHostInteface
public function hostImplOnly(i:Int, s:String, f:Float) : String return i+s+f;
public function whoStartedYou() return "HostBase";
public function whoOverridesYou() return "No one";
}

View File

@ -0,0 +1,6 @@
// Same as IHostInterface, but not implemented in host
interface IClientHostInterface extends IHostInterface
{
public function whoAreYou() : String;
}

View File

@ -0,0 +1,7 @@
interface IClientInterface
{
// Same as IHostInterface, but not implemented in host
public function whoStartedYou() : String;
public function whoOverridesYou() : String;
public function uniqueClientFunc() : String;
}

View File

@ -0,0 +1,6 @@
interface IHostInterface
{
public function hostImplOnly(i:Int, s:String, f:Float) : String;
public function whoStartedYou() : String;
public function whoOverridesYou() : String;
}

View File

@ -0,0 +1,4 @@
-main Client
-D dll_import=host_classes.info
-cppia bin/client.cppia
-cp ../unit

View File

@ -0,0 +1,6 @@
-main CppiaHost
-D scriptable
-D dll_export=host_classes.info
-dce no
-cpp bin
-cp ../unit

View File

@ -0,0 +1,7 @@
package pack;
interface HostInterface
{
public function getOne() : Int;
public function getOneString() : String;
}

View File

@ -0,0 +1,45 @@
class App
{
public static var hasRunBreakMe = false;
public static var hasRunBreakMe2 = false;
function breakMe()
{
hasRunBreakMe = true;
}
function breakMe2() hasRunBreakMe2 = true;
public function new()
{
breakMe();
breakMe2();
Lines.lineStep();
}
public static function main()
{
TestDebugger.setup();
new App();
if (!TestDebugger.finished)
{
Sys.println("Not all breakpoints triggered");
Sys.exit(-1);
}
else if (!TestDebugger.ok)
{
Sys.println("Some debugger checks failed");
Sys.exit(-1);
}
else
{
Sys.println("All good!");
}
}
}

View File

@ -0,0 +1,20 @@
class Lines // line 1
{ // line 2
public static var line = -1; // line 3
// line 4
public static function lineStep() // line 5
{ // line 6
line = 7; // line 7;
callFunction(); // 8
line = 9; // line 9;
callFunction(); // 10
// 11
line = 12; // 12
} // line 13
// 14
public static function callFunction() // 15
{ // 16
// 17
line = 18;
}
}

View File

@ -0,0 +1,156 @@
import cpp.vm.Debugger;
#if haxe4
import sys.thread.Thread;
#else
import cpp.vm.Thread;
#end
typedef DebuggerContext = { className : String,
functionName : String,
fileName : String,
lineNumber : Int };
typedef DebuggerTest = { setup:Void->Void,
test:DebuggerContext->Bool,
name:String,
resume:Int->Void };
class TestDebugger
{
public static var ok = true;
public static var finished = false;
static var jobs:Array<DebuggerTest>;
static var currentTest:DebuggerContext->Bool;
static var currentName:String;
static var currentResume:Void->Void;
public static function setup()
{
Debugger.enableCurrentThreadDebugging(false);
var mainThread = Thread.current();
Thread.create( function() {
startDebugger();
mainThread.sendMessage("setup");
});
var message = Thread.readMessage(true);
Sys.println("Debugger : " + message);
Debugger.enableCurrentThreadDebugging(true);
}
static function handleThreadEvent(threadNumber : Int, event : Int,
stackFrame : Int,
className : String,
functionName : String,
fileName : String, lineNumber : Int)
{
if (event==Debugger.THREAD_STOPPED)
{
var ctx = { className:className, functionName:functionName, fileName:fileName, lineNumber:lineNumber };
if (!currentTest(ctx))
{
ok = false;
Sys.println('Test failed : $currentName - got $ctx');
Sys.exit(-1);
}
else
{
nextTest(threadNumber);
}
}
}
static function cont(id:Int)
{
Debugger.continueThreads(-1,1);
}
static function step(id:Int)
{
Debugger.stepThread(id,Debugger.STEP_INTO,1);
}
static function stepOver(id:Int)
{
Debugger.stepThread(id,Debugger.STEP_OVER,1);
}
static function stepOut(id:Int)
{
Debugger.stepThread(id,Debugger.STEP_OUT,1);
}
static function nextTest(threadId:Int)
{
var test = jobs.shift();
if (test==null)
{
finished = true;
currentName = null;
currentTest = null;
currentResume = null;
Debugger.setEventNotificationHandler(null);
cont(-1);
}
else
{
currentName = test.name;
currentTest = test.test;
test.setup();
Sys.println(' $currentName...');
test.resume(threadId);
}
}
static function startDebugger()
{
Debugger.setEventNotificationHandler(handleThreadEvent);
jobs = [
{ setup:function() Debugger.addClassFunctionBreakpoint("App","breakMe"),
test:function(ctx) return !App.hasRunBreakMe,
name:"Set function breakpoint App.breakMe",
resume:cont },
{ setup:function() Debugger.addClassFunctionBreakpoint("App","breakMe2"),
test:function(ctx) return App.hasRunBreakMe && !App.hasRunBreakMe2,
name:"Set function breakpoint App.breakMe2",
resume:cont},
{ setup:function() Debugger.addFileLineBreakpoint("Lines.hx",7),
test:function(ctx) return Lines.line==-1,
name:"Set line breakpoint Lines.hx:7",
resume:cont},
{ setup:function() { },
test:function(ctx) return Lines.line==7,
name:"Step from Lines.hx:7",
resume:step},
{ setup:function() { },
test:function(ctx) return Lines.line==18,
name:"Step over callFunction",
resume:stepOver},
{ setup:function() { },
test:function(ctx) return Lines.line==9,
name:"Step over line 9",
resume:step},
{ setup:function() { },
test:function(ctx) return Lines.line==9,
name:"step into callFunction",
resume:step},
{ setup:function() { },
test:function(ctx) return Lines.line==18,
name:"step out of callFunction",
resume:stepOut },
{ setup:function() { },
test:function(ctx) return Lines.line==12,
name:"step out of Lines",
resume:stepOut },
];
nextTest(-1);
}
}

View File

@ -0,0 +1,6 @@
-main App
-cpp bin
-D hxcpp_debugger
-D HXCPP_DEBUGGER
-debug
-cp ../unit

View File

@ -0,0 +1,10 @@
package api;
@:nativeGen
@:structAccess
class HaxeApi
{
@:keep
public static function createBase( ) : HaxeObject return new impl.HaxeImpl();
}

View File

@ -0,0 +1,12 @@
package api;
@:nativeGen
interface HaxeObject
{
public function getName( ):cpp.StdString;
public function setName( inName:cpp.StdStringRef ) : Void;
public function createChild() : HaxeObject;
public function printInt(x:Int):Void;
}

View File

@ -0,0 +1,4 @@
-cpp gen-externs
-D static_link
api.HaxeApi
-cp ../unit

View File

@ -0,0 +1,44 @@
package impl;
import api.HaxeObject;
@:keep
class HaxeImpl implements HaxeObject
{
var parentName:String;
var name:String;
var haxeObject:HaxeObject;
public function new(?inParent:HaxeImpl)
{
haxeObject = null;
parentName = inParent==null ? "" : inParent.name;
if (haxeObject==null)
haxeObject = this;
}
public function getName( ):cpp.StdString
{
return cpp.StdString.ofString(name);
}
@:unreflective
public function setName( inName:cpp.StdStringRef ) : Void
{
name = inName.toString();
}
public function createChild() : HaxeObject
{
var child = new HaxeImpl(this);
return child;
}
public function printInt(x:Int):Void
{
Sys.println( Std.string(x) );
}
}

View File

@ -0,0 +1,15 @@
<xml>
<files id="myfiles">
<compilerflag value="-I${HXCPP}/include"/>
<compilerflag value="-I../extern-lib/gen-externs/include"/>
<file name="Main.cpp" />
</files>
<target id="default" tool="linker" toolid="exe" output="ExternUse">
<files id="myfiles"/>
<libpath name="../extern-lib/gen-externs" />
<lib base="liboutput" />
</target>
</xml>

View File

@ -0,0 +1,73 @@
#include <stdio.h>
#include <hx/Native.h>
#include <api/HaxeObject.h>
#include <api/HaxeApi.h>
struct MyStruct
{
hx::Ref<api::HaxeObject *> haxeRef;
};
extern void __hxcpp_collect(bool inMajor);
int main(int argc, char **argv)
{
MyStruct *myStruct = new MyStruct();
const char *err = hx::Init();
if (err)
{
printf("Could not initialize library: %s\n", err);
return -1;
}
else
{
hx::NativeAttach autoAttach;
api::HaxeObject *obj = api::HaxeApi::createBase();
obj->setName("child");
myStruct->haxeRef = obj;
obj->setName("Name");
api::HaxeObject *child = obj->createChild();
}
{
hx::NativeAttach autoAttach;
__hxcpp_collect(true);
}
{
hx::NativeAttach autoAttach;
if (myStruct->haxeRef->getName()!="Name")
{
printf("Could not get value back (%s)\n", myStruct->haxeRef->getName().c_str() );
return -1;
}
}
{
hx::NativeAttach autoAttach0;
hx::NativeAttach autoAttach1;
hx::NativeAttach autoAttach2;
hx::NativeAttach autoAttach3;
if (hx::GcGetThreadAttachedCount()!=4)
{
printf("Bad attach count\n");
return -1;
}
}
if (hx::GcGetThreadAttachedCount()!=0)
{
printf("Bad clear attach count\n");
return -1;
}
printf("all good\n");
return 0;
}

View File

@ -0,0 +1,66 @@
class TestIntHash extends haxe.unit.TestCase
{
function spamAlot()
{
var values = new Array< Null<Int> >();
values[0] = null;
var h = new Map<Int,Int>();
for(i in 0...2000)
{
for(j in 0...2000)
{
var idx = Std.int(Math.random()*2999);
if (h.get(idx)!=values[idx])
throw "Bad value";
if ( (i % 4)== 1 || Math.random()>0.5 )
{
if (h.remove(idx) != (values[idx]!=null))
throw "Error in remove!";
values[idx] = null;
}
else
{
h.set(idx,j);
values[idx] = j;
}
}
var keys = h.keys();
var keyed = new Array<Bool>();
for(i in 0...values.length)
keyed[i] = false;
for( key in h.keys())
keyed[ key ] = true;
for(i in 0...values.length)
if (keyed[i]!=(values[i]!=null))
throw "Bad value";
var valued = new Array<Int>();
for( val in h.iterator())
valued[val]++;
for(val in values)
if (val!=null)
{
if (valued[val]<1)
throw "Not valued!";
valued[val]--;
}
}
}
public function test()
{
var err = "";
try
{
spamAlot();
}
catch(e:String)
{
err = e;
}
assertTrue(err=="");
}
}

View File

@ -0,0 +1,49 @@
private enum GnarlyEnum
{
e0;
GnarlyEnum;
narlyEnum;
Dynamic;
getFixed(i:Int);
getInt;
init(i:Int);
String;
index(i:Int);
const;
super(i:Int);
tag(i:Int);
getTag(i:Int);
getObject(i:Int);
}
class TestKeywords extends haxe.unit.TestCase
{
public function new() super();
//public function getGnarly() { return GnarlyEnum.super(1); }
public function getGnarly() { return Dynamic; }
public function testEnum()
{
var count =
switch( getGnarly() )
{
case e0: 1;
//case GnarlyEnum: 1;
case narlyEnum: 1;
case Dynamic: 3;
case getFixed(i): 1;
case getInt: 1;
case init(i): 1;
case String: 1;
case index(i): 1;
case const: 1;
//case GnarlyEnum.super(i): 2;
case tag(i): 1;
case getTag(i): 1;
case getObject(i): 1;
default: 0;
}
assertTrue(count==3);
}
}

View File

@ -0,0 +1,76 @@
package;
import gc.TestGC;
class TestMain #if nme extends nme.display.Sprite #end {
static function runTests():Int
{
var passes = 1;
#if !nme
var args = Sys.args();
if (args.length>0)
passes = Std.parseInt(args[0]);
#end
var r = new haxe.unit.TestRunner();
r.add(new TestTypes());
r.add(new TestKeywords());
r.add(new TestSort());
r.add(new TestGC());
#if !nme
r.add(new gc.TestGCThreaded());
#end
r.add(new TestIntHash());
r.add(new TestStringHash());
r.add(new TestObjectHash());
r.add(new TestWeakHash());
#if !nme
r.add(new file.TestFile());
#end
#if cpp
r.add(new native.TestFinalizer());
#end
for(i in 0...passes)
{
var t0 = haxe.Timer.stamp();
var success = r.run();
trace(" Time : " + (haxe.Timer.stamp()-t0)*1000 );
if (!success)
return 1;
}
return 0;
}
#if nme
var frameCount = 0;
var tf:nme.text.TextField;
public function new()
{
super();
tf = new nme.text.TextField();
tf.text="RUN...";
addChild(tf);
addEventListener( nme.events.Event.ENTER_FRAME, onFrame );
}
function onFrame(_)
{
var err = runTests();
tf.text = "" + (++frameCount);
stage.opaqueBackground = err==0 ? 0xff00ff00: 0xffff0000;
}
static function endTest(error:Int) trace(error==0 ? "All tests OK" : "Tests Failed!");
#else
public static function main()
{
Sys.exit(runTests());
}
public static function endTest(error:Int) Sys.exit(error);
#end
}

View File

@ -0,0 +1,91 @@
class ObjectData
{
public var id:Int;
public function new(inId:Int) id = inId;
}
class TestObjectHash extends haxe.unit.TestCase
{
function spamAlot()
{
var values = new Array< Null<Int> >();
values[0] = null;
var h = new Map<ObjectData,Int>();
var idxToKey = new Array<ObjectData>();
for(idx in 0...3000)
idxToKey[idx] = new ObjectData(idx);
for(i in 0...2000)
{
for(j in 0...2000)
{
var idxInt = Std.int(Math.random()*2999);
var idx = idxToKey[idxInt];
if (h.get(idx)!=values[idxInt])
{
throw "Bad value";
}
if ( (i % 4)== 1 || Math.random()>0.5 )
{
if (h.remove(idx) != (values[idxInt]!=null))
{
trace("Bad remove");
throw "Error in remove!";
}
values[idxInt] = null;
}
else
{
h.set(idx,j);
values[idxInt] = j;
}
}
var keys = h.keys();
var keyed = new Array<Bool>();
for(i in 0...values.length)
keyed[i] = false;
for( key in h.keys())
{
var idxInt = key.id;
keyed[ idxInt ] = true;
}
for(i in 0...values.length)
if (keyed[i]!=(values[i]!=null))
throw "Bad value";
var valued = new Array<Int>();
#if neko
valued[3000]=0;
for(i in 0...3000)
valued[i] = 0;
#end
for( val in h.iterator())
valued[val]++;
for(val in values)
if (val!=null)
{
if (valued[val]<1)
throw "Not valued!";
valued[val]--;
}
}
}
public function test()
{
var err = "";
try
{
spamAlot();
}
catch(e:Dynamic)
{
trace(e);
err = e;
}
assertTrue(err=="");
}
}

View File

@ -0,0 +1,60 @@
class SortData
{
public var value:Int;
public var id:Int;
static var ids = 0;
public function new()
{
value = Std.int(Math.random()*500);
id = ids++;
}
}
class TestSort extends haxe.unit.TestCase
{
public function testObjects()
{
var tests = new Array<SortData>();
for(i in 0...100000)
tests.push( new SortData() );
var sorted = tests.copy();
sorted.sort( function(a,b) return a.value - b.value );
for(i in 1...sorted.length)
{
if (sorted[i].value < sorted[i-1].value)
throw "Index out of order";
if (sorted[i].value == sorted[i-1].value &&
sorted[i].id <= sorted[i-1].id )
throw "Not stable sort";
}
var sorted = tests.copy();
var compares = 0;
sorted.sort( function(a,b) {
// Churn some GC
var array = new Array<Int>();
compares++;
array.push(a.value);
array.push(b.value);
return array[0] < array[1] ? 1 : array[0] > array[1] ? -1 : 0;
});
//Sys.println("\nCompares per log elements:" + (compares/(tests.length*Math.log(tests.length))));
for(i in 1...sorted.length)
{
if (sorted[i].value > sorted[i-1].value)
throw "Index out of order";
if (sorted[i].value == sorted[i-1].value &&
sorted[i].id <= sorted[i-1].id )
throw "Not stable sort";
}
assertTrue(true);
}
}

View File

@ -0,0 +1,88 @@
class TestStringHash extends haxe.unit.TestCase
{
function spamAlot()
{
var values = new Array< Null<Int> >();
values[0] = null;
var h = new Map<String,Int>();
var idxToKey = new Array<String>();
for(idx in 0...3000)
idxToKey[idx] = Std.string(idx);
for(i in 0...2000)
{
for(j in 0...2000)
{
var idxInt = Std.int(Math.random()*2999);
var idx = idxToKey[idxInt];
if (h.get(idx)!=values[idxInt])
{
throw "Bad value";
}
if ( (i % 4)== 1 || Math.random()>0.5 )
{
if (h.remove(idx) != (values[idxInt]!=null))
{
trace("Bad remove");
throw "Error in remove!";
}
values[idxInt] = null;
}
else
{
h.set(idx,j);
values[idxInt] = j;
}
}
var arr = [0,1,2];
var keys = h.keys();
// Empty allocations can mess with the GC nursery
cpp.NativeArray.setSize(arr,0);
cpp.NativeArray.setSize(arr,3);
var keyed = new Array<Bool>();
for(i in 0...values.length)
keyed[i] = false;
for( key in h.keys())
{
var idxInt = Std.parseInt(key);
keyed[ idxInt ] = true;
}
for(i in 0...values.length)
if (keyed[i]!=(values[i]!=null))
throw "Bad value";
var valued = new Array<Int>();
#if neko
valued[3000]=0;
for(i in 0...3000)
valued[i] = 0;
#end
for( val in h.iterator())
valued[val]++;
for(val in values)
if (val!=null)
{
if (valued[val]<1)
throw "Not valued!";
valued[val]--;
}
}
}
public function test()
{
var err = "";
try
{
spamAlot();
}
catch(e:Dynamic)
{
trace(e);
err = e;
}
assertTrue(err=="");
}
}

View File

@ -0,0 +1,49 @@
class TestTypes extends haxe.unit.TestCase
{
var i0:Int = 1;
var i1:cpp.Int32 = 1;
var i2:cpp.UInt32 = 1;
var i3:cpp.Int64 = 1;
var i4:cpp.UInt64 = 1;
var i5:cpp.Int8 = 1;
var i6:cpp.UInt8 = 1;
var i7:cpp.Int16 = 1;
var i8:cpp.UInt16 = 1;
public function new() super();
function stringToCcs(string:String) : cpp.ConstCharStar
{
return string;
}
function ccsToString(ccs:cpp.ConstCharStar) : String
{
return ccs;
}
function ccsToStringCast(ccs:cpp.ConstCharStar) : String
{
return cast ccs;
}
public function testConstCharStar()
{
var ccs = stringToCcs("hello");
assertTrue( ccsToString(ccs)=="hello" );
assertTrue( ccsToStringCast(ccs)=="hello" );
}
public function testDynamic()
{
var d:Dynamic = this;
assertTrue(d.i0==1);
assertTrue(d.i1==1);
assertTrue(d.i2==1);
assertTrue(d.i3==1);
assertTrue(d.i4==1);
assertTrue(d.i5==1);
assertTrue(d.i6==1);
assertTrue(d.i7==1);
}
}

View File

@ -0,0 +1,93 @@
import haxe.ds.WeakMap;
class WeakObjectData
{
public var id:Int;
public function new(inId:Int) id = inId;
public function toString() return "Data " + id;
}
class TestWeakHash extends haxe.unit.TestCase
{
var retained:Array<WeakObjectData>;
function createMap(inCount:Int)
{
retained = [];
var map = new WeakMap<WeakObjectData,Int>();
for(i in 0...inCount)
{
var obj = new WeakObjectData(i);
if ( (i&1)==0 )
retained.push(obj);
map.set(obj,i);
}
return map;
}
function createMapDeep(inDepth:Int, inCount:Int)
{
if (inDepth<1)
return createMap(inCount);
return createMapDeep(inDepth-1, inCount);
}
function checkMap(map:WeakMap<WeakObjectData,Int>, expect:Int)
{
var valid = 0;
var oddFound = 0;
for(k in map.keys())
{
if( (k.id&1)!= 0)
{
oddFound ++;
//throw "Odd retained " + k.id;
}
else
valid++;
}
// There may be one or two values lurking on the stack, which is conservatively marked
if (oddFound>2)
trace("Too many odd values retained " + oddFound);
if (!(valid>=expect && valid<expect+2))
trace("WeakHash invalid range "+ expect + "..." + valid + "..." + (expect+2) );
assertTrue(valid>=expect && valid<expect+2);
}
function deepCheckMap(inDepth:Int, map:WeakMap<WeakObjectData,Int>, expect:Int)
{
if (inDepth<1)
checkMap(map,expect);
else
deepCheckMap(inDepth-1, map, expect);
}
function deepClearRetained(inRecurse:Int)
{
if (inRecurse>0)
deepClearRetained(inRecurse-1);
else
retained = [];
}
public function test()
{
var err = "";
try
{
var map = createMapDeep(20,1000);
cpp.vm.Gc.run(true);
deepCheckMap(10,map,500);
deepClearRetained(10);
cpp.vm.Gc.run(true);
checkMap(map,0);
}
catch(e:String)
{
trace(e);
err = e;
}
assertTrue(err=="");
}
}

View File

@ -0,0 +1,5 @@
-cpp bin
-main TestMain
-resource TestMain.hx
-D HXCPP_GC_GENERATIONAL
-cp ../unit

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<project>
<meta
title="GCTests"
package="org.haxe.hxcpp.gctest"
version="1.0.0"
company="haxefoundation"
/>
<app
file="TestMain"
main="TestMain"
/>
<window
width="640"
height="480"
orientation="landscape"
fps="60"
background="0xeeeeee"
require_shaders="true"
resizable="true"
hardware="true"
/>
<haxelib name="nme" />
<haxedef name="HXCPP_GC_GENERATIONAL" />
<haxedef name="HXCPP_DEBUG_LINK" />
<haxeflag name="-resource TestMain.hx" />
<cp path="../unit" />
</project>

View File

@ -0,0 +1,10 @@
package file;
class TestFile extends haxe.unit.TestCase
{
public function testGetContentEmptyFile()
{
assertEquals('', sys.io.File.getContent('./file/empty.txt'));
}
}

View File

@ -0,0 +1,102 @@
package gc;
class TestBigStack
{
var refs:Array<TestBigStack>;
var self:TestBigStack;
public function new()
{
refs = [];
self = this;
}
function check()
{
if (self!=this)
throw("Bad self reference");
}
function checkRec()
{
if (self!=this)
throw("Bad self reference");
for(r in refs)
r.checkRec();
}
function runRec(depth:Int)
{
var d = depth-1;
if (d==0)
return this;
var b0 = new TestBigStack().runRec(d);
var b1 = new TestBigStack().runRec(d);
var b2 = new TestBigStack().runRec(d);
var b3 = new TestBigStack().runRec(d);
var b4 = new TestBigStack().runRec(d);
var b5 = new TestBigStack().runRec(d);
var b6 = new TestBigStack().runRec(d);
var b7 = new TestBigStack().runRec(d);
var b8 = new TestBigStack().runRec(d);
var b9 = new TestBigStack().runRec(d);
var b10 = new TestBigStack().runRec(d);
var b11 = new TestBigStack().runRec(d);
var b12 = new TestBigStack().runRec(d);
var b13 = new TestBigStack().runRec(d);
var b14 = new TestBigStack().runRec(d);
var b15 = new TestBigStack().runRec(d);
var b16 = new TestBigStack().runRec(d);
var b17 = new TestBigStack().runRec(d);
var b18 = new TestBigStack().runRec(d);
var b19 = new TestBigStack().runRec(d);
refs.push(b0);
b0.check();
b1.check();
b2.check();
b3.check();
b4.check();
b5.check();
b6.check();
b7.check();
b8.check();
b9.check();
b10.check();
b11.check();
b12.check();
b13.check();
b14.check();
b15.check();
b16.check();
b17.check();
b18.check();
b19.check();
return this;
}
function run(passes:Int, depth:Int)
{
for(p in 0...passes)
{
//if ( (p%1000)==0 )
// Sys.println('Pass $p...');
refs = [];
runRec(depth);
checkRec();
}
}
public static function test() : Bool
{
try {
var b = new TestBigStack();
b.run(5000,5);
return true;
}
catch(e:Dynamic)
{
return false;
}
}
}

View File

@ -0,0 +1,129 @@
package gc;
import haxe.io.Bytes;
import cpp.vm.Gc;
class CustomObject {
public function new():Void {}
}
class TestGC extends haxe.unit.TestCase {
function createDummy(val:Dynamic):Dynamic {
return { dummy: val };
}
function gc():Dynamic {
Gc.run(true);
return Gc.getNextZombie();
}
/**
For avoiding the simple call being optimized in some way.
*/
function create(f:Void->Void):Void {
f();
clearStack(10);
}
function clearStack(count:Int, ?nothing:Dynamic):Dynamic
{
if (count==0)
return 0;
return clearStack(count-1);
}
function createAbc():Void {
var object = { test: "abc" };
Gc.doNotKill(object);
}
public function testObject():Void {
create(createAbc);
var zombie = gc();
assertTrue(zombie != null);
assertEquals("abc", zombie.test);
assertTrue(gc() == null);
}
// Null<int> for numbers < 256 are special cases
// Infact, there are no guarantees that Null<Int> will be actual objects in the future
/*
function create1234():Void {
var object:Null<Int> = 1234;
Gc.doNotKill(object);
};
public function testBoxedInt():Void {
create(create1234);
var zombie:Dynamic = gc();
assertTrue(zombie != null);
assertEquals(1234, zombie);
assertTrue(gc() == null);
}
*/
function createFunction():Void {
var object = function() return "abc";
Gc.doNotKill(object);
};
public function testFunc():Void {
create(createFunction);
var zombie = gc();
assertTrue(zombie != null);
assertEquals("abc", zombie());
assertTrue(gc() == null);
}
function createCustom():Void {
var object = new CustomObject();
Gc.doNotKill(object);
};
public function testCustomObject():Void {
create(createCustom);
var zombie = gc();
assertTrue(zombie != null);
assertTrue(Std.isOfType(zombie, CustomObject));
assertTrue(gc() == null);
}
function createBytes():Void {
var object = Bytes.alloc(1);
Gc.doNotKill(object);
};
public function testBytes():Void {
create(createBytes);
var zombie = gc();
assertTrue(zombie != null);
assertTrue(Std.isOfType(zombie, Bytes));
assertTrue(gc() == null);
}
public function testBigStack():Void {
assertTrue( TestBigStack.test() );
}
#if !cppia
public function testConstStrings():Void {
// Const strings void Gc overhead
var strings = new Array<String>();
strings.push( haxe.Resource.getString("TestMain.hx") );
strings.push( "some string" );
var chars = "abc123";
// Optimization for single chars...
for(c in 0...chars.length)
strings.push( chars.substr(c,1) );
for(string in strings)
assertTrue( untyped __global__.__hxcpp_is_const_string(string) );
Gc.run(true);
for(string in strings)
assertTrue( untyped __global__.__hxcpp_is_const_string(string) );
var strings = new Array<String>();
strings.push( haxe.Resource.getString("TestMain.hx").substr(10) );
strings.push( "some string" + chars );
for(c in 0...chars.length-1)
strings.push( chars.substr(c,2) );
for(string in strings)
assertFalse( untyped __global__.__hxcpp_is_const_string(string) );
}
#end
}

View File

@ -0,0 +1,134 @@
package gc;
import haxe.io.Bytes;
import haxe.crypto.Md5;
import cpp.vm.Gc;
import sys.io.File;
#if haxe4
import sys.thread.Thread;
#else
import cpp.vm.Thread;
#end
class Wrapper
{
public var a:Int;
public function new(inA:Int) a = inA;
}
@:cppInclude("./ZoneTest.cpp")
@:depend("./ZoneTest.cpp")
class TestGCThreaded extends haxe.unit.TestCase
{
@:keep
static var keepRunning = false;
@:keep
static var nativeRunning = false;
var bigText:String;
override public function setup()
{
var lines = [ for(i in 0...100000) "abc123\n" ];
#if nme
bigText = lines.join("");
#else
File.saveContent( "gc/big.txt", lines.join("") );
#end
}
public function testThreadOnce():Void
{
startNative();
doThreadedWork(4,100);
stopNative();
assertTrue(true);
}
public function testThreadMany():Void
{
startNative();
for(i in 0...10)
#if nme
doThreadedWork(4,100);
#else
doThreadedWork(100,100);
#end
stopNative();
assertTrue(true);
}
@:native("nativeLoop")
extern static function nativeLoop() : Void;
function startNative()
{
Thread.create( () -> {
nativeRunning = true;
keepRunning = true;
nativeLoop();
});
}
function stopNative()
{
keepRunning = false;
while(nativeRunning)
Sys.sleep(0.1);
}
function doThreadedWork(numThreads, numWork):Void
{
var threads:Array<Thread> = makeThreads(numThreads);
for (i in 0...numWork)
threads[i % threads.length].sendMessage('doWork');
for (i in 0...numThreads)
{
threads[i].sendMessage('exit');
Thread.readMessage(true);
}
}
function makeThreads(numThreads:Int):Array<Thread>
{
#if nme
var text:String = bigText;
#else
var text:String = File.getContent("gc/big.txt");
#end
var main:Thread = Thread.current();
var threads:Array<Thread> = [];
for (i in 0...numThreads)
{
threads.push( Thread.create(function() {
while(true) {
var message:Dynamic = Thread.readMessage(true);
if(message == 'exit')
break;
else
Md5.encode(text);
var arrays = new Array<Array<Wrapper>>();
for(i in 0...100)
{
var wrappers = new Array<Wrapper>();
arrays.push(wrappers);
for(j in 0...1000)
wrappers.push( new Wrapper(1) );
}
var sum = 0;
for(a in arrays)
for(w in a)
sum += w.a;
assertTrue(sum==100000);
}
main.sendMessage('done');
}) );
}
return threads;
}
}

View File

@ -0,0 +1,15 @@
void nativeLoop()
{
while( gc::TestGCThreaded_obj::keepRunning)
{
for(int i=0; i<100; i++)
::gc::Wrapper_obj::__alloc( HX_CTX_GET ,1);
::Sys_obj::sleep(0.01);
}
gc::TestGCThreaded_obj::nativeRunning = false;
}

View File

@ -0,0 +1,149 @@
package native;
@:native("ExternStruct")
extern class ExternStruct
{
@:native("~ExternStruct")
public function destroy():Void;
@:native("new ExternStruct")
public static function create():cpp.Pointer<ExternStruct>;
}
#if !cppia
@:headerCode('
struct ExternStruct {
ExternStruct() { }
~ExternStruct() { }
};
')
class ExternWrapper
{
var pointer:cpp.Pointer<ExternStruct>;
public static var instances:Int = 0;
public function new()
{
pointer = ExternStruct.create();
instances++;
cpp.vm.Gc.setFinalizer(this, cpp.Function.fromStaticFunction(destroy));
}
@:void static public function destroy(ExternWrapper : ExternWrapper) : Void {
instances--;
ExternWrapper.pointer.destroy();
}
}
class CustomFinalizable
{
public static var count = 0;
public function new()
{
cpp.vm.Gc.setFinalizer(this, cpp.Function.fromStaticFunction(__finalizeCallback));
}
function __finalize() : Void count++;
@:void public static function __finalizeCallback(o : CustomFinalizable) : Void
{
if(o != null)
o.__finalize();
else
Sys.println("Null callback object?");
}
}
#end
class MyFinalizable extends cpp.Finalizable
{
public static var count = 0;
public function new()
{
super();
}
override public function finalize()
{
count ++;
}
}
class TestFinalizer extends haxe.unit.TestCase
{
override public function setup()
{
MyFinalizable.count = 0;
CustomFinalizable.count = 0;
}
#if !cppia
function createExternWrapper(i:Int)
{
if (i<=0)
new ExternWrapper();
else
createExternWrapper(i-1);
}
public function testCount()
{
for(i in 0...10)
{
createExternWrapper(2);
cpp.vm.Gc.run(true);
}
Sys.println("\nExtern instances remaining:" + ExternWrapper.instances);
assertTrue( ExternWrapper.instances < 10 );
}
function createCustomFinalizable(i:Int)
{
if (i<=0)
new CustomFinalizable();
else
createCustomFinalizable(i-1);
}
public function testCustomFinalizable()
{
for(i in 0...100)
createCustomFinalizable(2);
cpp.vm.Gc.run(true);
Sys.println("custom cleared:" + CustomFinalizable.count);
assertTrue(CustomFinalizable.count>0);
}
#end
function createMyFinalizable(i:Int)
{
if (i<=0)
new MyFinalizable();
else
createMyFinalizable(i-1);
}
public function testFinalizable()
{
for(i in 0...100)
createMyFinalizable(2);
cpp.vm.Gc.run(true);
Sys.println("MyFinalizable cleared:" + MyFinalizable.count);
assertTrue(MyFinalizable.count>0);
}
}

View File

@ -0,0 +1,21 @@
package;
class Native
{
static function main()
{
var r = new haxe.unit.TestRunner();
r.add(new tests.TestStdio());
r.add(new tests.TestRgb());
r.add(new tests.TestRectangle());
r.add(new tests.TestGlobalNamespace());
r.add(new tests.TestNativeGen());
r.add(new tests.TestNonVirtual());
r.add(new tests.TestPtr());
r.add(new tests.TestNativeEnum());
var t0 = haxe.Timer.stamp();
var success = r.run();
trace(" Time : " + (haxe.Timer.stamp()-t0)*1000 );
Sys.exit(success ? 0 : 1);
}
}

View File

@ -0,0 +1,22 @@
@:nativeGen
@:structAccess
class NativeGen
{
public var x:Float;
public static var y:Int;
public function getValue():Float return x;
public static function someNativeFunction()
{
trace("Hi!");
}
}
@:native("cpp::Struct<NativeGen>")
@:include("NativeGen.h")
extern class NativeGenStruct extends NativeGen
{
}

View File

@ -0,0 +1,4 @@
-cpp bin
-main Native
-D HXCPP_DEBUGGER
-cp ../unit

View File

@ -0,0 +1,44 @@
package externs;
import cpp.UInt8;
import cpp.Pointer;
@:include("./../lib/LibInclude.h")
@:sourceFile("./../lib/RGB.cpp")
@:native("RGB")
extern class RGB
{
public var r:UInt8;
public var g:UInt8;
public var b:UInt8;
public function getLuma():Int;
public function toInt():Int;
@:native("new RGB")
public static function create(r:Int, g:Int, b:Int):Pointer<RGB>;
@:native("~RGB")
public function deleteMe():Void;
}
// By extending RGB we keep the same API as far as haxe is concerned, but store the data (not pointer)
// The native Reference class knows how to take the reference to the structure
@:native("cpp.Reference<RGB>")
extern class RGBRef extends RGB
{
}
// By extending RGBRef, we can keep the same api,
// rather than a pointer
@:native("cpp.Struct<RGB>")
extern class RGBStruct extends RGBRef
{
}

View File

@ -0,0 +1,38 @@
package externs;
import externs.RectangleApi;
@:include("./RectangleDef.h")
@:structAccess
@:native("Rectangle")
extern class Rectangle
{
@:native("Rectangle::instanceCount")
static var instanceCount:Int;
public var x:Int;
public var y:Int;
public var width:Int;
public var height:Int;
public function area() : Int;
@:native("new Rectangle")
@:overload( function():cpp.Star<Rectangle>{} )
@:overload( function(x:Int):cpp.Star<Rectangle>{} )
@:overload( function(x:Int, y:Int):cpp.Star<Rectangle>{} )
@:overload( function(x:Int, y:Int, width:Int):cpp.Star<Rectangle>{} )
static function create(x:Int, y:Int, width:Int, height:Int):cpp.Star<Rectangle>;
@:native("Rectangle")
@:overload( function():Rectangle {} )
@:overload( function(x:Int):Rectangle {} )
@:overload( function(x:Int, y:Int):Rectangle {} )
@:overload( function(x:Int, y:Int, width:Int):Rectangle {} )
static function make(x:Int, y:Int, width:Int, height:Int):Rectangle;
@:native("~Rectangle")
public function delete():Void;
}
typedef RectanglePtr = cpp.Star<Rectangle>;

View File

@ -0,0 +1,9 @@
package externs;
// This class acts as a container for the Rectangle implementation, which will get included
// in the cpp file, and therfore get compiled and linked with the correct flags
@:cppInclude("./RectangleImpl.cpp")
@:keep
class RectangleApi
{
}

View File

@ -0,0 +1,26 @@
#ifndef RECTANGLE_DEF_INCLUDED
#define RECTANGLE_DEF_INCLUDED
struct Rectangle
{
static int instanceCount;
int x;
int y;
int width;
int height;
inline Rectangle(int inX=0, int inY=0, int inW=0, int inH=0) :
x(inX), y(inY), width(inW), height(inH)
{
instanceCount++;
}
inline ~Rectangle()
{
instanceCount--;
}
int area();
};
#endif

View File

@ -0,0 +1,8 @@
#include "RectangleDef.h"
int Rectangle::instanceCount = 0;
int Rectangle::area()
{
return width*height;
}

View File

@ -0,0 +1,4 @@
package externs;
@:native("short *") @:unreflective
extern class ShortPtr { }

View File

@ -0,0 +1,28 @@
#ifndef LIB_INCLUDE_INCLUDED
#define LIB_INCLUDE_INCLUDED
struct RGB
{
unsigned char r;
unsigned char g;
unsigned char b;
RGB(int inR=0, int inG=0, int inB=0) :
r(inR), g(inG), b(inB)
{
}
int getLuma();
int toInt();
};
struct Gradient
{
RGB colour0;
RGB colour1;
int steps;
};
#endif

View File

@ -0,0 +1,5 @@
#include "LibInclude.h"
int RGB::getLuma() { return (r+g+b)/3; }
int RGB::toInt() { return (r<<16) | (g<<8) | b; }

View File

@ -0,0 +1,12 @@
package tests;
class TestGlobalNamespace extends haxe.unit.TestCase
{
var shortPtr:externs.ShortPtr;
public function testGen()
{
assertTrue(true);
}
}

View File

@ -0,0 +1,65 @@
package tests;
// Uses native enum, which does not play nice with Dynamic - must use @:unreflective
@:unreflective
@:enum extern abstract SystemMetric(SystemMetricImpl) {
@:native("wxSYS_MOUSE_BUTTONS") var MOUSE_BUTTONS;
@:native("wxSYS_OS") var OS;
}
@:unreflective
@:native("wxSystemMetric")
extern class SystemMetricImpl { }
// Wraps enum in struct, which does play nice...
@:enum extern abstract SystemMetricStruct(SystemMetricStructImpl) {
@:native("wxSYS_MOUSE_BUTTONS") var MOUSE_BUTTONS;
@:native("wxSYS_OS") var OS;
}
@:native("cpp::Struct<wxSystemMetric, cpp::EnumHandler>")
extern class SystemMetricStructImpl { }
@:headerCode('
enum wxSystemMetric
{
wxSYS_OS = 3,
wxSYS_MOUSE_BUTTONS = 27,
};
')
class TestNativeEnum extends haxe.unit.TestCase
{
var x:SystemMetric = SystemMetric.MOUSE_BUTTONS;
var xStruct:SystemMetricStruct = SystemMetricStruct.MOUSE_BUTTONS;
function isX(val:SystemMetric)
{
return (val==x);
}
function isXStruct(val:SystemMetricStruct)
{
return (val==xStruct);
}
public function test()
{
assertTrue( isX(SystemMetric.MOUSE_BUTTONS)==true );
assertTrue( isX(SystemMetric.OS)==false );
assertTrue( isXStruct(SystemMetricStruct.MOUSE_BUTTONS)==true );
assertTrue( isXStruct(SystemMetricStruct.OS)==false );
var d:Dynamic = this;
assertTrue( d.x==null );
assertTrue( d.xStruct!=null );
assertTrue( d.isX==null );
assertTrue( d.isXStruct!=null );
var func = d.isXStruct;
assertTrue(func!=null);
assertTrue(func(SystemMetricStruct.MOUSE_BUTTONS)==true );
assertTrue(func(SystemMetricStruct.OS)==false );
}
}

View File

@ -0,0 +1,23 @@
package tests;
import NativeGen;
class TestNativeGen extends haxe.unit.TestCase
{
@:unreflective var unreflectiveValue:NativeGen;
@:unreflective public function unreflectiveFunction(inGen:NativeGen)
{
unreflectiveValue = inGen;
return unreflectiveValue.x==22;
}
public function testCreate()
{
var nGen:NativeGenStruct = null;
nGen.x = 22;
assertTrue(nGen.getValue()==22);
assertTrue(unreflectiveFunction(nGen) );
}
}

View File

@ -0,0 +1,37 @@
package tests;
class Base
{
public function new() {}
@:nonVirtual public function getNvName() return "Base";
public function getName() return "Base";
}
class Derived extends Base
{
@:nonVirtual override public function getNvName() return "Derived";
override public function getName() return "Derived";
}
class TestNonVirtual extends haxe.unit.TestCase
{
public function testOverride()
{
var derived = new Derived();
assertTrue( derived.getName() == "Derived" );
assertTrue( derived.getNvName() == "Derived" );
var closure:Dynamic = derived.getNvName;
assertTrue( closure() == "Derived" );
var base:Base = derived;
assertTrue( base.getName() == "Derived" );
assertTrue( base.getNvName() == "Base" );
var closure:Dynamic = base.getNvName;
assertTrue( closure() == "Base" );
}
}

View File

@ -0,0 +1,378 @@
package tests;
import NativeGen;
import cpp.NativeGc;
import cpp.Stdlib;
import cpp.Pointer;
import cpp.RawPointer;
import cpp.UInt8;
using cpp.NativeArray;
using cpp.NativeString;
@:unreflective
@:native("CVec")
extern class Vec {
public var x:Float;
public var y:Float;
public var z:Float;
}
@:unreflective
@:structAccess
@:native("CVec")
extern class VecStructAccess {
public var x:Float;
public var y:Float;
public var z:Float;
@:native("new CVec")
public static function create(val:Float) : Pointer<VecStructAccess>;
public function set99(ioVec:VecStructAccess):Void;
}
@:unreflective
@:native("cpp::Struct<CVec>")
extern class VecStruct {
public var x:Float;
public var y:Float;
public var z:Float;
}
@:native("::SomeStruct")
extern class Native_SomeStruct {
var data:RawPointer<cpp.UInt8>;
var dataLength:Int;
inline function getDataBytes():haxe.io.Bytes {
var bdata:haxe.io.BytesData = [];
cpp.NativeArray.setData(bdata, cast data, dataLength); // Null Function Pointer
return haxe.io.Bytes.ofData(bdata);
}
inline function getUnmanagedDataBytes():haxe.io.Bytes {
var bdata:haxe.io.BytesData = [];
cpp.NativeArray.setUnmanagedData(bdata, cast data, dataLength); // Null Function Pointer
return haxe.io.Bytes.ofData(bdata);
}
}
@:native("::cpp::Reference<SomeStruct>")
extern class SomeStructRef extends Native_SomeStruct {}
@:native("::cpp::Struct<SomeStruct>")
extern class SomeStruct extends SomeStructRef {}
class IntHolder
{
public var ival:Int;
public function new(inVal:Int = 1) ival = inVal;
}
@:headerCode('
struct CVec{
CVec(double inX=0) : x(inX), y(inX), z(inX) { }
double x;
double y;
double z;
void set99(CVec &ioVex) { ioVex.x=99; }
};
struct SomeStruct {
SomeStruct() : data((unsigned char *)"Hi!"), dataLength(3) { }
unsigned char *data;
int dataLength;
};
')
@:cppFileCode('
int callPointer(CVec *) { return 5; }
')
class TestPtr extends haxe.unit.TestCase{
/*
Alternate version
@:generic
public static inline function malloc<T>(size:Int) : cpp.Pointer<T>{
var p : cpp.RawPointer<cpp.Void> = untyped __cpp__("malloc({0})",size);
return cast cpp.Pointer.fromRaw( cast p );
}
*/
public function testMalloc() {
var a : Pointer<Vec> = Stdlib.malloc( Stdlib.sizeof(Vec) );
assertTrue( a!=null );
assertTrue( a.raw!=null );
a.ptr.x = 66;
assertTrue( a.ptr.x == 66 );
Stdlib.free(a);
}
public function testExtened() {
var test = NativeGc.allocateExtended( TestPtr, Stdlib.sizeof(Int) * 5 );
var a : Pointer<Int> = cast Pointer.endOf(test);
for(i in 0...5)
a.setAt(i,i);
for(i in 0...5)
assertTrue( a.postIncRef() == i );
}
function test9194() {
// will fail during C++ compile
var buffer: cpp.RawPointer<cpp.Void> = null;
var floatBuffer: cpp.RawPointer<cpp.Float32> = cast buffer;
// generates incorrect: float* floatBuffer = buffer
// the lack of native casting means the compiler throws an error here
var buffer: cpp.Star<cpp.Void> = null;
var floatBuffer: cpp.Star<cpp.Float32> = cast buffer;
// generates correct: float* floatBuffer = ( (float*) buffer )
assertTrue(floatBuffer==null);
}
public function testNull() {
var nullP : Pointer<Vec> = null;
var nullRawP = nullP.raw;
assertTrue( nullP==null );
assertTrue( null==nullP );
assertFalse( nullP!=null );
assertTrue( nullRawP==null );
assertFalse( nullRawP!=null );
nullRawP = null;
assertTrue( nullRawP==null );
}
private function anonOf(d:Dynamic) : Dynamic return {ptr:d};
public function testStructAccess() {
var e = VecStructAccess.create(1);
var tmp = e.ptr;
var tmp1 = e.ref;
tmp.set99(tmp1);
assertTrue(e.ptr.x==99);
}
@:native("callPointer") @:extern
private static function callPointer(ptr:cpp.Pointer<Vec>):Int;
public function testPointerCast() {
var map = new Map<Int, cpp.Pointer<Vec> >();
map.set(1,null);
var result = callPointer( map.get(2) );
assertTrue(result==5);
}
public function testDynamic() {
var a = [1];
var intPtr = a.address(0);
var d:Dynamic = intPtr;
assertFalse(d==[2].address(0));
assertTrue(d==a.address(0));
var anon = anonOf(d);
assertFalse([2].address(0)==d);
assertTrue(a.address(0)==d);
assertFalse(intPtr==[2].address(0));
assertTrue(intPtr==a.address(0));
assertFalse(anon.ptr==[2].address(0));
assertTrue(anon.ptr==a.address(0));
assertFalse([2].address(0)==anon.ptr);
assertTrue(a.address(0)==anon.ptr);
}
function getAnonI(a:Dynamic) : Dynamic
{
return a.i;
}
public function testAnon() {
var a = [1];
var intPtr = a.address(0);
var anon = { i:intPtr };
assertTrue( getAnonI(anon)==intPtr );
var vecPtr = VecStructAccess.create(1);
var anon = { i:vecPtr };
assertTrue( getAnonI(anon)==vecPtr );
var vec:VecStruct = null;
vec.x = 123;
var anon = { i:vec };
assertTrue( getAnonI(anon)==vec );
}
static function callMe(x:Int) return 10+x;
static function notProcAddress(module:String, func:String) return null;
public function testArrayAccess() {
var array = [ 0.0, 1.1, 2.2, 3.3 ];
var ptr = cpp.Pointer.arrayElem(array, 0);
assertTrue( ptr[1]==1.1 );
ptr[1] = 2;
assertTrue( ptr[1]==2 );
ptr[1]++;
assertTrue( ptr[1]==3 );
ptr[1]-=2.5;
assertTrue( ptr[1]==0.5 );
var raw = ptr.raw;
assertTrue( raw[2]==2.2 );
raw[2] = 2;
assertTrue( raw[2]==2 );
raw[2]++;
assertTrue( raw[2]==3 );
raw[2]-=2.5;
assertTrue( raw[2]==0.5 );
}
public function testFromRaw()
{
var i = new IntHolder(3);
var ptr = cpp.Pointer.fromRaw(cpp.Pointer.addressOf(i).rawCast());
assertTrue( ptr.ref.ival==i.ival );
ptr.ref.ival==23;
assertTrue( ptr.ref.ival==i.ival );
}
private static var output:cpp.Pointer<Array<Int>>;
private static var arrayValue:Array<Int>;
private static function makeValue():{ a:cpp.Pointer<Array<Int>> }
{
arrayValue = [9];
return { a: cpp.Pointer.addressOf(arrayValue) };
}
@:analyzer(no_fusion)
public function testDynamicOutput()
{
// Declared as structure (just `var val = ...` works too)
var val:{ a:cpp.Pointer<Array<Int>> } = makeValue();
var a:cpp.Pointer<Array<Int>> = val.a;
output = a;
output = (val.a:Dynamic);
output = val.a;
output = (val.a:cpp.Pointer<Array<Int>>);
val.a = output;
// Declared as Dynamic
var val2:Dynamic = makeValue();
a = val2.a;
output = a;
output = (val2.a:Dynamic);
output = val2.a;
output = (val2.a:cpp.Pointer<Array<Int>>);
val2.a = output;
assertTrue( val2.a==output );
assertTrue( output==val.a );
}
public function testAutoCast() {
var z = [ 1, 2, 3 ];
assertTrue( cpp.NativeArray.address(z, 0).ptr == cpp.NativeArray.address(z, 0).ptr );
assertTrue( cpp.NativeArray.address(z, 1).ptr != cpp.NativeArray.address(z, 0).ptr );
assertTrue( cpp.NativeArray.address(z, 1).gt(cpp.NativeArray.address(z, 0)) );
assertTrue( cpp.NativeArray.address(z, 1).geq(cpp.NativeArray.address(z, 0)) );
assertTrue( cpp.NativeArray.address(z, 1).geq(cpp.NativeArray.address(z, 1)) );
assertTrue( cpp.NativeArray.address(z, 0).leq(cpp.NativeArray.address(z, 0)) );
assertTrue( cpp.NativeArray.address(z, 1).leq(cpp.NativeArray.address(z, 2)) );
assertTrue( cpp.NativeArray.address(z, 1).leq(cpp.NativeArray.address(z, 2)) );
assertTrue( cpp.NativeArray.address(z, 0) == cpp.Pointer.ofArray(z) );
assertTrue( cpp.NativeArray.address(z, 1) == cpp.Pointer.arrayElem(z,1) );
assertTrue( cpp.NativeArray.address(z, 1) != cpp.Pointer.fromHandle(null) );
assertTrue( cpp.Function.fromStaticFunction(callMe)(1)==11 );
try
{
assertTrue( cpp.Function.fromStaticFunction(notProcAddress)!=cpp.Function.getProcAddress("nomodule","nofunc!") );
}
catch(e:Dynamic)
{
// Could not load module - expected
}
}
static function functionCaller(fn:cpp.Function<Void->Int,cpp.abi.Abi>) {
var a = fn.call();
}
public function testFunctionStructAccess() {
assertTrue( functionCaller != null );
}
public function testSetData() {
var ss:SomeStruct = null;
ss.dataLength = 4;
ss.data = cast "bye!".c_str();
var b = ss.getDataBytes();
assertTrue( b.getString(0, b.length) == "bye!" );
var ss:SomeStruct = null;
var b = ss.getUnmanagedDataBytes();
assertTrue( b.getString(0, b.length) == "Hi!" );
}
public function testZero() {
var a = [1,2,3];
a.zero();
assertTrue(a.length==3);
assertTrue(a[0]==0);
assertTrue(a[1]==0);
assertTrue(a[2]==0);
}
public function testMemcmp() {
var a = [1,2,3];
var b = [2,2,3];
assertTrue( a.memcmp(b) == -1 );
assertTrue( b.memcmp(a) == 1 );
assertTrue( a.memcmp(a) == 0 );
}
public function testCapacity() {
var a = [1,2,3];
assertTrue( a.capacity() < 1000 );
a.reserve(1000);
assertTrue( a.capacity() == 1000 );
a[1000] = 1;
assertTrue( a.capacity() > 1000 );
}
public function testElementSize() {
var a = [1];
assertTrue( a.getElementSize() == cpp.Stdlib.sizeof(Int) );
var a = ["hello!"];
assertTrue( a.getElementSize() == cpp.Stdlib.sizeof(String) );
var a = [7.1];
assertTrue( a.getElementSize() == cpp.Stdlib.sizeof(Float) );
}
public function testBlit() {
var a = [1,2,3,4];
var b = [0,0,0,0];
b.blit(0,a,0,a.length);
for(i in 0...4)
assertTrue(b[i] == a[i]);
for(i in 0...4)
b.blit(i,a,0,1);
for(i in 0...4)
assertTrue(b[i] == a[0]);
for(i in 0...4)
b.blit(i,a,2,1);
for(i in 0...4)
assertTrue(b[i] == a[2]);
}
}

View File

@ -0,0 +1,107 @@
package tests;
import externs.Rectangle;
class TestRectangle extends haxe.unit.TestCase
{
static var statRect:Rectangle;
static var statRectPtr:RectanglePtr;
static var statRectProp(get,set):Rectangle;
static var statRectPtrProp(get,set):RectanglePtr;
var memRect:Rectangle;
var memRectPtr:RectanglePtr;
var memRectProp(get,set):Rectangle;
var memRectPtrProp(get,set):RectanglePtr;
static function get_statRectProp() return statRect;
static function set_statRectProp(val:Rectangle) return statRect=val;
static function get_statRectPtrProp() return statRectPtr;
static function set_statRectPtrProp(val:RectanglePtr) return statRectPtr=val;
function get_memRectProp() return memRect;
function set_memRectProp(val:Rectangle) return memRect=val;
function get_memRectPtrProp() return memRectPtr;
function set_memRectPtrProp(val:RectanglePtr) return memRectPtr=val;
public function testRect()
{
// Struct - copy semantic
var rectangle = Rectangle.make(3,4);
assertTrue( rectangle.area()==0 );
var rect2 = rectangle;
rect2.width = 2;
rect2.height = 4;
assertTrue( rect2.area()==8 );
assertTrue( rectangle.area()==0 );
// Take address ...
var rectPtr:RectanglePtr = rectangle;
// Pointer-like sysntax
rectPtr.width = 3;
rectPtr.height = 5;
var dynamicPtr:Dynamic = rectPtr;
assertTrue( rectPtr.area()==15 );
// Same object
assertTrue( rectangle.area()==15 );
var dynamicCopy:Dynamic = rectangle; // 3,4 3x5
rectangle.width = 10;
rectangle.height = 10;
assertTrue( rectangle.area()==100 );
// points to original object
var fromDynamic:RectanglePtr = rectPtr;
assertTrue( fromDynamic.area()==100 );
// Restore from Dynamic ...
rectangle = dynamicCopy;
assertTrue( rectangle.area()==15 );
}
public function testReflect()
{
statRect = Rectangle.make(1,2,3,4);
memRect = Rectangle.make(4,5,6,7);
// This is not correct in the GC moving case ...
//statRectPtr = memRect;
statRectPtr = Rectangle.create(1,1,2,2);
memRectPtr = statRect;
assertTrue( statRectProp.area()==12 );
assertTrue( memRectProp.area()==42 );
assertTrue( statRectPtrProp.area()==4 );
assertTrue( memRectPtrProp.area()==12 );
var d:Dynamic = this;
var r:Rectangle = d.memRect;
assertTrue( r.area()==42 );
var prop:Rectangle = Reflect.getProperty(d,"memRectProp");
assertTrue( prop.area()==42 );
var propPtr:RectanglePtr = Reflect.getProperty(d,"memRectPtrProp");
assertTrue( propPtr.area()==12 );
var d:Dynamic = TestRectangle;
var r:Rectangle = d.statRect;
assertTrue( r.area()==12 );
var prop:Rectangle = Reflect.getProperty(d,"statRectProp");
assertTrue( prop.area()==12 );
var propPtr:RectanglePtr = Reflect.getProperty(d,"statRectPtrProp");
assertTrue( propPtr.area()==4 );
// No longer valid
statRectPtr.delete();
statRectPtr = null;
}
}

View File

@ -0,0 +1,53 @@
package tests;
import externs.RGB;
class TestRgb extends haxe.unit.TestCase
{
public function testCreate()
{
// Pointer-like sysntax
var rgbPtr = RGB.create(255,0,128);
assertTrue( rgbPtr.ptr.toInt() == 0xff0080 );
rgbPtr.ptr.deleteMe();
// Structure-like syntax
var rgbStruct:RGBStruct = null;
rgbStruct.r = 1;
rgbStruct = null;
rgbStruct.r = 1;
rgbStruct.g = 2;
rgbStruct.b = 3;
assertTrue( rgbStruct.toInt() == 0x010203 );
// Store in dynamic
var d:Dynamic = rgbStruct;
// Reference (pointer) like syntax
var rgbRef:RGBRef = rgbStruct;
rgbRef.g = 255;
assertTrue( rgbStruct.toInt() == 0x01ff03 );
// Get from dynamic
rgbStruct = d;
assertTrue( rgbStruct.toInt() == 0x010203 );
var rgbStruct2:RGBStruct = cast rgbRef;
assertTrue( rgbStruct2.toInt() == 0x010203 );
// Reference refers to rgbStruct, not rgbStruct2
rgbRef.b = 0;
assertTrue( rgbStruct2.toInt() == 0x010203 );
assertTrue( rgbStruct.toInt() == 0x010200 );
// TODO - non-dynamic versions
var d2:Dynamic = rgbStruct2;
// == dynamic
assertTrue( d2==d );
// != dynamic
var d0:Dynamic = rgbStruct;
assertTrue( d0!=d );
}
}

View File

@ -0,0 +1,23 @@
package tests;
import cpp.Stdio;
using cpp.NativeArray;
class TestStdio extends haxe.unit.TestCase
{
public function test()
{
var file = Stdio.fopen("test.txt", "wb");
var ints = [1];
var size:cpp.SizeT = cpp.Stdlib.sizeof(Int);
Stdio.fwrite( ints.address(0).raw, size, 1, file );
Stdio.fclose(file);
var bytes = sys.io.File.getBytes("test.txt");
var input = new haxe.io.BytesInput(bytes);
var val = input.readInt32();
assertTrue(val==ints[0]);
}
}

View File

@ -0,0 +1,100 @@
class MkOps
{
public static function main()
{
var file = [];
file.push("enum E { EVal0; EVal1; }");
file.push("class Ops {");
file.push(" public static var data: { ?f:Float };");
file.push(" public static function check(b:Bool) { }");
file.push(" public static function main() {");
file.push(" var d:Dynamic = null;");
file.push(" var ai = [1]; var fi=[1.2];");
file.push(" var int:Int=0;");
file.push(" var anon={a:Int, b:[2], c:EVal0};");
file.push(" var anon2:Dynamic={a:1};");
file.push(" var dynArray:Array<Dynamic> = [1];");
file.push(" var uint8:cpp.UInt8 = 1;");
file.push(" var int8:cpp.Int8 = 1;");
file.push(" var uint16:cpp.UInt16 = 1;");
file.push(" var int16:cpp.Int16 = 1;");
file.push(" var uint64:cpp.UInt64 = 1;");
file.push(" var int64:cpp.Int64 = 1;");
file.push(" var string = 'S0';");
file.push(" var arrarr = [ [12] ];");
file.push(" var arrdyn = [ [d] ];");
file.push(" var arrdynarray = [ [dynArray] ];");
file.push(" var eval = EVal0;");
var exprs = [ "d", "null", "int", "ai", "ai[0]", "fi", "fi[0]", "anon.a", "anon.b", "anon.c", "anon", "anon2.xyz", "dynArray", "dynArray[0]", "3.8", '"Hello"', "uint8", "int8", "uint16", "int16", "uint64", "int64", "string", "arrarr", "arrarr[0]", "arrarr[0][0]", "arrdyn", "arrdynarray", "EVal1", "eval", "data.f" ];
var total = 0;
for(e1 in exprs)
{
for(e2 in exprs)
{
file.push('check( $e1 != $e2 );');
file.push('check( $e1 == $e2 );');
file.push('check( $e1 > $e2 );');
file.push('$e1 = $e2;');
total += 4;
if (!skipPlus(e1) && !skipPlus(e2))
{
file.push('$e1 += $e2;');
file.push('$e1 -= $e2;');
file.push('$e1 /= $e2;');
file.push('$e1 / $e2;');
file.push('$e1 *= $e2;');
total +=5;
}
}
}
file.push("}}");
// Pass0 catches common stuff
// Pass1 checks for "null on static targets"
// Pass2 should work
var errors = 0;
for(pass in 0...3)
{
sys.io.File.saveContent("Ops.hx", file.join("\n") );
var proc = new sys.io.Process("haxe", ["-cpp", "cpp", "-D", "no-compilation", "-main", "Ops"] );
try
{
var stderr = proc.stderr;
var errMatch = ~/^Ops.hx:(\d+):(.*)/;
while(true)
{
var line = stderr.readLine();
if (errMatch.match(line))
{
var errLine = Std.parseInt(errMatch.matched(1));
file[errLine-1] = "// " + errMatch.matched(2) + " " + file[errLine-1];
errors++;
}
}
}
catch(e:Dynamic) { }
var code = proc.exitCode();
Sys.println(' pass error $code, total errors = $errors/$total');
if (pass==2 && code!=0)
{
Sys.println("Still errors after 3 passes - aborting");
Sys.exit(-1);
}
}
var code = Sys.command("haxe", ["-cpp", "cpp", "-main", "Ops"] );
Sys.println("Combos : " + total);
Sys.println("Exit code : " + code);
Sys.exit(code);
}
// + and arrays do not mix...
static function skipPlus(e:String)
{
return e=="ai" || e=="arrarr" || e=="arrdyn" || e=="arrarr[0]" || e=="fi" ||
e=="arrdynarray" || e=="dynArray" || e=="eval" || e=="anon.b" || e== "EVal1";
}
}

View File

@ -0,0 +1,24 @@
import cpp.*;
// Windows only.
// Compile with "-D no_console" for best effect
@:cppFileCode("#include <windows.h>")
class MessageBox
{
public static function main()
{
var messageBox:cpp.Function< Pointer< Void > ->
ConstCharStar ->
ConstCharStar ->
Int -> Int, cpp.abi.Winapi > =
Function.getProcAddress("User32.dll", "MessageBoxA");
messageBox(null, "Hello, World!", "Hxcpp MessageBox", 0);
// This will actually print out if you have started from a console (not double-click)
trace("Sneaky trace");
}
}

View File

@ -0,0 +1,4 @@
-main MessageBox
-cpp cpp
-D no_console
-cmd start cpp/MessageBox.exe

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<project>
<app
file="TestLib"
title="TestLib"
package="org.haxe.hxcpp.TestLib"
version="1.0"
company="nme"
main="Test"
/>
<window
width="640"
height="480"
orientation="landscape"
fps="60"
background="0xffffff"
resizeable="true"
hardware="true"
/>
<classpath name="." />
<haxelib name="nme" />
<assets>
<asset name="Test.hx" />
</assets>
<ndll name="std" />
<ndll name="regexp" />
<ndll name="zlib" />
<ndll name="nme" haxelib="nme" nekoapi="1"/>
<certificates>
<certificate file="signature.cer" name="mysign" password="ajkhsakjhf" />
</certificates>
</project>

View File

@ -0,0 +1,5 @@
-main Test
-cpp cpp32
-D HXCPP_M32
-D HXCPP_DEBUGGER
-cp ../unit

View File

@ -0,0 +1,4 @@
-main Test
-cpp cpp64
-D HXCPP_M64
-cp ../unit

View File

@ -0,0 +1,8 @@
-main Test
-cpp arm32
-D android
-D exe_link
-cp ../unit
-cmd adb push arm32/Test /storage/ext_sd
-cmd adb push Test.hx /storage/ext_sd
-cmd adb shell "cd /storage/ext_sd && ./Test"

View File

@ -0,0 +1,19 @@
class TestBasic extends haxe.unit.TestCase
{
public function new() super();
function testStartTelemetry(string:String)
{
var thread_id:Int = startTelemetry(true, true);
assertTrue(thread_id>=0);
}
function startTelemetry(with_profiler:Bool=true,
with_allocations:Bool=true):Int
{
// Compile will fail without -D HXCPP_TELEMETRY
return untyped __global__.__hxcpp_hxt_start_telemetry(with_profiler,
with_allocations);
}
}

View File

@ -0,0 +1,13 @@
package;
class TestMain {
static function main(){
var r = new haxe.unit.TestRunner();
r.add(new TestBasic());
var t0 = haxe.Timer.stamp();
var success = r.run();
trace(" Time : " + (haxe.Timer.stamp()-t0)*1000 );
Sys.exit(success ? 0 : 1);
}
}

View File

@ -0,0 +1,6 @@
-cpp bin
-main TestMain
-resource TestMain.hx
-D HXCPP_TELEMETRY
-D HXCPP_STACK_TRACE
-cp ../unit

View File

@ -0,0 +1,2 @@
haxe compile.hxml
"bin/TestMain.exe"

View File

@ -0,0 +1,40 @@
import sys.thread.Thread;
import sys.io.File;
@:cppInclude("./ThreadCode.cpp")
class Test
{
static var mainThread:Thread;
@:native("runThread")
extern static function createNativeThread():Void;
public static function callFromThread()
{
trace("Same:" + (mainThread==Thread.current()) );
mainThread.sendMessage("Done");
}
public static function main()
{
var me = Thread.current();
mainThread = me;
Thread.create( function() {
File.copy("a.txt","b.txt");
me.sendMessage("Done");
trace("Same thread:" + (me==Thread.current()) );
} );
var result = Thread.readMessage(true);
trace(result);
for(x in 0...20)
{
trace("call...");
createNativeThread();
trace("zzz...");
Sys.sleep(1);
var result = Thread.readMessage(true);
trace(result);
}
}
}

View File

@ -0,0 +1,16 @@
#include <hx/Native.h>
#include <hx/Thread.h>
THREAD_FUNC_TYPE threadFunc(void *data)
{
printf("In thread\n");
hx::NativeAttach attach;
Test_obj::callFromThread();
THREAD_FUNC_RET
}
void runThread()
{
HxCreateDetachedThread(threadFunc,nullptr);
}

View File

@ -0,0 +1 @@
hello

View File

@ -0,0 +1,4 @@
-main Test
-cpp cpp
-debug
-cp ../unit

View File

@ -0,0 +1,116 @@
/*
* Copyright (C)2005-2017 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package haxe.unit;
import haxe.PosInfos;
/**
This unit test class should be extended to create test cases. Each test
method created in this extended class should start with the name "test".
These test methods should call the assertion methods:
* `assertTrue(a)`: Succeeds if `a` is `true`.
* `assertFalse(a)`: Succeeds if `a` is `false`.
* `assertEquals(expected, actual)`: Succeeds if `expected` and `actual`
are equal.
```haxe
class MyTestCase extends haxe.unit.TestCase {
function testBasic() {
assertEquals("A", "A");
}
}
```
The TestCase can be tested using `TestRunner`.
To run code before or after the test, override the functions `setup`
and `tearDown`.
@see <https://haxe.org/manual/std-unit-testing.html>
**/
@:keepSub
@:publicFields
class TestCase {
/**
The current test status of the TestRunner.
**/
public var currentTest : TestStatus;
public function new( ) {
}
/**
Override this method to execute code before the test runs.
**/
public function setup() : Void {
}
/**
Override this method to execute code after the test ran.
**/
public function tearDown() : Void {
}
function print( v : Dynamic ) {
haxe.unit.TestRunner.print(v);
}
/**
Succeeds if `b` is `true`.
**/
function assertTrue( b:Bool, ?c : PosInfos ) : Void {
currentTest.done = true;
if (b != true){
currentTest.success = false;
currentTest.error = "expected true but was false";
currentTest.posInfos = c;
throw currentTest;
}
}
/**
Succeeds if `b` is `false`.
**/
function assertFalse( b:Bool, ?c : PosInfos ) : Void {
currentTest.done = true;
if (b == true){
currentTest.success = false;
currentTest.error = "expected false but was true";
currentTest.posInfos = c;
throw currentTest;
}
}
/**
Succeeds if `expected` and `actual` are equal.
**/
function assertEquals<T>( expected: T , actual: T, ?c : PosInfos ) : Void {
currentTest.done = true;
if (actual != expected){
currentTest.success = false;
currentTest.error = "expected '" + expected + "' but was '" + actual + "'";
currentTest.posInfos = c;
throw currentTest;
}
}
}

View File

@ -0,0 +1,100 @@
/*
* Copyright (C)2005-2017 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package haxe.unit;
/**
TestResult contains the result of the executed unit tests.
**/
class TestResult {
var m_tests : List<TestStatus>;
/**
`true` if the unit test succesfully executed the test cases.
**/
public var success(default, null) : Bool;
public function new() {
m_tests = new List();
success = true;
}
public function add( t:TestStatus ) : Void {
m_tests.add(t);
if( !t.success )
success = false;
}
/**
String representation from the result of the unit test.
**/
public function toString() : String {
var buf = new StringBuf();
var failures = 0;
for ( test in m_tests ){
if (test.success == false){
buf.add("* ");
buf.add(test.classname);
buf.add("::");
buf.add(test.method);
buf.add("()");
buf.add("\n");
buf.add("ERR: ");
if( test.posInfos != null ){
buf.add(test.posInfos.fileName);
buf.add(":");
buf.add(test.posInfos.lineNumber);
buf.add("(");
buf.add(test.posInfos.className);
buf.add(".");
buf.add(test.posInfos.methodName);
buf.add(") - ");
}
buf.add(test.error);
buf.add("\n");
if (test.backtrace != null) {
buf.add(test.backtrace);
buf.add("\n");
}
buf.add("\n");
failures++;
}
}
buf.add("\n");
if (failures == 0)
buf.add("OK ");
else
buf.add("FAILED ");
buf.add(m_tests.length);
buf.add(" tests, ");
buf.add(failures);
buf.add(" failed, ");
buf.add( (m_tests.length - failures) );
buf.add(" success");
buf.add("\n");
return buf.toString();
}
}

View File

@ -0,0 +1,186 @@
/*
* Copyright (C)2005-2017 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package haxe.unit;
import Reflect;
/**
This class runs unit test cases and prints the result.
```haxe
var r = new haxe.unit.TestRunner();
r.add(new MyTestCase());
// add other TestCases here
// finally, run the tests
r.run();
```
@see <https://haxe.org/manual/std-unit-testing.html>
**/
class TestRunner {
/**
The unit test results. Available after the `run()` is called.
**/
public var result(default, null) : TestResult;
var cases : List<TestCase>;
#if flash
static var tf : flash.text.TextField = null;
#end
/**
Prints the given object/value.
* Flash outputs the result in a new `TextField` on stage.
* JavaScript outputs the result using `console.log`.
* Other targets use native `print` to output the result.
This function is `dynamic` so it can be overriden in custom setups.
**/
public static dynamic function print( v : Dynamic ) untyped {
#if flash
if( tf == null ) {
tf = new flash.text.TextField();
tf.selectable = false;
tf.width = flash.Lib.current.stage.stageWidth;
tf.autoSize = flash.text.TextFieldAutoSize.LEFT;
flash.Lib.current.addChild(tf);
}
tf.appendText(v);
#elseif neko
__dollar__print(v);
#elseif php
php.Lib.print(v);
#elseif cpp
cpp.Lib.print(v);
#elseif js
var msg = js.Boot.__string_rec(v,"");
var d;
if( __js__("typeof")(document) != "undefined"
&& (d = document.getElementById("haxe:trace")) != null ) {
msg = StringTools.htmlEscape(msg).split("\n").join("<br/>");
d.innerHTML += msg+"<br/>";
}
else if ( __js__("typeof process") != "undefined"
&& __js__("process").stdout != null
&& __js__("process").stdout.write != null)
__js__("process").stdout.write(msg); // node
else if ( __js__("typeof console") != "undefined"
&& __js__("console").log != null )
__js__("console").log(msg); // document-less js (which may include a line break)
#elseif cs
cs.system.Console.Write(v);
#elseif java
var str:String = v;
untyped __java__("java.lang.System.out.print(str)");
#elseif python
python.Lib.print(v);
#elseif (hl || lua)
Sys.print(Std.string(v));
#end
}
private static function customTrace( v, ?p : haxe.PosInfos ) {
print(p.fileName+":"+p.lineNumber+": "+Std.string(v)+"\n");
}
public function new() {
result = new TestResult();
cases = new List();
}
/**
Add TestCase instances to the unit test.
**/
public function add( c:TestCase ) : Void{
cases.add(c);
}
/**
Runs the unit tests and prints the results.
@return `true` if the unit test succesfully executed the test cases.
**/
public function run() : Bool {
result = new TestResult();
for ( c in cases ){
runCase(c);
}
print(result.toString());
return result.success;
}
function runCase( t:TestCase ) : Void {
var old = haxe.Log.trace;
haxe.Log.trace = customTrace;
var cl = Type.getClass(t);
var fields = Type.getInstanceFields(cl);
print( "Class: "+Type.getClassName(cl)+" ");
for ( f in fields ){
var fname = f;
var field = Reflect.field(t, f);
if ( StringTools.startsWith(fname,"test") && Reflect.isFunction(field) ){
t.currentTest = new TestStatus();
t.currentTest.classname = Type.getClassName(cl);
t.currentTest.method = fname;
t.setup();
try {
Reflect.callMethod(t, field, new Array());
if( t.currentTest.done ){
t.currentTest.success = true;
print(".");
}else{
t.currentTest.success = false;
t.currentTest.error = "(warning) no assert";
print("W");
}
}catch ( e : TestStatus ){
print("F");
t.currentTest.backtrace = haxe.CallStack.toString(haxe.CallStack.exceptionStack());
}catch ( e : Dynamic ){
print("E");
#if js
if( e.message != null ){
t.currentTest.error = "exception thrown : "+e+" ["+e.message+"]";
}else{
t.currentTest.error = "exception thrown : "+e;
}
#else
t.currentTest.error = "exception thrown : "+e;
#end
t.currentTest.backtrace = haxe.CallStack.toString(haxe.CallStack.exceptionStack());
}
result.add(t.currentTest);
t.tearDown();
}
}
print("\n");
haxe.Log.trace = old;
}
}

View File

@ -0,0 +1,72 @@
/*
* Copyright (C)2005-2017 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package haxe.unit;
import haxe.CallStack;
import haxe.PosInfos;
/**
The status information of a unit test case method.
@see <https://haxe.org/manual/std-unit-testing.html>
**/
class TestStatus {
/**
`true` when the unit test is executed.
**/
public var done : Bool;
/**
`true` when succesfully unit tested.
**/
public var success : Bool;
/**
The error message of the unit test method.
**/
public var error : String;
/**
The method name of the unit test.
**/
public var method : String;
/**
The class name of the unit test.
**/
public var classname : String;
/**
The position information of the unit test.
**/
public var posInfos : PosInfos;
/**
The representation of the stack exception.
**/
public var backtrace : String;
public function new() {
done = false;
success = false;
}
}