Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/assets/app/bootstrap.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// A sample code how to catch uncaught errors
global.__onUncaughtError = function(error){
if(error.nativeException){
Log("err.message: " + error.message);
Log("err.stackTrace: " + error.stackTrace);
// false == do not continue execution
return false;
}
Expand Down
270 changes: 270 additions & 0 deletions src/assets/app/tests/testModules/numericConversionTests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
/*
Test suite for numeric conversions and constructor/method resolutions.
*/

var Assert = function(condition, failMessage) {
if (condition == false) {
fail(failMessage);
}
}

var TestCreateInstanceWithConstructorResolutionWithNumberLiteral = function() {

Log("TEST: TestCreateInstanceWithConstructorResolutionWithNumberLiteral");

var n = new com.tns.tests.NumericConversionTest(123);

var s = n.getInit();

Assert(s === "byte", "TestCreateInstanceWithConstructorResolutionWithNumberLiteral FAILED: Expected value is 'byte', actual value=" + s);
}

var TestCreateInstanceWithConstructorResolutionWithCastFunctions = function() {

Log("TEST: TestCreateInstanceWithConstructorResolutionWithCastFunctions");

var n1 = new com.tns.tests.NumericConversionTest(byte(123));
var s1 = n1.getInit();
Assert(s1 === "byte", "TestCreateInstanceWithConstructorResolutionWithCastFunctions FAILED: Expected value is 'byte', actual value=" + s1);

var n2 = new com.tns.tests.NumericConversionTest(short(123));
var s2 = n2.getInit();
Assert(s2 === "byte", "TestCreateInstanceWithConstructorResolutionWithCastFunctions FAILED: Expected value is 'byte', actual value=" + s2);

var n3 = new com.tns.tests.NumericConversionTest(long(123));
var s3 = n3.getInit();
Assert(s3 === "byte", "TestCreateInstanceWithConstructorResolutionWithCastFunctions FAILED: Expected value is 'byte', actual value=" + s3);
}

var TestCreateInstanceWithConstructorResolutionWithValuesFromJavaCalls = function() {

Log("TEST: TestCreateInstanceWithConstructorResolutionWithValuesFromJavaCalls");

var b = java.lang.Byte.parseByte("123");
var n1 = new com.tns.tests.NumericConversionTest(b);
var s1 = n1.getInit();
Assert(s1 === "byte", "TestCreateInstanceWithConstructorResolutionWithValuesFromJavaCalls FAILED: Expected value is 'byte', actual value=" + s1);

var i = java.lang.Integer.parseInt("12345");
var n2 = new com.tns.tests.NumericConversionTest(i);
var s2 = n2.getInit();
Assert(s2 === "byte", "TestCreateInstanceWithConstructorResolutionWithValuesFromJavaCalls FAILED: Expected value is 'byte', actual value=" + s2);
}

var TestCreateInstanceWithConstructorResolutionWithPromotingValueUp = function() {

Log("TEST: TestCreateInstanceWithConstructorResolutionWithPromotingValueUp");

var n = new com.tns.tests.NumericConversionTest(null, short(1));
var s = n.getInit();
Assert(s === "Object,int", "TestCreateInstanceWithConstructorResolutionWithPromotingValueUp FAILED: Expected value is 'Object,int', actual value=" + s);
}

var TestCreateInstanceWithConstructorResolutionWithPromotingValueDown = function() {

Log("TEST: TestCreateInstanceWithConstructorResolutionWithPromotingValueDown");

var n = new com.tns.tests.NumericConversionTest(null, null, long(1));
var s = n.getInit();
Assert(s === "Object,Object,short", "TestCreateInstanceWithConstructorResolutionWithPromotingValueDown FAILED: Expected value is 'Object,Object,short', actual value=" + s);
}

var TestCallMethodWithResolutionWithPromotingValueUp = function() {

Log("TEST: TestCallMethodWithResolutionWithPromotingValueUp");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method1(byte(1));
Assert(s === "short=1", "TestCallMethodWithResolutionWithPromotingValueUp FAILED: Expected value is 'short=1', actual value=" + s);
}

var TestCallMethodWithResolutionWithPromotingValueDown = function() {

Log("TEST: TestCallMethodWithResolutionWithPromotingValueDown");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method1(1);
Assert(s === "short=1", "TestCallMethodWithResolutionWithPromotingValueDown FAILED: Expected value is 'short=1', actual value=" + s);

var n1 = new com.tns.tests.NumericConversionTest();
var s1 = n1.method1(long((1 << 16) + 2));
Assert(s1 === "short=2", "TestCallMethodWithResolutionWithPromotingValueDown FAILED: Expected value is 'short=2', actual value=" + s1);
}

var TestLongCastToFloatConversionWhenThereIsDoubleOverload = function() {

Log("TEST: TestLongCastToFloatConversionWhenThereIsDoubleOverload");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method2(long(65536 + 2));
Assert(s === "float=65538.0", "TestLongCastToFloatConversionWhenThereIsDoubleOverload FAILED: Expected value is 'float=65538.0', actual value=" + s);
}

var TestByteCastToFloatConversionWhenThereIsDoubleOverload = function() {

Log("TEST: TestByteCastToFloatConversionWhenThereIsDoubleOverload");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method2(byte(65536 + 2));
Assert(s === "float=2.0", "TestByteCastToFloatConversionWhenThereIsDoubleOverload FAILED: Expected value is 'float=2.0', actual value=" + s);
}

var TestShortCastToFloatConversionWhenThereIsDoubleOverload = function() {

Log("TEST: TestShortCastToFloatConversionWhenThereIsDoubleOverload");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method2(short(65536 + 2));
Assert(s === "float=2.0", "TestShortCastToFloatConversionWhenThereIsDoubleOverload FAILED: Expected value is 'float=2.0', actual value=" + s);
}

var TestDoubleCastWhenThereIsDoubleOverload = function() {

Log("TEST: TestDoubleCastWhenThereIsDoubleOverload");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method2(double(65536 + 2));
Assert(s === "double=65538.0", "TestDoubleCastWhenThereIsDoubleOverload FAILED: Expected value is 'double=65538.0', actual value=" + s);
}

var TestNumberExpressionToFloatConversionWhenThereIsDoubleOverload = function() {

Log("TEST: TestNumberExpressionToFloatConversionWhenThereIsDoubleOverload");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method2(65536 + 2);
Assert(s === "float=65538.0", "TestNumberExpressionToFloatConversionWhenThereIsDoubleOverload FAILED: Expected value is 'float=65538.0', actual value=" + s);
}

var TestDoubleCastToLongConversionWhenThereIsShortOverload = function() {

Log("TEST: TestDoubleCastToLongConversionWhenThereIsShortOverload");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method3(double(65536 + 2));
Assert(s === "long=65538", "TestDoubleCastToLongConversionWhenThereIsShortOverload FAILED: Expected value is 'long=65538', actual value=" + s);
}

var TestFloatCastToLongConversionWhenThereIsShortOverload = function() {

Log("TEST: TestFloatCastToLongConversionWhenThereIsShortOverload");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method3(float(65536 + 2));
Assert(s === "long=65538", "TestFloatCastToLongConversionWhenThereIsShortOverload FAILED: Expected value is 'long=65538', actual value=" + s);
}

var TestFloatCastToShortConversionWhenThereIsObjectOverload = function() {

Log("TEST: TestFloatCastToShortConversionWhenThereIsObjectOverload");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method4(float(65536 + 2));
Assert(s === "short=2", "TestFloatCastToShortConversionWhenThereIsObjectOverload FAILED: Expected value is 'short=2', actual value=" + s);
}

var TestByteCastToShortConversionWhenThereIsObjectOverload = function() {

Log("TEST: TestByteCastToShortConversionWhenThereIsObjectOverload");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method4(byte(65536 + 2));
Assert(s === "short=2", "TestByteCastToShortConversionWhenThereIsObjectOverload FAILED: Expected value is 'short=2', actual value=" + s);
}

var TestResolveMethodWithByteCast = function() {

Log("TEST: TestResolveMethodWithByteCast");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method5(byte(65536 + 123));
Assert(s === "byte=123", "TestResolveMethodWithByteCast FAILED: Expected value is 'byte=123', actual value=" + s);
}

var TestResolveMethodWithShortCast = function() {

Log("TEST: TestResolveMethodWithShortCast");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method5(short(65536 + 1234));
Assert(s === "short=1234", "TestResolveMethodWithShortCast FAILED: Expected value is 'short=1234', actual value=" + s);
}

var TestResolveMethodWithoutCastFunction = function() {

Log("TEST: TestResolveMethodWithoutCastFunction");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method5(123456);
Assert(s === "int=123456", "TestResolveMethodWithoutCastFunction FAILED: Expected value is 'int=123456', actual value=" + s);
}

var TestResolveMethodWithLongCast = function() {

Log("TEST: TestResolveMethodWithLongCast");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method5(long("123456789012"));
Assert(s === "long=123456789012", "TestResolveMethodWithLongCast FAILED: Expected value is 'long=123456789012', actual value=" + s);
}

var TestResolveMethodWithFloatCast = function() {

Log("TEST: TestResolveMethodWithFloatCast");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method5(float(1.23));
Assert(s === "float=1.23", "TestResolveMethodWithFloatCast FAILED: Expected value is 'float=1.23', actual value=" + s);
}

var TestResolveMethodWithDoubleCast = function() {

Log("TEST: TestResolveMethodWithDoubleCast");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method5(double(1));
Assert(s === "double=1.0", "TestResolveMethodWithDoubleCast FAILED: Expected value is 'double=1.0', actual value=" + s);
}

var TestResolveIntMethodWithNumberObjectWithIntArgument = function() {

Log("TEST: TestResolveIntMethodWithNumberObjectWithIntArgument");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method5(new Number(1));
Assert(s === "int=1", "TestResolveIntMethodWithNumberObjectWithIntArgument FAILED: Expected value is 'int=1', actual value=" + s);
}

var TestResolveIntMethodWithNumberObjectWithDoubleArgument = function() {

Log("TEST: TestResolveIntMethodWithNumberObjectWithDoubleArgument");

var n = new com.tns.tests.NumericConversionTest();
var s = n.method5(new Number(1.23));
Assert(s === "double=1.23", "TestResolveIntMethodWithNumberObjectWithDoubleArgument 123FAILED: Expected value is 'double=1.23', actual value=" + s);
}

TestCreateInstanceWithConstructorResolutionWithNumberLiteral();
TestCreateInstanceWithConstructorResolutionWithCastFunctions();
TestCreateInstanceWithConstructorResolutionWithValuesFromJavaCalls();
TestCreateInstanceWithConstructorResolutionWithPromotingValueUp();
TestCreateInstanceWithConstructorResolutionWithPromotingValueDown();
TestCallMethodWithResolutionWithPromotingValueUp();
TestCallMethodWithResolutionWithPromotingValueDown();
TestLongCastToFloatConversionWhenThereIsDoubleOverload();
TestByteCastToFloatConversionWhenThereIsDoubleOverload();
TestShortCastToFloatConversionWhenThereIsDoubleOverload();
TestDoubleCastWhenThereIsDoubleOverload();
TestNumberExpressionToFloatConversionWhenThereIsDoubleOverload();
TestDoubleCastToLongConversionWhenThereIsShortOverload();
TestFloatCastToLongConversionWhenThereIsShortOverload();
TestFloatCastToShortConversionWhenThereIsObjectOverload();
TestByteCastToShortConversionWhenThereIsObjectOverload();
TestResolveMethodWithByteCast();
TestResolveMethodWithShortCast();
TestResolveMethodWithoutCastFunction();
TestResolveMethodWithLongCast();
TestResolveMethodWithFloatCast();
TestResolveMethodWithDoubleCast();
TestResolveIntMethodWithNumberObjectWithIntArgument();
TestResolveIntMethodWithNumberObjectWithDoubleArgument();
63 changes: 35 additions & 28 deletions src/jni/ExceptionUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,43 +150,50 @@ bool ExceptionUtil::HandleTryCatch(TryCatch& tc){
void ExceptionUtil::OnUncaughtError(Handle<Message> message, Handle<Value> error){
auto errorMessage = instance->PrintErrorMessage(message, error);

auto isolate = Isolate::GetCurrent();
Isolate *isolate = Isolate::GetCurrent();
HandleScope scope(isolate);

// call the global exception handler
Handle<Value> errorObject;

if(error->IsObject()){
errorObject = error.As<Object>();
error.As<Object>()->Set(ConvertToV8String("message"), ConvertToV8String(errorMessage));
}
else{
errorObject = Exception::Error(ConvertToV8String(errorMessage));
}

CallJFuncWithErr(errorObject);

// check whether the developer marked the error as "Caught"
// As per discussion, it is safer to ALWAYS kill the application due to uncaught error(s)
// TODO: We may think for some per-thread specific behavior and allow execution to continue for background thread exceptions
// if(!returnValue.IsEmpty() && (returnValue->IsBoolean() || returnValue->IsBooleanObject())){
// handled = returnValue->BooleanValue();
// }
}

void ExceptionUtil::CallJFuncWithErr(Handle<Value> errObj)
{
//create handle scope
Isolate *isolate = Isolate::GetCurrent();
HandleScope scope(isolate);

auto context = isolate->GetCurrentContext();
auto globalHandle = context->Global();

auto handler = globalHandle->Get(V8StringConstants::GetUncaughtError());
auto isEmpty = handler.IsEmpty();
auto isFunction = handler->IsFunction();

if(!isEmpty && isFunction){
// call the global exception handler
Handle<Value> errorObject;

if(error->IsObject()){
errorObject = error.As<Object>();
error.As<Object>()->Set(ConvertToV8String("message"), ConvertToV8String(errorMessage));
}
else{
errorObject = Exception::Error(ConvertToV8String(errorMessage));
}

if(!isEmpty && isFunction)
{
auto thiz = Object::New(isolate);
auto func = handler.As<Function>();

// Notify the developer for the exception and let him do some additional job here
// TODO: Launching UI at this point may be erroneous, think how to prevent it
func->Call(thiz, 1, &errorObject);

// check whether the developer marked the error as "Caught"
// As per discussion, it is safer to ALWAYS kill the application due to uncaught error(s)
// TODO: We may think for some per-thread specific behavior and allow execution to continue for background thread exceptions
// if(!returnValue.IsEmpty() && (returnValue->IsBoolean() || returnValue->IsBooleanObject())){
// handled = returnValue->BooleanValue();
// }
func->Call(thiz, 1, &errObj);
}

// go to Java through the Thread.setUncaughtExceptionHandler routine
//NativeScriptRuntime::APP_FAIL(errorMessage.c_str());
}

string ExceptionUtil::GetErrorMessage(const Handle<Message>& message, const Handle<Value>& error){
Expand All @@ -200,7 +207,7 @@ string ExceptionUtil::GetErrorMessage(const Handle<Message>& message, const Hand
String::Utf8Value utfError(str);
ss << *utfError << endl;
ss << "File: \"" << ConvertToString(message->GetScriptResourceName().As<String>());
ss << ", line: " << message->GetLineNumber() << ", column: " << message->GetStartColumn() << endl;
ss << ", line: " << message->GetLineNumber() - Constants::MODULE_LINES_OFFSET << ", column: " << message->GetStartColumn() << endl;

string stackTraceMessage = GetErrorStackTrace(message->GetStackTrace());
ss << "StackTrace: " << endl << stackTraceMessage;
Expand Down Expand Up @@ -267,7 +274,7 @@ bool ExceptionUtil::CheckForException(Isolate *isolate, const string& methodName
String::Utf8Value file(tc.Message()->GetScriptResourceName());
int line = tc.Message()->GetLineNumber();
int column = tc.Message()->GetStartColumn();
DEBUG_WRITE("Error: %s @line: %d, column: %d", *error, line, column);
DEBUG_WRITE("Error: %s @line: %d, column: %d", *error, line - Constants::MODULE_LINES_OFFSET, column);

auto pv = new Persistent<Value>(isolate, ex);

Expand Down
1 change: 1 addition & 0 deletions src/jni/ExceptionUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ namespace tns
* Reports any uncaught non-critical errors.
*/
static void OnUncaughtError(v8::Handle<v8::Message> message, v8::Handle<v8::Value> error);
static void CallJFuncWithErr(v8::Handle<v8::Value> errObj);

static ExceptionUtil* GetInstance();

Expand Down
Loading