objectmodel 4.4.6 → 4.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +8 -8
- package/.eslintrc.json +25 -25
- package/LICENSE +22 -22
- package/README.md +67 -67
- package/build/bundle-entry.dev.js +2 -2
- package/build/bundle-entry.js +11 -11
- package/dist/object-model.cjs +110 -110
- package/dist/object-model.js +83 -85
- package/dist/object-model.js.map +1 -1
- package/dist/object-model.min.js +2 -4
- package/dist/object-model.min.js.map +1 -1
- package/index.html +4 -4
- package/package.json +68 -72
- package/rollup.config.js +13 -13
- package/src/helpers.js +43 -43
- package/src/list-model.js +43 -43
- package/test/basic-model.spec.cjs +272 -272
- package/test/bench/array.html +51 -51
- package/test/bench/bench-lib.js +49 -49
- package/test/bench/map-no-cast.html +53 -53
- package/test/bench/map-set.html +52 -52
- package/test/bench/map.html +51 -51
- package/test/bench/object-models.html +87 -87
- package/test/index.cjs +13 -13
- package/test/map-model.spec.cjs +236 -236
- package/test/model.spec.cjs +30 -30
- package/test/set-model.spec.cjs +222 -222
- package/test/umd.html +25 -25
package/test/map-model.spec.cjs
CHANGED
|
@@ -1,237 +1,237 @@
|
|
|
1
|
-
/* global QUnit, MapModel, ObjectModel */
|
|
2
|
-
|
|
3
|
-
QUnit.module("Map Models");
|
|
4
|
-
|
|
5
|
-
QUnit.test("constructor && proto", function (assert) {
|
|
6
|
-
|
|
7
|
-
assert.ok(MapModel instanceof Function, "MapModel instanceof Function");
|
|
8
|
-
|
|
9
|
-
const Dict = MapModel(String, Number);
|
|
10
|
-
|
|
11
|
-
assert.ok(Dict instanceof MapModel, "Map models can be declared");
|
|
12
|
-
|
|
13
|
-
assert.ok(typeof Dict.extend === "function", "test Map model method extend");
|
|
14
|
-
assert.ok(typeof Dict.assert === "function", "test Map model method assert");
|
|
15
|
-
assert.ok(typeof Dict.test === "function", "test Map model method test");
|
|
16
|
-
assert.ok(Dict.definition.key === String, "test Map model prop definition 1/2");
|
|
17
|
-
assert.ok(Dict.definition.value === Number, "test Map model prop definition 2/2");
|
|
18
|
-
assert.ok(typeof Dict.assertions === "object", "test Map model prop assertions");
|
|
19
|
-
|
|
20
|
-
assert.ok(MapModel(undefined, undefined) instanceof MapModel, "MapModel can receive undefined as argument");
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
QUnit.test("instanciation && mutation methods watchers", function (assert) {
|
|
24
|
-
|
|
25
|
-
const Dict = MapModel(String, Number).assert(m => m.size >= 2, "minsize assert");
|
|
26
|
-
const m = Dict([["one", 1], ["two", 2]]);
|
|
27
|
-
|
|
28
|
-
assert.ok(m instanceof Dict && m instanceof Map, "Map models can be instanciated");
|
|
29
|
-
|
|
30
|
-
m.set("three", 3);
|
|
31
|
-
|
|
32
|
-
assert.equal(m.set.name, "set", "proxyfied methods keep original properties");
|
|
33
|
-
|
|
34
|
-
assert.throws(function () {
|
|
35
|
-
m.set("four", "4");
|
|
36
|
-
}, /TypeError.*expecting Map.set arguments\[1] to be Number, got String "4"/, "set calls are catched");
|
|
37
|
-
|
|
38
|
-
assert.equal(m.size, 3, "map size change is ok 1/2");
|
|
39
|
-
|
|
40
|
-
m.delete("three");
|
|
41
|
-
assert.throws(function () {
|
|
42
|
-
m.delete("two");
|
|
43
|
-
}, /TypeError.*minsize assert/, "delete calls are catched");
|
|
44
|
-
|
|
45
|
-
assert.throws(function () {
|
|
46
|
-
m.clear();
|
|
47
|
-
}, /TypeError.*minsize assert/, "clear calls are catched");
|
|
48
|
-
|
|
49
|
-
assert.equal(m.size, 2, "map size change is ok 2/2");
|
|
50
|
-
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
QUnit.test("validation in constructor", function (assert) {
|
|
54
|
-
|
|
55
|
-
const Dict = MapModel(String, Number)
|
|
56
|
-
const m = Dict([["one", 1], ["two", 2]]);
|
|
57
|
-
assert.equal(m.size, 2, "map size is ok");
|
|
58
|
-
|
|
59
|
-
assert.throws(function () {
|
|
60
|
-
Dict(["one", 1], [1, 2]);
|
|
61
|
-
}, /TypeError/, "validation in map model constructor 1/2");
|
|
62
|
-
|
|
63
|
-
assert.throws(function () {
|
|
64
|
-
Dict(["one", 1], ["two", "2"]);
|
|
65
|
-
}, /TypeError/, "validation in map model constructor 2/2");
|
|
66
|
-
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
QUnit.test("union types & submodels", function (assert) {
|
|
70
|
-
|
|
71
|
-
const Question = ObjectModel({ question: String })
|
|
72
|
-
const Answer = ObjectModel({ answer: Number })
|
|
73
|
-
|
|
74
|
-
const Dict = MapModel([Question, String], [Answer, String, Boolean]);
|
|
75
|
-
const m = Dict([["test", "test"]]);
|
|
76
|
-
m.set("is it real life ?", true);
|
|
77
|
-
m.set(Question({ question: "life universe and everything" }), Answer({ answer: 42 }));
|
|
78
|
-
m.set("another one with autocast", { answer: 43 });
|
|
79
|
-
assert.throws(function () {
|
|
80
|
-
m.set(42, false);
|
|
81
|
-
}, /TypeError.*expecting Map.set arguments\[0] to be.*[\s\S]*Number 42/, "map set multiple types for keys");
|
|
82
|
-
assert.throws(function () {
|
|
83
|
-
m.set("test", 42)
|
|
84
|
-
}, /TypeError.*expecting Map.set arguments\[1] to be.*[\s\S]*Number 42/, "map set multiple types for values");
|
|
85
|
-
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
QUnit.test("union types & fixed values", function (assert) {
|
|
89
|
-
|
|
90
|
-
const DictA = MapModel([true, 2, "3"], [4, "5"]);
|
|
91
|
-
assert.throws(function () {
|
|
92
|
-
DictA([["3", 4], ["2", "5"]]);
|
|
93
|
-
}, /TypeError.*expecting Map key to be true or 2 or "3", got String "2"/, "MapModel fixed values");
|
|
94
|
-
|
|
95
|
-
DictA([[true, 4], [2, "5"]]);
|
|
96
|
-
const DictB = DictA.extend().assert(m => m.size === 2);
|
|
97
|
-
const dictB = new DictB([[2, 4], ["3", "5"]]);
|
|
98
|
-
|
|
99
|
-
assert.ok(Object.getPrototypeOf(DictB.prototype) === DictA.prototype, "extension respect prototypal chain");
|
|
100
|
-
assert.ok(dictB instanceof DictB && dictB instanceof DictA, "map model inheritance");
|
|
101
|
-
DictA([[true, 4], [2, "5"]]).set("3", 4);
|
|
102
|
-
assert.throws(function () {
|
|
103
|
-
DictB([[true, 4], [2, "5"]]).set("3", 4);
|
|
104
|
-
}, /TypeError/, "min/max of inherit map model");
|
|
105
|
-
|
|
106
|
-
const DictC = DictB.extend("new", "val");
|
|
107
|
-
DictC([["new", "5"], [true, "val"]]);
|
|
108
|
-
assert.throws(function () {
|
|
109
|
-
DictB([["new", "5"], ["3", 4]]);
|
|
110
|
-
}, /TypeError/, "map model type extension 1/2");
|
|
111
|
-
assert.throws(function () {
|
|
112
|
-
DictB([["3", 4], [true, "val"]]);
|
|
113
|
-
}, /TypeError/, "map model type extension 2/2");
|
|
114
|
-
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
QUnit.test("Child map models in object models", function (assert) {
|
|
118
|
-
|
|
119
|
-
const Child = ObjectModel({ map: MapModel(Number, String) });
|
|
120
|
-
const Parent = ObjectModel({ child: Child });
|
|
121
|
-
|
|
122
|
-
const childO = Child({ map: new Map([[1, "one"], [2, "two"]]) });
|
|
123
|
-
assert.ok(childO.map instanceof Map, "child map model is instanceof Map");
|
|
124
|
-
const parentO = Parent({ child: childO });
|
|
125
|
-
assert.ok(parentO.child.map instanceof Map, "child map model from parent is Map");
|
|
126
|
-
|
|
127
|
-
childO.map.set(3, "three");
|
|
128
|
-
assert.throws(function () {
|
|
129
|
-
childO.map.set(4, false);
|
|
130
|
-
}, /TypeError/, "child map model catches invalid set value");
|
|
131
|
-
assert.throws(function () {
|
|
132
|
-
childO.map.set("four", "four");
|
|
133
|
-
}, /TypeError/, "child map model catches invalid set key");
|
|
134
|
-
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
QUnit.test("default values", function (assert) {
|
|
138
|
-
|
|
139
|
-
const M = MapModel(Number, String).defaultTo(new Map([[1, "one"], [2, "two"]]));
|
|
140
|
-
const a = M();
|
|
141
|
-
|
|
142
|
-
assert.ok(a instanceof Map && a.size === 2, "Map model default value");
|
|
143
|
-
|
|
144
|
-
M.default.set(3, "three");
|
|
145
|
-
|
|
146
|
-
const b = M();
|
|
147
|
-
|
|
148
|
-
assert.ok(b.size === 3 && Array.from(b.keys()).sort().join(";") === "1;2;3", "map model default value is mutable");
|
|
149
|
-
|
|
150
|
-
M.default = "nope";
|
|
151
|
-
|
|
152
|
-
assert.throws(function () {
|
|
153
|
-
M()
|
|
154
|
-
}, /TypeError/, "invalid default property still throws TypeError for map models");
|
|
155
|
-
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
QUnit.test("validate defaut values provided", function (assert) {
|
|
159
|
-
assert.throws(function () {
|
|
160
|
-
MapModel(Number, String).defaultTo()
|
|
161
|
-
}, /TypeError.*expecting Map of Number : String, got undefined*/, "invalid default value provided: undefined");
|
|
162
|
-
assert.throws(function () {
|
|
163
|
-
MapModel(Number, String).defaultTo(new Map([["foo", "bar"]]))
|
|
164
|
-
}, /TypeError.*expecting Map key to be Number, got String \"foo\"*/, "invalid default value provided: wrong type for key");
|
|
165
|
-
assert.throws(function () {
|
|
166
|
-
MapModel(Number, String).defaultTo(new Map([[1,2]]))
|
|
167
|
-
}, /TypeError.*expecting Map\[1\] to be String, got Number 2*/, "invalid default value provided: wrong type for value");
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
QUnit.test("assertions", function (assert) {
|
|
171
|
-
|
|
172
|
-
const MapMax3 = MapModel(Number, String).assert(function maxEntries(map) {
|
|
173
|
-
return map.size <= 3;
|
|
174
|
-
});
|
|
175
|
-
let map = MapMax3([[1, "one"], [2, "two"]]);
|
|
176
|
-
|
|
177
|
-
map.set(3, "three");
|
|
178
|
-
assert.throws(function () {
|
|
179
|
-
map.set(4, "four");
|
|
180
|
-
}, /TypeError[\s\S]*maxEntries/, "test assertion after map method");
|
|
181
|
-
|
|
182
|
-
const AssertMap = MapModel(Number, Number).assert(m => m.size > 0, "may throw exception");
|
|
183
|
-
|
|
184
|
-
new AssertMap([[1, 2]]);
|
|
185
|
-
|
|
186
|
-
assert.throws(function () { new AssertMap([]); },
|
|
187
|
-
/assertion "may throw exception" returned false.*for Map = \[]/,
|
|
188
|
-
"assertions catch exceptions on Map models"
|
|
189
|
-
);
|
|
190
|
-
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
QUnit.test("Automatic model casting", function (assert) {
|
|
194
|
-
|
|
195
|
-
const X = ObjectModel({ x: Number }).defaultTo({ x: 5 })
|
|
196
|
-
const Y = ObjectModel({ y: [Number] }).defaultTo({ y: 7 });
|
|
197
|
-
const M = MapModel(X, Y);
|
|
198
|
-
const m = M([[{ x: 9 }, {}]]);
|
|
199
|
-
|
|
200
|
-
assert.ok(Array.from(m.keys())[0] instanceof X, "test automatic model casting with map init 1/3")
|
|
201
|
-
assert.ok(Array.from(m.values())[0] instanceof Y, "test automatic model casting with map init 2/3")
|
|
202
|
-
let [k, v] = Array.from(m.entries())[0];
|
|
203
|
-
assert.equal(k.x * v.y, 63, "test automatic model casting with map init 3/3")
|
|
204
|
-
|
|
205
|
-
m.set({ x: 3 }, { y: 4 })
|
|
206
|
-
|
|
207
|
-
assert.ok(Array.from(m.keys())[1] instanceof X, "test automatic model casting with map mutator method 1/3")
|
|
208
|
-
assert.ok(Array.from(m.values())[1] instanceof Y, "test automatic model casting with map mutator method 2/3");
|
|
209
|
-
|
|
210
|
-
[k, v] = Array.from(m.entries())[1];
|
|
211
|
-
assert.equal(k.x * v.y, 12, "test automatic model casting with map mutator method 3/3")
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
QUnit.test("toString", function (assert) {
|
|
215
|
-
assert.equal(MapModel(Number, String).toString(), "Map of Number : String", "MapModel toString for basic elements")
|
|
216
|
-
assert.equal(MapModel(Date, [String, 42]).toString(), "Map of Date : String or 42", "MapModel toString for union type elements")
|
|
217
|
-
})
|
|
218
|
-
|
|
219
|
-
QUnit.test("dynamic definition", function (assert) {
|
|
220
|
-
let M = MapModel(String, String);
|
|
221
|
-
let m1 = M([["hello", "world"]])
|
|
222
|
-
M.definition.key = Number;
|
|
223
|
-
M.definition.value = Number;
|
|
224
|
-
let m2 = M([[1, 1], [2, 1], [3, 2], [4, 3], [5, 5]])
|
|
225
|
-
assert.equal(M.test(m1), false, "definition can be dynamically changed 1/4")
|
|
226
|
-
assert.equal(M.test(m2), true, "definition can be dynamically changed 2/4")
|
|
227
|
-
m1.clear();
|
|
228
|
-
assert.throws(() => m1.set("hello", "world"), /TypeError/, "definition can be dynamically changed 3/4")
|
|
229
|
-
m1.set(0, 42);
|
|
230
|
-
assert.equal(m1.get(0), 42, "definition can be dynamically changed 4/4")
|
|
231
|
-
|
|
232
|
-
let OM = ObjectModel({ n: Number });
|
|
233
|
-
M.definition.value = OM;
|
|
234
|
-
m1.clear();
|
|
235
|
-
m1.set(1, { n: 42 });
|
|
236
|
-
assert.ok(m1.get(1) instanceof OM, "autocast still works after definition dynamically changed")
|
|
1
|
+
/* global QUnit, MapModel, ObjectModel */
|
|
2
|
+
|
|
3
|
+
QUnit.module("Map Models");
|
|
4
|
+
|
|
5
|
+
QUnit.test("constructor && proto", function (assert) {
|
|
6
|
+
|
|
7
|
+
assert.ok(MapModel instanceof Function, "MapModel instanceof Function");
|
|
8
|
+
|
|
9
|
+
const Dict = MapModel(String, Number);
|
|
10
|
+
|
|
11
|
+
assert.ok(Dict instanceof MapModel, "Map models can be declared");
|
|
12
|
+
|
|
13
|
+
assert.ok(typeof Dict.extend === "function", "test Map model method extend");
|
|
14
|
+
assert.ok(typeof Dict.assert === "function", "test Map model method assert");
|
|
15
|
+
assert.ok(typeof Dict.test === "function", "test Map model method test");
|
|
16
|
+
assert.ok(Dict.definition.key === String, "test Map model prop definition 1/2");
|
|
17
|
+
assert.ok(Dict.definition.value === Number, "test Map model prop definition 2/2");
|
|
18
|
+
assert.ok(typeof Dict.assertions === "object", "test Map model prop assertions");
|
|
19
|
+
|
|
20
|
+
assert.ok(MapModel(undefined, undefined) instanceof MapModel, "MapModel can receive undefined as argument");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
QUnit.test("instanciation && mutation methods watchers", function (assert) {
|
|
24
|
+
|
|
25
|
+
const Dict = MapModel(String, Number).assert(m => m.size >= 2, "minsize assert");
|
|
26
|
+
const m = Dict([["one", 1], ["two", 2]]);
|
|
27
|
+
|
|
28
|
+
assert.ok(m instanceof Dict && m instanceof Map, "Map models can be instanciated");
|
|
29
|
+
|
|
30
|
+
m.set("three", 3);
|
|
31
|
+
|
|
32
|
+
assert.equal(m.set.name, "set", "proxyfied methods keep original properties");
|
|
33
|
+
|
|
34
|
+
assert.throws(function () {
|
|
35
|
+
m.set("four", "4");
|
|
36
|
+
}, /TypeError.*expecting Map.set arguments\[1] to be Number, got String "4"/, "set calls are catched");
|
|
37
|
+
|
|
38
|
+
assert.equal(m.size, 3, "map size change is ok 1/2");
|
|
39
|
+
|
|
40
|
+
m.delete("three");
|
|
41
|
+
assert.throws(function () {
|
|
42
|
+
m.delete("two");
|
|
43
|
+
}, /TypeError.*minsize assert/, "delete calls are catched");
|
|
44
|
+
|
|
45
|
+
assert.throws(function () {
|
|
46
|
+
m.clear();
|
|
47
|
+
}, /TypeError.*minsize assert/, "clear calls are catched");
|
|
48
|
+
|
|
49
|
+
assert.equal(m.size, 2, "map size change is ok 2/2");
|
|
50
|
+
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
QUnit.test("validation in constructor", function (assert) {
|
|
54
|
+
|
|
55
|
+
const Dict = MapModel(String, Number)
|
|
56
|
+
const m = Dict([["one", 1], ["two", 2]]);
|
|
57
|
+
assert.equal(m.size, 2, "map size is ok");
|
|
58
|
+
|
|
59
|
+
assert.throws(function () {
|
|
60
|
+
Dict(["one", 1], [1, 2]);
|
|
61
|
+
}, /TypeError/, "validation in map model constructor 1/2");
|
|
62
|
+
|
|
63
|
+
assert.throws(function () {
|
|
64
|
+
Dict(["one", 1], ["two", "2"]);
|
|
65
|
+
}, /TypeError/, "validation in map model constructor 2/2");
|
|
66
|
+
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
QUnit.test("union types & submodels", function (assert) {
|
|
70
|
+
|
|
71
|
+
const Question = ObjectModel({ question: String })
|
|
72
|
+
const Answer = ObjectModel({ answer: Number })
|
|
73
|
+
|
|
74
|
+
const Dict = MapModel([Question, String], [Answer, String, Boolean]);
|
|
75
|
+
const m = Dict([["test", "test"]]);
|
|
76
|
+
m.set("is it real life ?", true);
|
|
77
|
+
m.set(Question({ question: "life universe and everything" }), Answer({ answer: 42 }));
|
|
78
|
+
m.set("another one with autocast", { answer: 43 });
|
|
79
|
+
assert.throws(function () {
|
|
80
|
+
m.set(42, false);
|
|
81
|
+
}, /TypeError.*expecting Map.set arguments\[0] to be.*[\s\S]*Number 42/, "map set multiple types for keys");
|
|
82
|
+
assert.throws(function () {
|
|
83
|
+
m.set("test", 42)
|
|
84
|
+
}, /TypeError.*expecting Map.set arguments\[1] to be.*[\s\S]*Number 42/, "map set multiple types for values");
|
|
85
|
+
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
QUnit.test("union types & fixed values", function (assert) {
|
|
89
|
+
|
|
90
|
+
const DictA = MapModel([true, 2, "3"], [4, "5"]);
|
|
91
|
+
assert.throws(function () {
|
|
92
|
+
DictA([["3", 4], ["2", "5"]]);
|
|
93
|
+
}, /TypeError.*expecting Map key to be true or 2 or "3", got String "2"/, "MapModel fixed values");
|
|
94
|
+
|
|
95
|
+
DictA([[true, 4], [2, "5"]]);
|
|
96
|
+
const DictB = DictA.extend().assert(m => m.size === 2);
|
|
97
|
+
const dictB = new DictB([[2, 4], ["3", "5"]]);
|
|
98
|
+
|
|
99
|
+
assert.ok(Object.getPrototypeOf(DictB.prototype) === DictA.prototype, "extension respect prototypal chain");
|
|
100
|
+
assert.ok(dictB instanceof DictB && dictB instanceof DictA, "map model inheritance");
|
|
101
|
+
DictA([[true, 4], [2, "5"]]).set("3", 4);
|
|
102
|
+
assert.throws(function () {
|
|
103
|
+
DictB([[true, 4], [2, "5"]]).set("3", 4);
|
|
104
|
+
}, /TypeError/, "min/max of inherit map model");
|
|
105
|
+
|
|
106
|
+
const DictC = DictB.extend("new", "val");
|
|
107
|
+
DictC([["new", "5"], [true, "val"]]);
|
|
108
|
+
assert.throws(function () {
|
|
109
|
+
DictB([["new", "5"], ["3", 4]]);
|
|
110
|
+
}, /TypeError/, "map model type extension 1/2");
|
|
111
|
+
assert.throws(function () {
|
|
112
|
+
DictB([["3", 4], [true, "val"]]);
|
|
113
|
+
}, /TypeError/, "map model type extension 2/2");
|
|
114
|
+
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
QUnit.test("Child map models in object models", function (assert) {
|
|
118
|
+
|
|
119
|
+
const Child = ObjectModel({ map: MapModel(Number, String) });
|
|
120
|
+
const Parent = ObjectModel({ child: Child });
|
|
121
|
+
|
|
122
|
+
const childO = Child({ map: new Map([[1, "one"], [2, "two"]]) });
|
|
123
|
+
assert.ok(childO.map instanceof Map, "child map model is instanceof Map");
|
|
124
|
+
const parentO = Parent({ child: childO });
|
|
125
|
+
assert.ok(parentO.child.map instanceof Map, "child map model from parent is Map");
|
|
126
|
+
|
|
127
|
+
childO.map.set(3, "three");
|
|
128
|
+
assert.throws(function () {
|
|
129
|
+
childO.map.set(4, false);
|
|
130
|
+
}, /TypeError/, "child map model catches invalid set value");
|
|
131
|
+
assert.throws(function () {
|
|
132
|
+
childO.map.set("four", "four");
|
|
133
|
+
}, /TypeError/, "child map model catches invalid set key");
|
|
134
|
+
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
QUnit.test("default values", function (assert) {
|
|
138
|
+
|
|
139
|
+
const M = MapModel(Number, String).defaultTo(new Map([[1, "one"], [2, "two"]]));
|
|
140
|
+
const a = M();
|
|
141
|
+
|
|
142
|
+
assert.ok(a instanceof Map && a.size === 2, "Map model default value");
|
|
143
|
+
|
|
144
|
+
M.default.set(3, "three");
|
|
145
|
+
|
|
146
|
+
const b = M();
|
|
147
|
+
|
|
148
|
+
assert.ok(b.size === 3 && Array.from(b.keys()).sort().join(";") === "1;2;3", "map model default value is mutable");
|
|
149
|
+
|
|
150
|
+
M.default = "nope";
|
|
151
|
+
|
|
152
|
+
assert.throws(function () {
|
|
153
|
+
M()
|
|
154
|
+
}, /TypeError/, "invalid default property still throws TypeError for map models");
|
|
155
|
+
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
QUnit.test("validate defaut values provided", function (assert) {
|
|
159
|
+
assert.throws(function () {
|
|
160
|
+
MapModel(Number, String).defaultTo()
|
|
161
|
+
}, /TypeError.*expecting Map of Number : String, got undefined*/, "invalid default value provided: undefined");
|
|
162
|
+
assert.throws(function () {
|
|
163
|
+
MapModel(Number, String).defaultTo(new Map([["foo", "bar"]]))
|
|
164
|
+
}, /TypeError.*expecting Map key to be Number, got String \"foo\"*/, "invalid default value provided: wrong type for key");
|
|
165
|
+
assert.throws(function () {
|
|
166
|
+
MapModel(Number, String).defaultTo(new Map([[1,2]]))
|
|
167
|
+
}, /TypeError.*expecting Map\[1\] to be String, got Number 2*/, "invalid default value provided: wrong type for value");
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
QUnit.test("assertions", function (assert) {
|
|
171
|
+
|
|
172
|
+
const MapMax3 = MapModel(Number, String).assert(function maxEntries(map) {
|
|
173
|
+
return map.size <= 3;
|
|
174
|
+
});
|
|
175
|
+
let map = MapMax3([[1, "one"], [2, "two"]]);
|
|
176
|
+
|
|
177
|
+
map.set(3, "three");
|
|
178
|
+
assert.throws(function () {
|
|
179
|
+
map.set(4, "four");
|
|
180
|
+
}, /TypeError[\s\S]*maxEntries/, "test assertion after map method");
|
|
181
|
+
|
|
182
|
+
const AssertMap = MapModel(Number, Number).assert(m => m.size > 0, "may throw exception");
|
|
183
|
+
|
|
184
|
+
new AssertMap([[1, 2]]);
|
|
185
|
+
|
|
186
|
+
assert.throws(function () { new AssertMap([]); },
|
|
187
|
+
/assertion "may throw exception" returned false.*for Map = \[]/,
|
|
188
|
+
"assertions catch exceptions on Map models"
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
QUnit.test("Automatic model casting", function (assert) {
|
|
194
|
+
|
|
195
|
+
const X = ObjectModel({ x: Number }).defaultTo({ x: 5 })
|
|
196
|
+
const Y = ObjectModel({ y: [Number] }).defaultTo({ y: 7 });
|
|
197
|
+
const M = MapModel(X, Y);
|
|
198
|
+
const m = M([[{ x: 9 }, {}]]);
|
|
199
|
+
|
|
200
|
+
assert.ok(Array.from(m.keys())[0] instanceof X, "test automatic model casting with map init 1/3")
|
|
201
|
+
assert.ok(Array.from(m.values())[0] instanceof Y, "test automatic model casting with map init 2/3")
|
|
202
|
+
let [k, v] = Array.from(m.entries())[0];
|
|
203
|
+
assert.equal(k.x * v.y, 63, "test automatic model casting with map init 3/3")
|
|
204
|
+
|
|
205
|
+
m.set({ x: 3 }, { y: 4 })
|
|
206
|
+
|
|
207
|
+
assert.ok(Array.from(m.keys())[1] instanceof X, "test automatic model casting with map mutator method 1/3")
|
|
208
|
+
assert.ok(Array.from(m.values())[1] instanceof Y, "test automatic model casting with map mutator method 2/3");
|
|
209
|
+
|
|
210
|
+
[k, v] = Array.from(m.entries())[1];
|
|
211
|
+
assert.equal(k.x * v.y, 12, "test automatic model casting with map mutator method 3/3")
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
QUnit.test("toString", function (assert) {
|
|
215
|
+
assert.equal(MapModel(Number, String).toString(), "Map of Number : String", "MapModel toString for basic elements")
|
|
216
|
+
assert.equal(MapModel(Date, [String, 42]).toString(), "Map of Date : String or 42", "MapModel toString for union type elements")
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
QUnit.test("dynamic definition", function (assert) {
|
|
220
|
+
let M = MapModel(String, String);
|
|
221
|
+
let m1 = M([["hello", "world"]])
|
|
222
|
+
M.definition.key = Number;
|
|
223
|
+
M.definition.value = Number;
|
|
224
|
+
let m2 = M([[1, 1], [2, 1], [3, 2], [4, 3], [5, 5]])
|
|
225
|
+
assert.equal(M.test(m1), false, "definition can be dynamically changed 1/4")
|
|
226
|
+
assert.equal(M.test(m2), true, "definition can be dynamically changed 2/4")
|
|
227
|
+
m1.clear();
|
|
228
|
+
assert.throws(() => m1.set("hello", "world"), /TypeError/, "definition can be dynamically changed 3/4")
|
|
229
|
+
m1.set(0, 42);
|
|
230
|
+
assert.equal(m1.get(0), 42, "definition can be dynamically changed 4/4")
|
|
231
|
+
|
|
232
|
+
let OM = ObjectModel({ n: Number });
|
|
233
|
+
M.definition.value = OM;
|
|
234
|
+
m1.clear();
|
|
235
|
+
m1.set(1, { n: 42 });
|
|
236
|
+
assert.ok(m1.get(1) instanceof OM, "autocast still works after definition dynamically changed")
|
|
237
237
|
})
|
package/test/model.spec.cjs
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
/* global QUnit, Model, BasicModel, ObjectModel */
|
|
2
|
-
|
|
3
|
-
QUnit.module("Generic Model");
|
|
4
|
-
|
|
5
|
-
QUnit.test("Generic models constructor && proto", function (assert) {
|
|
6
|
-
assert.ok(Model instanceof Function, "Model is defined");
|
|
7
|
-
|
|
8
|
-
assert.ok(Model(Number) instanceof BasicModel, "test model constructor 1/4");
|
|
9
|
-
assert.ok(Model({}) instanceof ObjectModel, "test model constructor 2/4");
|
|
10
|
-
assert.ok(Model([]) instanceof BasicModel, "test model constructor 3/4");
|
|
11
|
-
assert.ok(Model() instanceof BasicModel, "test model constructor 4/4");
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
QUnit.test("Model names", function (assert) {
|
|
15
|
-
let NamedModel = Model({}).as("Test");
|
|
16
|
-
assert.equal(NamedModel.name, "Test", "test model name 1/2")
|
|
17
|
-
let namedInstance = NamedModel({});
|
|
18
|
-
assert.equal(Object.getPrototypeOf(namedInstance).constructor.name, "Test", "test model name 2/2");
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
QUnit.test("Exotic objects", function (assert) {
|
|
22
|
-
const VoidObject = Object.create(null) // not using Object.prototype
|
|
23
|
-
VoidObject.foo = "bar"
|
|
24
|
-
const VoidObjectModel = Model(VoidObject)
|
|
25
|
-
|
|
26
|
-
assert.ok(VoidObjectModel instanceof BasicModel, "should not be ObjectModel since not inheriting from Object proto")
|
|
27
|
-
assert.throws(function () {
|
|
28
|
-
VoidObjectModel({})
|
|
29
|
-
}, /expecting {\n\tfoo: "bar"/, "validates correctly exotic objects")
|
|
30
|
-
assert.equal(VoidObjectModel(VoidObject).foo, "bar", "accept valid exotic objects")
|
|
1
|
+
/* global QUnit, Model, BasicModel, ObjectModel */
|
|
2
|
+
|
|
3
|
+
QUnit.module("Generic Model");
|
|
4
|
+
|
|
5
|
+
QUnit.test("Generic models constructor && proto", function (assert) {
|
|
6
|
+
assert.ok(Model instanceof Function, "Model is defined");
|
|
7
|
+
|
|
8
|
+
assert.ok(Model(Number) instanceof BasicModel, "test model constructor 1/4");
|
|
9
|
+
assert.ok(Model({}) instanceof ObjectModel, "test model constructor 2/4");
|
|
10
|
+
assert.ok(Model([]) instanceof BasicModel, "test model constructor 3/4");
|
|
11
|
+
assert.ok(Model() instanceof BasicModel, "test model constructor 4/4");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
QUnit.test("Model names", function (assert) {
|
|
15
|
+
let NamedModel = Model({}).as("Test");
|
|
16
|
+
assert.equal(NamedModel.name, "Test", "test model name 1/2")
|
|
17
|
+
let namedInstance = NamedModel({});
|
|
18
|
+
assert.equal(Object.getPrototypeOf(namedInstance).constructor.name, "Test", "test model name 2/2");
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
QUnit.test("Exotic objects", function (assert) {
|
|
22
|
+
const VoidObject = Object.create(null) // not using Object.prototype
|
|
23
|
+
VoidObject.foo = "bar"
|
|
24
|
+
const VoidObjectModel = Model(VoidObject)
|
|
25
|
+
|
|
26
|
+
assert.ok(VoidObjectModel instanceof BasicModel, "should not be ObjectModel since not inheriting from Object proto")
|
|
27
|
+
assert.throws(function () {
|
|
28
|
+
VoidObjectModel({})
|
|
29
|
+
}, /expecting {\n\tfoo: "bar"/, "validates correctly exotic objects")
|
|
30
|
+
assert.equal(VoidObjectModel(VoidObject).foo, "bar", "accept valid exotic objects")
|
|
31
31
|
})
|