1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
|
describe('Expression Rewriting', function() {
it('Should be able to parse simple object literals', function() {
var result = ko.expressionRewriting.parseObjectLiteral("a: 1, b: 2, \"quotedKey\": 3, 'aposQuotedKey': 4");
expect(result.length).toEqual(4);
expect(result[0].key).toEqual("a");
expect(result[0].value).toEqual("1");
expect(result[1].key).toEqual("b");
expect(result[1].value).toEqual("2");
expect(result[2].key).toEqual("quotedKey");
expect(result[2].value).toEqual("3");
expect(result[3].key).toEqual("aposQuotedKey");
expect(result[3].value).toEqual("4");
});
it('Should ignore any outer braces', function() {
var result = ko.expressionRewriting.parseObjectLiteral("{a: 1}");
expect(result.length).toEqual(1);
expect(result[0].key).toEqual("a");
expect(result[0].value).toEqual("1");
});
it('Should be able to parse object literals containing string literals', function() {
var result = ko.expressionRewriting.parseObjectLiteral("a: \"comma, colon: brace{ bracket[ apos' escapedQuot\\\" end\", b: 'escapedApos\\\' brace} bracket] quot\"'");
expect(result.length).toEqual(2);
expect(result[0].key).toEqual("a");
expect(result[0].value).toEqual("\"comma, colon: brace{ bracket[ apos' escapedQuot\\\" end\"");
expect(result[1].key).toEqual("b");
expect(result[1].value).toEqual("'escapedApos\\\' brace} bracket] quot\"'");
});
it('Should be able to parse object literals containing child objects, arrays, function literals, and newlines', function() {
// The parsing may or may not keep unnecessary spaces. So to avoid confusion, avoid unnecessary spaces.
var result = ko.expressionRewriting.parseObjectLiteral(
"myObject:{someChild:{},someChildArray:[1,2,3],\"quotedChildProp\":'string value'},\n"
+ "someFn:function(a,b,c){var regex=/{/;var str='/})({';return{};},"
+ "myArray:[{},function(){},\"my'Str\",'my\"Str']"
);
expect(result.length).toEqual(3);
expect(result[0].key).toEqual("myObject");
expect(result[0].value).toEqual("{someChild:{},someChildArray:[1,2,3],\"quotedChildProp\":'string value'}");
expect(result[1].key).toEqual("someFn");
expect(result[1].value).toEqual("function(a,b,c){var regex=/{/;var str='/})({';return{};}");
expect(result[2].key).toEqual("myArray");
expect(result[2].value).toEqual("[{},function(){},\"my'Str\",'my\"Str']");
});
it('Should be able to parse object literals containing division and regular expressions', function() {
var result = ko.expressionRewriting.parseObjectLiteral("div: null/5, regexpFunc: function(){var regex=/{/g;return /123/;}");
expect(result.length).toEqual(2);
expect(result[0].key).toEqual("div");
expect(result[0].value).toEqual("null/5");
expect(result[1].key).toEqual("regexpFunc");
expect(result[1].value).toEqual("function(){var regex=/{/g;return/123/;}");
});
it('Should parse a value that begins with a colon', function() {
var result = ko.expressionRewriting.parseObjectLiteral("a: :-)");
expect(result.length).toEqual(1);
expect(result[0].key).toEqual("a");
expect(result[0].value).toEqual(":-)");
});
it('Should be able to cope with malformed syntax (things that aren\'t key-value pairs)', function() {
var result = ko.expressionRewriting.parseObjectLiteral("malformed1, 'mal:formed2', good:3, {malformed:4}, good5:5, keyonly:");
expect(result.length).toEqual(6);
expect(result[0].unknown).toEqual("malformed1");
expect(result[1].unknown).toEqual("mal:formed2");
expect(result[2].key).toEqual("good");
expect(result[2].value).toEqual("3");
expect(result[3].unknown).toEqual("{malformed:4}");
expect(result[4].key).toEqual("good5");
expect(result[4].value).toEqual("5");
expect(result[5].unknown).toEqual("keyonly");
});
it('Should ensure all keys are wrapped in quotes', function() {
var rewritten = ko.expressionRewriting.preProcessBindings("a: 1, 'b': 2, \"c\": 3");
expect(rewritten).toEqual("'a':1,'b':2,'c':3");
});
it('(Private API) Should convert writable values to property accessors', function () {
// Note that both _twoWayBindings and _ko_property_writers are undocumented private APIs.
// We reserve the right to remove or change either or both of these, especially if we
// create an official public property writers API.
var w = ko.expressionRewriting._twoWayBindings;
w.a = w.b = w.c = w.d = w.e = w.f = w.g = w.h = w.i = w.j = true;
var rewritten = ko.expressionRewriting.preProcessBindings(
'a : 1, b : firstName, c : function() { return "returnValue"; }, ' +
'd: firstName+lastName, e: boss.firstName, f: boss . lastName, ' +
'g: getAssitant(), h: getAssitant().firstName, i: getAssitant("[dummy]")[ "lastName" ], ' +
'j: boss.firstName + boss.lastName'
);
// Clear the two-way flag
w.a = w.b = w.c = w.d = w.e = w.f = w.g = w.h = w.i = w.j = false;
var assistant = { firstName: "john", lastName: "english" };
var model = {
firstName: "bob", lastName: "smith",
boss: { firstName: "rick", lastName: "martin" },
getAssitant: function() { return assistant }
};
with (model) {
var parsed = eval("({" + rewritten + "})");
// test values of property
expect(parsed.a).toEqual(1);
expect(parsed.b).toEqual("bob");
expect(parsed.c()).toEqual("returnValue");
expect(parsed.d).toEqual("bobsmith");
expect(parsed.e).toEqual("rick");
expect(parsed.f).toEqual("martin");
expect(parsed.g).toEqual(assistant);
expect(parsed.h).toEqual("john");
expect(parsed.i).toEqual("english");
// test that only writable expressions are set up for writing
// 'j' matches due to the simple checking for trailing property accessor
expect(parsed._ko_property_writers).toHaveOwnProperties(['b','e','f','h','i','j']);
// make sure writing to them works
parsed._ko_property_writers.b("bob2");
expect(model.firstName).toEqual("bob2");
parsed._ko_property_writers.e("rick2");
expect(model.boss.firstName).toEqual("rick2");
parsed._ko_property_writers.f("martin2");
expect(model.boss.lastName).toEqual("martin2");
parsed._ko_property_writers.h("john2");
expect(assistant.firstName).toEqual("john2");
parsed._ko_property_writers.i("english2");
expect(assistant.lastName).toEqual("english2");
// make sure writing to 'j' doesn't error or actually change anything
parsed._ko_property_writers.j("nothing at all");
expect(model.boss.firstName).toEqual("rick2");
expect(model.boss.lastName).toEqual("martin2");
}
});
it('Should be able to eval rewritten literals that contain unquoted keywords as keys', function() {
var rewritten = ko.expressionRewriting.preProcessBindings("if: true");
expect(rewritten).toEqual("'if':true");
var evaluated = eval("({" + rewritten + "})");
expect(evaluated['if']).toEqual(true);
});
it('Should eval keys without a value as if the value is undefined', function() {
var rewritten = ko.expressionRewriting.preProcessBindings("a: 1, b");
var parsedRewritten = eval("({" + rewritten + "})");
expect(parsedRewritten.a).toEqual(1);
expect('b' in parsedRewritten).toBeTruthy();
expect(parsedRewritten.b).toBeUndefined();
});
it('Should return accessor functions for each value when called with the valueAccessors option', function() {
var rewritten = ko.expressionRewriting.preProcessBindings("a: 1", {valueAccessors:true});
expect(rewritten).toEqual("'a':function(){return 1 }");
var evaluated = eval("({" + rewritten + "})");
expect(evaluated['a']()).toEqual(1);
});
it('Should be able to parse and evaluate object literals containing division', function() {
// Test a variety of expressions that include a division
// The final regex ensures that each of the divisions is run through the code that distinguishes between the two types of slashes
var result = ko.expressionRewriting.parseObjectLiteral("a: null/1, b: 2/1, c: (6) / 2, d: '2'/2, r: /a regex/");
expect(result).toEqual([{key:'a', value: 'null/1'}, {key: 'b', value: '2/1'}, {key: 'c', value: '(6)/2'}, {key: 'd', value: '\'2\'/2'}, {key: 'r', value: '/a regex/'}]);
var rewritten = ko.expressionRewriting.preProcessBindings(result, {valueAccessors:true});
var evaluated = eval("({" + rewritten + "})");
expect(evaluated.a()).toEqual(0);
expect(evaluated.b()).toEqual(2);
expect(evaluated.c()).toEqual(3);
expect(evaluated.d()).toEqual(1);
});
});
|