|
| 1 | +using DotVVM.Framework.Compilation.Javascript.Ast; |
| 2 | +using Microsoft.VisualStudio.TestTools.UnitTesting; |
| 3 | +using System; |
| 4 | +using DotVVM.Framework.Compilation.Javascript; |
| 5 | + |
| 6 | +namespace DotVVM.Framework.Tests.Runtime.JavascriptCompilation |
| 7 | +{ |
| 8 | + [TestClass] |
| 9 | + public class JsParametrizedCodeTests |
| 10 | + { |
| 11 | + static CodeSymbolicParameter symbolA = new CodeSymbolicParameter("A"); |
| 12 | + static CodeSymbolicParameter symbolB = new CodeSymbolicParameter("B"); |
| 13 | + static CodeSymbolicParameter symbolC = new CodeSymbolicParameter("C", defaultAssignment: new JsIdentifier("defaultValue").FormatParametrizedScript()); |
| 14 | + static CodeSymbolicParameter symbolD = new CodeSymbolicParameter("D", defaultAssignment: new JsBinaryExpression(new JsSymbolicParameter(symbolA), BinaryOperatorType.Times, new JsSymbolicParameter(symbolC)).FormatParametrizedScript()); |
| 15 | + static CodeSymbolicParameter symbolE = new CodeSymbolicParameter("E", defaultAssignment: new JsBinaryExpression(new JsSymbolicParameter(symbolA), BinaryOperatorType.Plus, new JsSymbolicParameter(symbolD)).FormatParametrizedScript()); |
| 16 | + |
| 17 | + [TestMethod] |
| 18 | + public void SymbolicParameters_Global() |
| 19 | + { |
| 20 | + // full would be "global.a+global |
| 21 | + var pcode = new JsBinaryExpression(new JsMemberAccessExpression(new JsSymbolicParameter(symbolA), "a"), BinaryOperatorType.Plus, |
| 22 | + new JsSymbolicParameter(symbolA)) |
| 23 | + .FormatParametrizedScript(); |
| 24 | + Assert.AreEqual("a+global", |
| 25 | + pcode.ToString(o => o == symbolA ? CodeParameterAssignment.FromExpression(new JsIdentifierExpression("global"), isGlobalContext: true) : |
| 26 | + throw new Exception())); |
| 27 | + Assert.AreEqual("a+global", |
| 28 | + pcode.AssignParameters(o => o == symbolA ? CodeParameterAssignment.FromExpression(new JsIdentifierExpression("global"), isGlobalContext: true) : |
| 29 | + throw new Exception()) |
| 30 | + .ToString(o => default)); |
| 31 | + } |
| 32 | + |
| 33 | + [TestMethod] |
| 34 | + public void SymbolicParameters_Global_ThroughDefault() |
| 35 | + { |
| 36 | + var globalDefaultSymbol = new CodeSymbolicParameter("global", defaultAssignment: symbolA.ToParametrizedCode()); |
| 37 | + // may be "global.a+global" or "a+global" - doesn't matter if the optimization works in this case, but it shouldn't be broken |
| 38 | + var pcode = new JsBinaryExpression(new JsMemberAccessExpression(new JsSymbolicParameter(globalDefaultSymbol), "a"), BinaryOperatorType.Plus, |
| 39 | + new JsSymbolicParameter(globalDefaultSymbol)) |
| 40 | + .FormatParametrizedScript(); |
| 41 | + Assert.AreEqual("global.a+global", |
| 42 | + pcode.ToString(o => o == symbolA ? CodeParameterAssignment.FromExpression(new JsIdentifierExpression("global"), isGlobalContext: true) : |
| 43 | + default)); |
| 44 | + Assert.AreEqual("global.a+global", |
| 45 | + pcode.AssignParameters(o => o == symbolA ? CodeParameterAssignment.FromExpression(new JsIdentifierExpression("global"), isGlobalContext: true) : |
| 46 | + default) |
| 47 | + .ToString(o => default)); |
| 48 | + } |
| 49 | + |
| 50 | + [TestMethod] |
| 51 | + public void SymbolicParameters_Throws_Unassigned() |
| 52 | + { |
| 53 | + var pcode = new JsBinaryExpression(new JsMemberAccessExpression(new JsSymbolicParameter(symbolA), "a"), BinaryOperatorType.Plus, new JsSymbolicParameter(symbolA)).FormatParametrizedScript(); |
| 54 | + |
| 55 | + var pcode2 = pcode.AssignParameters(o => default); // fine, not all have to be assigned |
| 56 | + var pcodeResolved = pcode.AssignParameters(o => o == symbolA ? CodeParameterAssignment.FromIdentifier("x") : default); |
| 57 | + |
| 58 | + Assert.AreEqual("y.a+y", pcode.ToString(o => o == symbolA ? CodeParameterAssignment.FromIdentifier("y") : default)); |
| 59 | + Assert.AreEqual("z.a+z", pcode2.ToString(o => o == symbolA ? CodeParameterAssignment.FromIdentifier("z") : default)); |
| 60 | + Assert.AreEqual("x.a+x", pcodeResolved.ToString(o => default)); |
| 61 | + Assert.AreEqual("x.a+x", pcodeResolved.ToString(o => o == symbolA ? CodeParameterAssignment.FromIdentifier("AREADY_ASSIGNED_BEFORE") : default)); |
| 62 | + |
| 63 | + var ex = Assert.ThrowsException<InvalidOperationException>(() => pcode.ToString(o => default)); |
| 64 | + XAssert.Contains("Assignment of parameter '{A|", ex.Message); |
| 65 | + |
| 66 | + ex = Assert.ThrowsException<InvalidOperationException>(() => pcode2.ToString(o => default)); |
| 67 | + XAssert.Contains("Assignment of parameter '{A|", ex.Message); |
| 68 | + } |
| 69 | + |
| 70 | + [TestMethod] |
| 71 | + public void SymbolicParameters_Partial_DefaultChain() |
| 72 | + { |
| 73 | + var expr = new JsBinaryExpression(symbolA.ToExpression(), BinaryOperatorType.Plus, symbolE.ToExpression()); |
| 74 | + var pcode = expr.FormatParametrizedScript(); |
| 75 | + |
| 76 | + Assert.AreEqual("x+(x+x*defaultValue)", pcode.ToString(o => o == symbolA ? CodeParameterAssignment.FromIdentifier("x") : default)); |
| 77 | + Assert.AreEqual("y+(y+y*defaultValue)", pcode.ToString(o => o == symbolA ? CodeParameterAssignment.FromIdentifier("y") : default)); |
| 78 | + |
| 79 | + // substitute symbolD for identifier, order doesn't matter |
| 80 | + Assert.AreEqual("x+(x+D)", |
| 81 | + pcode.AssignParameters(o => o == symbolA ? CodeParameterAssignment.FromIdentifier("x") : default) |
| 82 | + .ToString(o => o == symbolD ? CodeParameterAssignment.FromExpression(new JsIdentifierExpression("D")) : default)); |
| 83 | + Assert.AreEqual("x+(x+D)", |
| 84 | + pcode.AssignParameters(o => o == symbolD ? CodeParameterAssignment.FromExpression(new JsIdentifierExpression("D")) : default) |
| 85 | + .ToString(o => o == symbolA ? CodeParameterAssignment.FromIdentifier("x") : default)); |
| 86 | + |
| 87 | + // substitute symbolD for symbolA, order now matters |
| 88 | + Assert.AreEqual("x+(x+x)", |
| 89 | + pcode.AssignParameters(o => o == symbolD ? CodeParameterAssignment.FromExpression(new JsSymbolicParameter(symbolA)) : default) |
| 90 | + .ToString(o => o == symbolA ? CodeParameterAssignment.FromIdentifier("x") : default)); |
| 91 | + Assert.AreEqual("x+(x+y)", |
| 92 | + pcode.AssignParameters(o => o == symbolA ? CodeParameterAssignment.FromIdentifier("x") : default) |
| 93 | + .AssignParameters(o => o == symbolD ? CodeParameterAssignment.FromExpression(new JsSymbolicParameter(symbolA)) : default) |
| 94 | + .ToString(o => o == symbolA ? CodeParameterAssignment.FromIdentifier("y") : default)); |
| 95 | + } |
| 96 | + |
| 97 | + [TestMethod] |
| 98 | + public void SymbolicParameters_AddDefault() |
| 99 | + { |
| 100 | + var expr = new JsBinaryExpression(symbolA.ToExpression(), BinaryOperatorType.Plus, symbolE.ToExpression()); |
| 101 | + var pcode = expr.FormatParametrizedScript(); |
| 102 | + |
| 103 | + // add default for symbolA |
| 104 | + var assigned = pcode.AssignParameters(o => o == symbolA ? symbolA.ToExpression(CodeParameterAssignment.FromIdentifier("a")).FormatParametrizedScript() : default); |
| 105 | + |
| 106 | + Assert.AreEqual("a+(a+a*defaultValue)", assigned.ToString(o => default)); |
| 107 | + Assert.AreEqual("a+(a+a*defaultValue)", assigned.ToDefaultString()); |
| 108 | + |
| 109 | + Assert.AreEqual("x+(x+x*defaultValue)", assigned.ToString(o => o == symbolA ? CodeParameterAssignment.FromIdentifier("x") : default)); |
| 110 | + Assert.AreEqual("a+x", assigned.ToString(o => o == symbolE ? CodeParameterAssignment.FromIdentifier("x") : default)); |
| 111 | + } |
| 112 | + |
| 113 | + [TestMethod] |
| 114 | + public void SymbolicParameters_NoAssignmentNoAllocation() |
| 115 | + { |
| 116 | + var expr = new JsBinaryExpression(symbolA.ToExpression(), BinaryOperatorType.Plus, symbolE.ToExpression()); |
| 117 | + var pcode = expr.FormatParametrizedScript(); |
| 118 | + Func<CodeSymbolicParameter, CodeParameterAssignment> noAssignment = o => default; |
| 119 | + |
| 120 | + var b = GC.GetAllocatedBytesForCurrentThread(); |
| 121 | + pcode.AssignParameters(noAssignment); |
| 122 | + Assert.AreEqual(0, GC.GetAllocatedBytesForCurrentThread() - b); |
| 123 | + } |
| 124 | + } |
| 125 | +} |
0 commit comments