/**
* Copyright 2013 Douglas Campos, and individual contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dynjs.runtime;
import static org.fest.assertions.Assertions.*;
import org.dynjs.exception.DynJSException;
import org.dynjs.exception.ThrowException;
import org.junit.Ignore;
import org.junit.Test;
public class DynJSTest extends AbstractDynJSTestSupport {
@Test
public void testOperatorPrecedence() {
assertThat( eval( "3-1+1" ) ).isEqualTo(3L);
assertThat( eval( "3-0+1" ) ).isEqualTo(4L);
assertThat( eval( "3-2*2" ) ).isEqualTo(-1L);
assertThat( eval( "3*2-2" ) ).isEqualTo(4L);
}
@Test
public void testObjectPrototypePrototypeIsNull() {
assertThat(eval("Object.getPrototypeOf(Object.prototype) === null")).isEqualTo(true);
}
@Test
public void testTypeOfUndefined() {
assertThat(eval("typeof(undefined) === 'undefined'")).isEqualTo(true);
}
@Test
public void testObject() {
assertThat(eval("eval('{}')")).isEqualTo(Types.UNDEFINED);
}
@Test(expected = ThrowException.class)
public void testSyntaxErrorThrows() {
getRuntime().execute("var f ( {;");
}
@Test
public void evalLines() {
getRuntime().evaluate(
"var x = 'test'",
"var y = x");
Reference y = getContext().resolve("y");
assertThat(y)
.isNotNull()
.isInstanceOf(Reference.class);
assertThat(y.getValue(getContext()))
.isEqualTo("test");
}
@Test
public void assignsGlobalVariables() {
check("var result = 'test';", "test");
check("var result = undefined; result = 1.0;", 1L);
}
@Test
public void defineUnInitializedGlobalVariables() {
eval("var x;");
Reference x = getContext().resolve("x");
Object val = x.getValue(getContext());
assertThat(val)
.isNotNull()
.isEqualTo(Types.UNDEFINED);
}
@Test
public void assignsExprGlobalVariables() {
check("var x = 2 + 1; var result = x == 3;");
}
@Test
public void assignsExprMulGlobalVariables() {
check("var x = 3 * 2; var result = x == 6;");
}
@Test
public void assignsExprSubGlobalVariables() {
check("var x = 3 - 1; var result = x == 2;");
}
@Test
public void assignsComplexExprSubGlobalVariables() {
check("var x = 3 * 2 - 1; var result = x == 5");
}
@Test
public void assignsComplexparExprSubGlobalVariables() {
check("var x = (3 * 2) - 1; var result = x == 5");
}
@Test
public void assignsNamedEmptyFunction() {
check("function x(){}; var result = x();", Types.UNDEFINED);
}
@Test
public void assignsAnonymousEmptyFunction() {
check("var x = function(a,b,c){}; var result = x();", Types.UNDEFINED);
}
@Test
public void buildFunctionWithBody() {
check("var result = (function(a,b){var w = (1 + 2) * 3;})();", Types.UNDEFINED);
}
@Test
public void buildFunctionWithMultipleStatementBody() {
check("var result = (function(){var a = 1;var b = 2; var c = a + b;})()", Types.UNDEFINED);
}
@Test
public void buildFunctionWithReturn() {
check("var result = (function(){return 1+1;})() === 2;");
}
@Test(expected = ThrowException.class)
public void throwsReferenceErrorWhenCallAnonExistingReference() {
eval("print(x);");
}
@Test
public void testPrint() {
eval("print('taco');");
}
@Test
public void testRelationalOperators() {
check("var result = 1 < 2;");
check("var result = 2 > 1;");
check("var result = 2 <= 2;");
check("var result = 2 >= 2;");
}
@Test
public void testBooleanLiterals() {
check("var result = true;", true);
check("var result = false;", false);
}
@Test
public void testMathOperations() {
//check("var x = 1 + 1;var result = x == 2");
//check("var x = 1 - 1;var result = x == 0");
//check("var x = 3 * 7;var result = x == 21");
check("var x = 3 / 2;var result = x == 1.5");
//check("var x = 3 % 2;var result = x == 1");
}
@Test
public void testHexValue() {
check("var result = 0x16", 22L);
}
@Test
public void testBitwise() {
check("var result = 0x000F & 0x2222", 2L);
check("var result = 0x000F | 0x2222", 8751L);
check("var result = 0x000F ^ 0x2222", 8749L);
check("var result = 0x000F; result &= 0x2222", 2L);
check("var result = 0x000F; result |= 0x2222", 8751L);
check("var result = 0x000F; result ^= 0x2222", 8749L);
check("var result = 9 << 2", 36);
check("var result = 9 >> 2", 2);
check("var result = -1 >>> 2", 1073741823L);
check("var result = 9; result <<= 2", 36);
check("var result = 9; result >>= 2", 2);
check("var result = -1; result >>>= 2", 1073741823L);
}
@Test
public void testAssignments() {
check("var x = 1;x += 1; var result = x == 2;");
check("var x = 1;x -= 1; var result = x == 0;");
check("var x = 1;x *= 3; var result = x == 3;");
check("var x = 1;x /= 1; var result = x == 1.0;");
check("var x = 2;x %= 1; var result = x == 0;");
}
@Test
public void testContinue() {
eval("var x = 0;",
"for (var i = 0;i < 10; i+=1){",
" continue;",
" x+=1;",
"}");
Object x = getContext().resolve("x").getValue(getContext());
assertThat(x).isEqualTo(0L);
eval("var x = 0;",
"do {",
" x+=1;",
" if(x % 3 == 0) {",
" continue;",
" }",
" x+=3;",
"} while(x < 10)");
x = getContext().resolve("x").getValue(getContext());
assertThat(x).isEqualTo(13L);
eval("var x = 0;",
"while(x < 10) {",
" x+=1;",
" if(x % 2 == 0) {",
" continue;",
" }",
" ;x+=3",
"}");
x = getContext().resolve("x").getValue(getContext());
assertThat(x).isEqualTo(12L);
}
@Test
public void testBreak() {
check("var x = 0; for (var i = 0;i < 10; i+=1){ x+=1; break;}; var result = x == 1;");
check("var x = 0; var i = 0; for (;i < 10; i+=1){ x+=1; break;}; var result = x == 1;");
check("var x = 0; do { x+=1;if(x % 3 == 0) {break;};x+=3 } while(x < 10); var result = x == 9;");
check("var x = 0; while(x < 10) { x+=1; if(x % 2 == 0) {break;};x+=3}; var result = x == 12;");
}
@Test
public void testNullLiteral() {
Object result = eval("null");
assertThat(result).isEqualTo(Types.NULL);
}
@Test
public void testTernaryOperator() {
check("var x = 1 > 2 ? 55 : 56; var result = x == 56");
}
@Test
public void testLogicalOperators() {
check("var result = false || true;", true);
check("var result = true || false;", true);
check("var result = false || false;", false);
check("var result = true && false;", false);
check("var result = false && true;", false);
check("var result = true && true;", true);
}
@Test
public void testEmptyObjectLiteral() {
final Object result = resultFor("var result = {};");
assertThat(result)
.isNotNull()
.isInstanceOf(JSObject.class);
}
/*
@Test
public void testBasicObjectLiteral() {
final String expression = "var result = {w:true};";
final Object result = resultFor(expression);
assertThat(result)
.isNotNull()
.isInstanceOf(DynObject.class);
assertThat(((DynObject) result).resolve("w")).isInstanceOf(Boolean.class).isEqualTo(Boolean.TRUE);
}
*/
@Test
public void testObjectLiteralPropertyAccess() {
check("var x = {w:true}; var result = x.w;", true);
check("var x = {'y':false}; var result = x.y;", false);
check("var x = {'z':true}; var result = x['z'];", true);
}
@Test
public void testObjectAssignment() {
check("var x = {}; x.a = 'lol'; var result = x.a == 'lol';");
}
/*
@Test
public void testBuiltinLoading() {
getConfig().addBuiltin("sample", DynJSCompiler.wrapFunction(getContext(), new BypassFunction()));
check("var result = sample(true);");
}
*/
@Test
public void testEval() {
Object result = eval("eval('4+2')");
assertThat(result).isEqualTo(6L);
}
@Test
public void testTypeOf() {
check("var result = typeof undefined;", "undefined");
check("var result = typeof null === 'object';");
check("var result = typeof {} === 'object';");
check("var result = typeof true === 'boolean';");
check("var result = typeof 1.0 === 'number';");
check("var result = typeof 'lol' === 'string';");
check("function x(){}; var result = typeof x === 'function';");
}
@Test
public void testInstanceOf() {
check("function Car(){}; var x = new Car; var result = x instanceof Car;");
}
@Test
public void testVoid() {
check("var result = undefined === undefined;");
}
@Test
public void testThis() {
check("var x = {name:'myName', lol:function(){return this.name;}}; var result = x.name == 'myName' && x.lol() == 'myName';");
}
@Test(expected = DynJSException.class)
public void testThrow() {
check("throw 'pizza';");
}
@Test
public void testDeleteOper() {
check("var x = {a:'lol'}; var result = delete x.a;", true);
JSObject x = (JSObject) getContext().resolve("x").getValue(getContext());
assertThat(x.get(getContext(), "a")).isEqualTo(Types.UNDEFINED);
}
@Test
public void testUnaryMinusOper() {
check("var result = -1 + 1", 0L);
check("var result = -1", -1L);
check("var x = 1; var result = -x == -1");
}
@Test
public void testIfStatement() {
check("var x = function(a) { if (a) { return 1; } else { return 2; } }; var result = x(true) == 1;");
}
@Test
public void testFunctionCall() {
check("var result = (function () { return true; } )();");
check("function testCall(a) { return a; }; var result = testCall(1) == 1;");
}
@Test
public void testFactorial() {
check("function factorial(n) { if (n == 1) { return 1; } else { return (n * factorial(n - 1)); } }; var result = factorial(5) == 120;");
}
@Test
public void testFibRecursive() {
check("function fib(n) { return n < 2 ? n : fib(n - 1) + fib(n - 2); }; var result = fib(6) == 8;");
}
@Test
public void testIncrement() {
check("var x = 1; var y = 1; var result = ++x == 2 && y++ == 1;");
}
@Test
public void testDecrement() {
check("var x = 2; var y = 2; var result = --x == 1 && y-- == 2;");
}
@Test
public void testMath() {
check("var x = 10; var result = (x + 5 == 15) && (x - 1 == 9) && (x * 3 == 30) && (x / 2 == 5.0) && (x % 3 == 1);");
}
@Test
public void testRelational() {
check("var x = 10; var result = (x > 9) && (x < 11) && (x <= 10) && (x >= 10);");
}
@Test
public void testEquality() {
// equality
check("var result = undefined == undefined;");
check("var result = null == null;");
check("var result = NaN == NaN;", false);
check("var result = 1 == 1;");
check("var result = 0 == -0;");
check("var result = -0 == 0;");
check("var result = null == undefined;");
check("var result = undefined == null;");
check("var result = 1 == '1';");
check("var result = '1' == 1;");
check("var result = '' == 0");
check("var result = true == 1;");
check("var result = false == 0;");
check("var result = 1 == true;");
check("var result = 0 == false;");
check("var result = 1 != 2;");
// strict equality
check("var result = 1 === 1;");
check("var result = 'a' === 'a';");
check("var result = true === true;");
check("var x = 'foo'; var y = x; result = x === y;");
check("var result = 1 !== 2;");
}
@Test
public void testLoop() {
check("var x = 10;var y = 0; while(x < 10){x+=1;y+=1}; var result = y == 0;");
check("var x = 10;var y = 0; do { x+=1;y+=1; } while(x < 10); var result = y == 1;");
check("var x = 10; var y = 0; while(x < 10){ x += 1; y += 1 }; var result = y == 0;");
}
@Test
public void testFor() {
check("var x = 0; for (var i =0;i < 10; i+=1){ x+=1;}; var result = x == 10");
check("var x = 0; var i =0; for (var w = 0;i < 10; i+=1){ x+=1;}; var result = i == 10");
check("var x = 0; for (; x < 10; x += 1) { x += 1; }; var result = x == 10");
check("var i = 0; var x = 33; for(; i < 10; i++) { x -= 1} var result = x == 23");
check("var x = 0; for (var i =0; i < 10; i += 1) { x += 1; } var result = x == 10;");
}
@Test
public void testDivision() {
check("var x = 10; var result = x / 2 == 5.0;");
}
@Test
public void testNoTop() {
check("var x = 10; var result = !(x == 20);");
}
@Test
public void testStringEquality() {
check("var result = \"house\" == \"house\" && 'house' == 'house' && \"\" == 0;");
}
@Test
public void testGlobalEscapeFunctionProperties() {
eval("var global = Function(\"return this;\")()");
eval("var desc = Object.getOwnPropertyDescriptor(global, 'escape');");
assertThat(eval("desc.value != undefined")).isEqualTo(true);
assertThat(eval("desc.value == global.escape")).isEqualTo(true);
assertThat(eval("desc.writable")).isEqualTo(true);
assertThat(eval("desc.configurable")).isEqualTo(true);
assertThat(eval("desc.enumerable")).isEqualTo(true);
}
@Test
public void testHexEscape() {
// TODO: Better testing
assertThat(eval("escape('Now is the winter')")).isEqualTo("Now%20is%20the%20winter");
}
@Test
public void testGlobalUnescapeFunctionProperties() {
eval("var global = Function(\"return this;\")()");
eval("var desc = Object.getOwnPropertyDescriptor(global, 'unescape');");
assertThat(eval("desc.value != undefined")).isEqualTo(true);
assertThat(eval("desc.value == global.unescape")).isEqualTo(true);
assertThat(eval("desc.writable")).isEqualTo(true);
assertThat(eval("desc.configurable")).isEqualTo(true);
assertThat(eval("desc.enumerable")).isEqualTo(true);
}
}