Example #1
0
        /// <summary>
        /// Parses the specified expression and verifies that both the computed path and expected results are achieved
        /// </summary>
        void TestExpression <TRoot, TResult>(TRoot instance, string expression, TResult expectedValue, string expectedPath)
        {
            // Get the corresponding model type
            var type = typeof(TRoot).GetModelType();

            // Use the type to parse the model expression
            var exp = type.GetExpression <TResult>(expression);

            // Ensure the computed path is correct
            Assert.AreEqual(expectedPath, exp.Path.Path);

            // Ensure the expression yields the correct value
            if (exp.Expression.Parameters.Count == 0)
            {
                Assert.AreEqual(expectedValue, exp.Expression.Compile().DynamicInvoke());
            }
            else
            {
                Assert.AreEqual(expectedValue, exp.Expression.Compile().DynamicInvoke(instance));
            }

            // Convert the expression to javascript
            var translation = translator.Translate(exp.Expression);

            if (translation.Exceptions.Count > 0)
            {
                throw translation.Exceptions.First();
            }

            // Invoke the javascript expression
            var js     = "function (x) { " + translation.Exports.Aggregate("", (exports, export) => exports += export.Key + "=" + export.Value + ";") + " return (" + translation.Function + ").call(x);}(x)";
            var f      = Accessors.CreateScriptFunction("x", js);
            var result = f(type.GetModelInstance(instance));

            if (typeof(TResult) == typeof(string))
            {
                result = String.Concat(result);
            }
            else if (typeof(TResult) == typeof(DateTime))
            {
                result = ((Jurassic.Library.DateInstance)f(type.GetModelInstance(instance))).Value;
            }
            else
            {
                result = Convert.ChangeType(f(type.GetModelInstance(instance)), typeof(TResult));
            }

            if (typeof(TResult) == typeof(DateTime))
            {
                // Jurassic automatically converts to UTC but in reality we always convert to LocalTime on the client
                DateTime resultDate   = (DateTime)Convert.ChangeType(result, typeof(DateTime));
                var      expectedDate = (DateTime)(object)expectedValue;
                Assert.AreEqual(new DateTime(expectedDate.Ticks, DateTimeKind.Local), resultDate.ToLocalTime());
            }
            else
            {
                // Verify that the javascript expression evaluated to the correct result
                Assert.AreEqual(expectedValue, result);
            }
        }
Example #2
0
        public void TestCompiledExpressions()
        {
            // basic test to make sure functions compile
            var plus = Accessors.CreateScriptFunction("a", "b", "a + b");

            Assert.AreEqual(1.0 + 2.0, plus(1.0, 2.0));

            // create a second function with same arg names to test function isolation
            var minus = Accessors.CreateScriptFunction("a", "b", "a - b");

            Assert.AreEqual(1.0 - 2.0, minus(1.0, 2.0));
            Assert.AreEqual(1.0 + 2.0, plus(1.0, 2.0));

            // make sure arguments are declared locally (in above functions)
            try
            {
                Accessors.CreateScriptFunction("a", "b");
                Assert.Fail("Should not be able to reference undefined arguments");
            }
            catch { }

            // make sure arguments are local (again)
            var localSideEffects = Accessors.CreateScriptFunction("a", "++a");

            Assert.AreEqual(2.0, localSideEffects(1.0));
            Assert.AreEqual(2.0, localSideEffects(1.0));

            // test full function body
            Assert.AreEqual("xyz", Accessors.CreateScriptFunction("a", "var b=a; return b;", false)("xyz"));
        }
Example #3
0
        public void BalancedText()
        {
            string remainder;

            var run = Accessors.GetBalancedText("[outer[inner] []] - extra", '[', ']', out remainder);

            run.Should().Be("[outer[inner] []]");
            remainder.Should().Be(" - extra");

            run = Accessors.GetBalancedText("{Owner{FirstName,LastName}},Tag{Number}", '{', '}', out remainder);
            run.Should().Be("{Owner{FirstName,LastName}}");
            remainder.Should().Be(",Tag{Number}");

            Action openAndClosedAreTheSame = () => Accessors.GetBalancedText("", '|', '|', out remainder);

            openAndClosedAreTheSame.ShouldThrow <ArgumentException>().WithMessage("Open and closed characters cannot be the same.");

            Action doesNotStartWithOpen = () => Accessors.GetBalancedText("abcd", '<', '>', out remainder);

            doesNotStartWithOpen.ShouldThrow <ArgumentException>().WithMessage("Input text must begin with the open character.");

            Action unbalanced = () => Accessors.GetBalancedText("<abc<d>", '<', '>', out remainder);

            unbalanced.ShouldThrow <ArgumentException>().WithMessage("The input text is not balanced.");

            Action missingEnd = () => Accessors.GetBalancedText("<abcd", '<', '>', out remainder);

            missingEnd.ShouldThrow <ArgumentException>().WithMessage("The input text is not valid.");
        }
Example #4
0
        public void TestEntityArrays()
        {
            var data = new Category()
            {
                Name = "parent "
            };

            data.ChildCategories.Add(new Category()
            {
                Name = "child1"
            });
            data.ChildCategories.Add(new Category()
            {
                Name = "child2"
            });

            var echo = Accessors.CreateScriptFunction("list", "list");

            AssertLists.AreSame(data.ChildCategories, (IEnumerable)echo(data.ChildCategories), "lists should be the same");

            // test wrap/unwrap
            Assert.AreEqual((uint)data.ChildCategories.Count, Accessors.CreateScriptFunction("list", "list.length")(data.ChildCategories));

            // make sure the list is an array
            Assert.AreEqual((uint)data.ChildCategories.Count, Accessors.CreateScriptFunction("list", "list.length")(data.ChildCategories));

            // test optimization (wrap/unwrap)+
            var unwrapped1 = echo(data.ChildCategories);
            var unwrapped2 = echo(unwrapped1);

            Assert.AreEqual(Accessors.GetUnwrappedArray(unwrapped1), Accessors.GetUnwrappedArray(unwrapped2));
        }
Example #5
0
 public void TestCompiledExpressionsNullAndUndefinedMarshalling()
 {
     Assert.AreEqual(true, Accessors.CreateScriptFunction("x", "x === null")(null), "marshal null === null");
     Assert.AreEqual(true, Accessors.CreateScriptFunction("x", "x !== undefined")(null), "marshal null !== undefined");
     Assert.AreEqual(null, Accessors.CreateScriptFunction("x", "null")(null), "marshal return null");
     Assert.AreEqual(null, Accessors.CreateScriptFunction("x", "undefined")(null), "marshal return undefined");
 }
Example #6
0
        public void TestExpressionsReturningFunctions()
        {
            var functionGenerator = Accessors.CreateScriptFunction("a", "function(x) {return x;}");

            var f = (FunctionInstance)functionGenerator("1");

            Assert.AreEqual("abc", f.Call(null, "abc"));
        }
Example #7
0
        public void TestCompiledExpressionsFunctionMarshaling()
        {
            int value = 7;

            var add = Accessors.CreateScriptFunction("arg", "arg(3)");

            Assert.AreEqual(
                value + 3,
                add((Func <int, int>)(i => value + i)),
                "marshal ModelInstance");
        }
Example #8
0
 public void TestCompiledExpressionsSyntaxError()
 {
     try
     {
         Accessors.CreateScriptFunction("a", "a ==== a");
         Assert.Fail("Syntax error should be detected");
     }
     catch (Exception e)
     {
         Assert.IsTrue(e.GetType().Name.EndsWith("ScriptFunctionSyntaxException"), "a special syntax exception should be thrown");
     }
 }
Example #9
0
        private static void CreateDateParseLocale()
        {
            var createParseLocale = Accessors.CreateScriptFunction("o",
                                                                   @"(function() {
					Date.parseLocale = function (s) {
						var slashParts = s.split('/');
						if (slashParts.length === 3) {
							return new Date(parseInt(slashParts[2], 10), parseInt(slashParts[0], 10) - 1, parseInt(slashParts[1], 10));
						}

						throw new Error(""Date '"" + s + ""' could not be parsed."");
					};
				}())"                );

            createParseLocale(true);
        }
        private static void TestEntityException(object instance, string javascript, Predicate <Exception> expected)
        {
            var engine = new ScriptEngine();

            engine.ForceStrictMode = true;
            engine.SetGlobalValue("$instance", Accessors.CreateEntity(engine, (IModelInstance)instance));

            try
            {
                var result = engine.Evaluate(javascript);
                Assert.Fail("Expected an exception but one was not thrown: " + javascript + " --> " + result);
            }
            catch (Exception error)
            {
                Assert.IsTrue(expected(error), "An error was expected but not '" + error.Message + "': " + javascript);
            }
        }
Example #11
0
        private static void CreateNumberLocaleFormat()
        {
            var createLocaleFormat = Accessors.CreateScriptFunction("o",
                                                                    @"(function() {
					Number.prototype.localeFormat = function (format) {
						if (format === 'g') {
							return this.toString();
						}
						if (format === 'C') {
							return '$' + this.toFixed(2).toString();
						}

						throw new Error(""Number format '"" + format + ""' is not supported."");
					};
				}())"                );

            createLocaleFormat(true);
        }
Example #12
0
        public void TestCompiledExpressionsObjectMarshaling()
        {
            var data = new Request
            {
                User = new User()
            };

            var path = Accessors.CreateScriptFunction("arg", "arg.get_User()");

            Assert.AreEqual(((IModelInstance)data.User).Instance, path(((IModelInstance)data).Instance), "marshal ModelInstance");

            var f = Accessors.CreateScriptFunction("arg", "arg");

            Assert.AreEqual(true, f(true));
            Assert.AreEqual("abc", f("abc"));
            Assert.AreEqual(1.0, f(1.0));
            Assert.AreEqual(((IModelInstance)data).Instance, f(((IModelInstance)data).Instance));
        }
Example #13
0
        private static void CreateDateLocaleFormat()
        {
            var createLocaleFormat = Accessors.CreateScriptFunction("o",
                                                                    @"(function() {
					Date.prototype.localeFormat = function (format) {
						var date = this;

						if (format === 'd') {
							return (date.getMonth() + 1) + '/' + date.getDate() + '/' + (1900 + date.getYear()).toString();
						}

						if (format.indexOf('/') > 0) {
							var parts = format.split('/');
							if (parts.every(function(p) { return p === 'M' || p === 'MM' || p === 'd' || p === 'dd' || p === 'yyyy'; })) {
								return parts.map(function(p) {
									if (p === 'M') {
										return (date.getMonth() + 1).toString();
									} else if (p === 'MM') {
										return (date.getMonth() < 9 ? '0' : '') + (date.getMonth() + 1).toString();
									} else if (p === 'd') {
										return date.getDate().toString();
									} else if (p === 'dd') {
										return (date.getDate() < 10 ? '0' : '') + date.getDate().toString();
									} else if (p === 'yyyy') {
										return (1900 + date.getYear()).toString();
									}
								}).join('/');
							}
						}

						throw new Error(""Date format '"" + format + ""' is not supported."");
					};
				}())"                );

            createLocaleFormat(true);
        }
 private static void TestEntityExpression <T>(object instance, string javascript, T expectedResult)
 {
     TestExpression(engine => Accessors.CreateEntity(engine, (IModelInstance)instance), javascript, expectedResult);
 }
 private static void TestAdapterExpression <T>(object instance, string propertyName, string javascript, T expectedResult)
 {
     TestExpression(engine => Accessors.CreateAdapter(engine, (IModelInstance)instance, propertyName), javascript, expectedResult);
 }