objectmodel 4.4.2 → 4.4.3

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.
@@ -1,292 +1,301 @@
1
- /* global QUnit, ArrayModel, ObjectModel */
2
-
3
- QUnit.module("Array Models");
4
-
5
- QUnit.test("constructor && proto", function (assert) {
6
-
7
- assert.ok(ArrayModel instanceof Function, "ArrayModel instanceof Function");
8
-
9
- const Arr = ArrayModel(Number);
10
-
11
- assert.ok(Arr instanceof ArrayModel, "Array models can be declared");
12
-
13
- assert.ok(typeof Arr.extend === "function", "test Array model method extend");
14
- assert.ok(typeof Arr.assert === "function", "test Array model method assert");
15
- assert.ok(typeof Arr.test === "function", "test Array model method test");
16
- assert.ok(Arr.definition === Number, "test Array model prop definition");
17
- assert.ok(typeof Arr.assertions === "object", "test Array model prop assertions");
18
-
19
- assert.ok(ArrayModel(undefined) instanceof ArrayModel, "ArrayModel can receive undefined as argument");
20
- });
21
-
22
- QUnit.test("instanciation && mutation methods watchers", function (assert) {
23
-
24
- const Arr = ArrayModel(Number);
25
- const a = Arr([]);
26
-
27
- assert.ok(a instanceof Arr && a instanceof Array, "Array models can be instanciated");
28
-
29
- assert.equal(a.push.name, "push", "proxyfied methods keep original properties");
30
-
31
- a.push(1);
32
- a[0] = 42;
33
- a.splice(1, 0, 5, 6, Infinity);
34
- assert.throws(function () {
35
- a.push("toto");
36
- }, /TypeError/, "push calls are catched");
37
- assert.throws(function () {
38
- a[0] = {};
39
- }, /TypeError/, "array keys set are catched");
40
- assert.throws(function () {
41
- a.splice(1, 0, 7, 'oups', 9);
42
- }, /TypeError/, "splice calls are catched");
43
- assert.equal(a.length, 4, "array length change is ok");
44
-
45
- });
46
-
47
- QUnit.test("validation in constructor", function (assert) {
48
-
49
- const Arr = ArrayModel(Number);
50
- const b = Arr([1, 2, 3]);
51
- assert.equal(b.length, 3, "array.length is ok");
52
-
53
- assert.throws(function () {
54
- Arr([1, false, 3]);
55
- }, /TypeError/, "validation in array model constructor 1/2");
56
-
57
- assert.throws(function () {
58
- Arr([1, 2, 3, function () {
59
- }]);
60
- }, /TypeError/, "validation in array model constructor 2/2");
61
-
62
- });
63
-
64
- QUnit.test("union types & submodels", function (assert) {
65
-
66
- const Question = ObjectModel({
67
- answer: Number
68
- });
69
-
70
- const Arr = ArrayModel([Question, String, Boolean]);
71
- const a = Arr(["test"]);
72
- a.unshift(true);
73
- a.push(Question({ answer: 42 }));
74
- a.push({ answer: 43 });
75
- assert.throws(function () {
76
- a.unshift(42);
77
- }, /TypeError/, "unshift multiple types");
78
- assert.throws(function () {
79
- a[0] = null;
80
- }, /TypeError/, "set index multiple types");
81
-
82
- })
83
-
84
- QUnit.test("union types & fixed values", function (assert) {
85
-
86
- const Arr = ArrayModel([true, 2, "3"]);
87
- assert.throws(function () {
88
- Arr(["3", 2, true, 1]);
89
- }, /TypeError[\s\S]*Array\[3]/, "ArrayModel fixed values");
90
-
91
- const Cards = ArrayModel([Number, "J", "Q", "K"]); // array of Numbers, J, Q or K
92
- const Hand = Cards.extend().assert(cards => cards.length === 2);
93
- const pokerHand = new Hand(["K", 10]);
94
-
95
- assert.ok(Object.getPrototypeOf(Hand.prototype) === Cards.prototype, "extension respect prototypal chain");
96
- assert.ok(pokerHand instanceof Hand && pokerHand instanceof Cards, "array model inheritance");
97
- Cards(["K", 10]).push(7);
98
- assert.throws(function () {
99
- Hand(["K", 10]).push(7);
100
- }, /TypeError/, "min/max of inherit array model");
101
-
102
- const CheaterHand = Cards.extend("joker");
103
- CheaterHand(["K", 10, "joker"]);
104
- assert.throws(function () {
105
- Hand("K", 10, "joker");
106
- }, /TypeError/, "array model type extension");
107
-
108
- })
109
-
110
- QUnit.test("Child array models in object models", function (assert) {
111
-
112
- const Child = ObjectModel({ arr: ArrayModel(String) });
113
- const Parent = ObjectModel({ child: Child });
114
-
115
- const childO = Child({ arr: ["a", "b", "c"] });
116
- assert.ok(childO.arr instanceof Array, "child array model is array");
117
- const parentO = Parent({ child: childO });
118
- assert.ok(parentO.child.arr instanceof Array, "child array model from parent is array");
119
-
120
- childO.arr.push("a");
121
- assert.throws(function () {
122
- childO.arr.push(false);
123
- }, /TypeError/, "child array model catches push calls");
124
- assert.throws(function () {
125
- childO.arr[0] = 1;
126
- }, /TypeError/, "child array model catches set index");
127
-
128
- });
129
-
130
- QUnit.test("default values", function (assert) {
131
-
132
- const ArrModel = ArrayModel([Number, String]).defaultTo([]);
133
- const a = ArrModel();
134
-
135
- assert.ok(a instanceof Array && a.length === 0, "Array model default value");
136
- a.push(1, 2);
137
-
138
- const b = ArrModel();
139
- assert.ok(b instanceof Array && b.length === 0, "Avoid default value common reference issue for Array models");
140
-
141
- ArrModel.default.push(1, 2, 3);
142
-
143
- const c = ArrModel();
144
-
145
- assert.ok(c.length === 3 && c.join(";") === "1;2;3", "array model default value is mutable array");
146
-
147
- ArrModel.default = "nope";
148
-
149
- assert.throws(function () {
150
- ArrModel()
151
- }, /TypeError.*got String "nope"/, "invalid default property still throws TypeError for array models");
152
-
153
- })
154
-
155
- QUnit.test("Assertions", function (assert) {
156
-
157
- const ArrayMax3 = ArrayModel(Number).assert(function maxRange(arr) { return arr.length <= 3; });
158
- let arr = ArrayMax3([1, 2]);
159
-
160
- arr.push(3);
161
- assert.throws(function () { arr.push(4); }, /TypeError[\s\S]*maxRange/, "test assertion after array method");
162
-
163
- const ArraySumMax10 = ArrayModel(Number).assert(function (arr) {
164
- return arr.reduce(function (a, b) { return a + b; }, 0) <= 10;
165
- });
166
-
167
- arr = ArraySumMax10([2, 3, 4]);
168
- assert.throws(function () { arr[1] = 7; }, /TypeError/, "test assertion after array key assignment");
169
-
170
- const AssertArray = ArrayModel(Number).assert(v => v.length >= 0, "may throw exception");
171
-
172
- new AssertArray([]);
173
-
174
- assert.throws(function () { new AssertArray(); },
175
- /assertion "may throw exception" returned TypeError.*for value undefined/,
176
- "assertions catch exceptions on Array models");
177
-
178
- })
179
-
180
- QUnit.test("Automatic model casting", function (assert) {
181
-
182
- const N = ObjectModel({ x: Number, y: [Number] }).defaultTo({ x: 5, y: 7 });
183
- const Arr = ArrayModel(N);
184
- const a = Arr([{ x: 9 }]);
185
-
186
- assert.ok(a[0] instanceof N, "test automatic model casting with array init 1/2")
187
- assert.equal(a[0].x * a[0].y, 63, "test automatic model casting with array init 2/2")
188
-
189
- a.push({ x: 3 });
190
-
191
- assert.ok(a[1] instanceof N, "test automatic model casting with array push method 1/2")
192
- assert.equal(a[1].x * a[1].y, 21, "test automatic model casting with array push method 2/2")
193
-
194
- a.splice(1, 1, { x: 4 });
195
-
196
- assert.ok(a[1] instanceof N, "test automatic model casting with array splice method 1/2")
197
- assert.equal(a[1].x * a[1].y, 28, "test automatic model casting with array splice method 2/2")
198
-
199
- a.fill({ x: 5 })
200
-
201
- assert.ok(a[1] instanceof N, "test automatic model casting with array fill method 1/2")
202
- assert.equal(a[1].x * a[1].y, 35, "test automatic model casting with array fill method 2/2")
203
-
204
- a.unshift({ x: 1 }, { x: 6 })
205
-
206
- assert.ok(a[1] instanceof N, "test automatic model casting with array unshift method 1/2")
207
- assert.equal(a[1].x * a[1].y, 42, "test automatic model casting with array unshift method 2/2")
208
-
209
- a[0] = { x: 10 };
210
-
211
- assert.ok(a[0] instanceof N, "test automatic model casting with array set index 1/2")
212
- assert.equal(a[0].x * a[0].y, 70, "test automatic model casting with array set index 2/2");
213
-
214
- });
215
-
216
- QUnit.test("Other traps", function (assert) {
217
-
218
- const Arr = ArrayModel(Number);
219
- const a = Arr([1, 2, 3])
220
-
221
- delete a.unknownProperty;
222
- delete a[3];
223
-
224
- assert.throws(function () {
225
- delete a[2]
226
- }, /TypeError/, "deleteProperty trap block array holes if def != undefined")
227
-
228
- const ArrB = ArrayModel([Number]);
229
- const b = ArrB([1, 2, 3])
230
-
231
- delete b[2]
232
- assert.equal(b[2], undefined, "deleteProperty trap does not block when def is optional")
233
- })
234
-
235
- QUnit.test("toString", function (assert) {
236
- assert.equal(ArrayModel(Number).toString(), "Array of Number", "ArrayModels toString for basic elements")
237
- assert.equal(ArrayModel([String, 42]).toString(), "Array of String or 42", "ArrayModels toString for union type elements")
238
- })
239
-
240
- QUnit.test("Dynamic definition", function (assert) {
241
- let A = ArrayModel(String);
242
- let a1 = A(["hello", "world"])
243
- A.definition = Number;
244
- let a2 = A([1, 2, 3])
245
- assert.equal(A.test(a1), false, "definition can be dynamically changed 1/4")
246
- assert.equal(A.test(a2), true, "definition can be dynamically changed 2/4")
247
- a1.splice(0, a1.length);
248
- assert.throws(() => a1.push("hello"), /TypeError/, "definition can be dynamically changed 3/4")
249
- a1.push(42);
250
- assert.equal(a1[0], 42, "definition can be dynamically changed 4/4")
251
-
252
- let OM = ObjectModel({ n: Number });
253
- A.definition = OM;
254
- a1.splice(0, a1.length);
255
- a1.push({ n: 42 });
256
- assert.ok(a1[0] instanceof OM, "autocast still works after definition dynamically changed")
257
- })
258
-
259
- QUnit.test("delete key", function (assert) {
260
- let A = ArrayModel([Number]);
261
- let a = A([1, 2, 3])
262
- delete a[2]
263
- assert.equal(3 in a, false, "delete should remove own array key")
264
- assert.equal(a.length, 3, "delete should not update length")
265
- assert.equal(Object.keys(a).length, 2, "delete should leave an empty hole")
266
-
267
- const ArrayDense = ArrayModel([Number]).assert(function hasNoHoles(arr) {
268
- return arr.filter(() => true).length === arr.length
269
- }).as("ArrayDense");
270
-
271
- A = ArrayDense.extend([Number]);
272
- a = A([4, 5, 6])
273
- assert.throws(() => {
274
- delete a[2]
275
- }, /TypeError.*hasNoHoles/, "ArrayDense should prevent deleting keys")
276
-
277
- })
278
-
279
- QUnit.test("Arraymodel as ObjectModel default prop", function (assert) {
280
- class OM extends ObjectModel({
281
- a: ArrayModel(Number)
282
- }).defaultTo({
283
- a: []
284
- }) { }
285
-
286
- let o = new OM();
287
-
288
- assert.ok(Array.isArray(o.a), "ArrayModel works as ObjectModel default prop")
289
- o.a.push(1, 2, 3)
290
- assert.equal(o.a.length, 3, "ArrayModel as ObjectModel default prop can be mutated")
291
-
1
+ /* global QUnit, ArrayModel, ObjectModel */
2
+
3
+ QUnit.module("Array Models");
4
+
5
+ QUnit.test("constructor && proto", function (assert) {
6
+
7
+ assert.ok(ArrayModel instanceof Function, "ArrayModel instanceof Function");
8
+
9
+ const Arr = ArrayModel(Number);
10
+
11
+ assert.ok(Arr instanceof ArrayModel, "Array models can be declared");
12
+
13
+ assert.ok(typeof Arr.extend === "function", "test Array model method extend");
14
+ assert.ok(typeof Arr.assert === "function", "test Array model method assert");
15
+ assert.ok(typeof Arr.test === "function", "test Array model method test");
16
+ assert.ok(Arr.definition === Number, "test Array model prop definition");
17
+ assert.ok(typeof Arr.assertions === "object", "test Array model prop assertions");
18
+
19
+ assert.ok(ArrayModel(undefined) instanceof ArrayModel, "ArrayModel can receive undefined as argument");
20
+ });
21
+
22
+ QUnit.test("instanciation && mutation methods watchers", function (assert) {
23
+
24
+ const Arr = ArrayModel(Number);
25
+ const a = Arr([]);
26
+
27
+ assert.ok(a instanceof Arr && a instanceof Array, "Array models can be instanciated");
28
+
29
+ assert.equal(a.push.name, "push", "proxyfied methods keep original properties");
30
+
31
+ a.push(1);
32
+ a[0] = 42;
33
+ a.splice(1, 0, 5, 6, Infinity);
34
+ assert.throws(function () {
35
+ a.push("toto");
36
+ }, /TypeError/, "push calls are catched");
37
+ assert.throws(function () {
38
+ a[0] = {};
39
+ }, /TypeError/, "array keys set are catched");
40
+ assert.throws(function () {
41
+ a.splice(1, 0, 7, 'oups', 9);
42
+ }, /TypeError/, "splice calls are catched");
43
+ assert.equal(a.length, 4, "array length change is ok");
44
+
45
+ });
46
+
47
+ QUnit.test("validation in constructor", function (assert) {
48
+
49
+ const Arr = ArrayModel(Number);
50
+ const b = Arr([1, 2, 3]);
51
+ assert.equal(b.length, 3, "array.length is ok");
52
+
53
+ assert.throws(function () {
54
+ Arr([1, false, 3]);
55
+ }, /TypeError/, "validation in array model constructor 1/2");
56
+
57
+ assert.throws(function () {
58
+ Arr([1, 2, 3, function () {
59
+ }]);
60
+ }, /TypeError/, "validation in array model constructor 2/2");
61
+
62
+ });
63
+
64
+ QUnit.test("union types & submodels", function (assert) {
65
+
66
+ const Question = ObjectModel({
67
+ answer: Number
68
+ });
69
+
70
+ const Arr = ArrayModel([Question, String, Boolean]);
71
+ const a = Arr(["test"]);
72
+ a.unshift(true);
73
+ a.push(Question({ answer: 42 }));
74
+ a.push({ answer: 43 });
75
+ assert.throws(function () {
76
+ a.unshift(42);
77
+ }, /TypeError/, "unshift multiple types");
78
+ assert.throws(function () {
79
+ a[0] = null;
80
+ }, /TypeError/, "set index multiple types");
81
+
82
+ })
83
+
84
+ QUnit.test("union types & fixed values", function (assert) {
85
+
86
+ const Arr = ArrayModel([true, 2, "3"]);
87
+ assert.throws(function () {
88
+ Arr(["3", 2, true, 1]);
89
+ }, /TypeError[\s\S]*Array\[3]/, "ArrayModel fixed values");
90
+
91
+ const Cards = ArrayModel([Number, "J", "Q", "K"]); // array of Numbers, J, Q or K
92
+ const Hand = Cards.extend().assert(cards => cards.length === 2);
93
+ const pokerHand = new Hand(["K", 10]);
94
+
95
+ assert.ok(Object.getPrototypeOf(Hand.prototype) === Cards.prototype, "extension respect prototypal chain");
96
+ assert.ok(pokerHand instanceof Hand && pokerHand instanceof Cards, "array model inheritance");
97
+ Cards(["K", 10]).push(7);
98
+ assert.throws(function () {
99
+ Hand(["K", 10]).push(7);
100
+ }, /TypeError/, "min/max of inherit array model");
101
+
102
+ const CheaterHand = Cards.extend("joker");
103
+ CheaterHand(["K", 10, "joker"]);
104
+ assert.throws(function () {
105
+ Hand("K", 10, "joker");
106
+ }, /TypeError/, "array model type extension");
107
+
108
+ })
109
+
110
+ QUnit.test("Child array models in object models", function (assert) {
111
+
112
+ const Child = ObjectModel({ arr: ArrayModel(String) });
113
+ const Parent = ObjectModel({ child: Child });
114
+
115
+ const childO = Child({ arr: ["a", "b", "c"] });
116
+ assert.ok(childO.arr instanceof Array, "child array model is array");
117
+ const parentO = Parent({ child: childO });
118
+ assert.ok(parentO.child.arr instanceof Array, "child array model from parent is array");
119
+
120
+ childO.arr.push("a");
121
+ assert.throws(function () {
122
+ childO.arr.push(false);
123
+ }, /TypeError/, "child array model catches push calls");
124
+ assert.throws(function () {
125
+ childO.arr[0] = 1;
126
+ }, /TypeError/, "child array model catches set index");
127
+
128
+ });
129
+
130
+ QUnit.test("default values", function (assert) {
131
+
132
+ const ArrModel = ArrayModel([Number, String]).defaultTo([]);
133
+ const a = ArrModel();
134
+
135
+ assert.ok(a instanceof Array && a.length === 0, "Array model default value");
136
+ a.push(1, 2);
137
+
138
+ const b = ArrModel();
139
+ assert.ok(b instanceof Array && b.length === 0, "Avoid default value common reference issue for Array models");
140
+
141
+ ArrModel.default.push(1, 2, 3);
142
+
143
+ const c = ArrModel();
144
+
145
+ assert.ok(c.length === 3 && c.join(";") === "1;2;3", "array model default value is mutable array");
146
+
147
+ ArrModel.default = "nope";
148
+
149
+ assert.throws(function () {
150
+ ArrModel()
151
+ }, /TypeError.*got String "nope"/, "invalid default property still throws TypeError for array models");
152
+
153
+ })
154
+
155
+ QUnit.test("validate defaut values provided", function (assert) {
156
+ assert.throws(function () {
157
+ ArrayModel(Number).defaultTo()
158
+ }, /TypeError.*expecting Array of Number, got undefined*/, "invalid default value provided: undefined");
159
+ assert.throws(function () {
160
+ ArrayModel(String).defaultTo("test")
161
+ }, /TypeError.*expecting Array of String, got String \"test\"*/, "invalid default value provided: wrong type");
162
+ })
163
+
164
+ QUnit.test("Assertions", function (assert) {
165
+
166
+ const ArrayMax3 = ArrayModel(Number).assert(function maxRange(arr) { return arr.length <= 3; });
167
+ let arr = ArrayMax3([1, 2]);
168
+
169
+ arr.push(3);
170
+ assert.throws(function () { arr.push(4); }, /TypeError[\s\S]*maxRange/, "test assertion after array method");
171
+
172
+ const ArraySumMax10 = ArrayModel(Number).assert(function (arr) {
173
+ return arr.reduce(function (a, b) { return a + b; }, 0) <= 10;
174
+ });
175
+
176
+ arr = ArraySumMax10([2, 3, 4]);
177
+ assert.throws(function () { arr[1] = 7; }, /TypeError/, "test assertion after array key assignment");
178
+
179
+ const AssertArray = ArrayModel(Number).assert(v => v.length >= 0, "may throw exception");
180
+
181
+ new AssertArray([]);
182
+
183
+ assert.throws(function () { new AssertArray(); },
184
+ /assertion "may throw exception" returned TypeError.*for value undefined/,
185
+ "assertions catch exceptions on Array models");
186
+
187
+ })
188
+
189
+ QUnit.test("Automatic model casting", function (assert) {
190
+
191
+ const N = ObjectModel({ x: Number, y: [Number] }).defaultTo({ x: 5, y: 7 });
192
+ const Arr = ArrayModel(N);
193
+ const a = Arr([{ x: 9 }]);
194
+
195
+ assert.ok(a[0] instanceof N, "test automatic model casting with array init 1/2")
196
+ assert.equal(a[0].x * a[0].y, 63, "test automatic model casting with array init 2/2")
197
+
198
+ a.push({ x: 3 });
199
+
200
+ assert.ok(a[1] instanceof N, "test automatic model casting with array push method 1/2")
201
+ assert.equal(a[1].x * a[1].y, 21, "test automatic model casting with array push method 2/2")
202
+
203
+ a.splice(1, 1, { x: 4 });
204
+
205
+ assert.ok(a[1] instanceof N, "test automatic model casting with array splice method 1/2")
206
+ assert.equal(a[1].x * a[1].y, 28, "test automatic model casting with array splice method 2/2")
207
+
208
+ a.fill({ x: 5 })
209
+
210
+ assert.ok(a[1] instanceof N, "test automatic model casting with array fill method 1/2")
211
+ assert.equal(a[1].x * a[1].y, 35, "test automatic model casting with array fill method 2/2")
212
+
213
+ a.unshift({ x: 1 }, { x: 6 })
214
+
215
+ assert.ok(a[1] instanceof N, "test automatic model casting with array unshift method 1/2")
216
+ assert.equal(a[1].x * a[1].y, 42, "test automatic model casting with array unshift method 2/2")
217
+
218
+ a[0] = { x: 10 };
219
+
220
+ assert.ok(a[0] instanceof N, "test automatic model casting with array set index 1/2")
221
+ assert.equal(a[0].x * a[0].y, 70, "test automatic model casting with array set index 2/2");
222
+
223
+ });
224
+
225
+ QUnit.test("Other traps", function (assert) {
226
+
227
+ const Arr = ArrayModel(Number);
228
+ const a = Arr([1, 2, 3])
229
+
230
+ delete a.unknownProperty;
231
+ delete a[3];
232
+
233
+ assert.throws(function () {
234
+ delete a[2]
235
+ }, /TypeError/, "deleteProperty trap block array holes if def != undefined")
236
+
237
+ const ArrB = ArrayModel([Number]);
238
+ const b = ArrB([1, 2, 3])
239
+
240
+ delete b[2]
241
+ assert.equal(b[2], undefined, "deleteProperty trap does not block when def is optional")
242
+ })
243
+
244
+ QUnit.test("toString", function (assert) {
245
+ assert.equal(ArrayModel(Number).toString(), "Array of Number", "ArrayModels toString for basic elements")
246
+ assert.equal(ArrayModel([String, 42]).toString(), "Array of String or 42", "ArrayModels toString for union type elements")
247
+ })
248
+
249
+ QUnit.test("Dynamic definition", function (assert) {
250
+ let A = ArrayModel(String);
251
+ let a1 = A(["hello", "world"])
252
+ A.definition = Number;
253
+ let a2 = A([1, 2, 3])
254
+ assert.equal(A.test(a1), false, "definition can be dynamically changed 1/4")
255
+ assert.equal(A.test(a2), true, "definition can be dynamically changed 2/4")
256
+ a1.splice(0, a1.length);
257
+ assert.throws(() => a1.push("hello"), /TypeError/, "definition can be dynamically changed 3/4")
258
+ a1.push(42);
259
+ assert.equal(a1[0], 42, "definition can be dynamically changed 4/4")
260
+
261
+ let OM = ObjectModel({ n: Number });
262
+ A.definition = OM;
263
+ a1.splice(0, a1.length);
264
+ a1.push({ n: 42 });
265
+ assert.ok(a1[0] instanceof OM, "autocast still works after definition dynamically changed")
266
+ })
267
+
268
+ QUnit.test("delete key", function (assert) {
269
+ let A = ArrayModel([Number]);
270
+ let a = A([1, 2, 3])
271
+ delete a[2]
272
+ assert.equal(3 in a, false, "delete should remove own array key")
273
+ assert.equal(a.length, 3, "delete should not update length")
274
+ assert.equal(Object.keys(a).length, 2, "delete should leave an empty hole")
275
+
276
+ const ArrayDense = ArrayModel([Number]).assert(function hasNoHoles(arr) {
277
+ return arr.filter(() => true).length === arr.length
278
+ }).as("ArrayDense");
279
+
280
+ A = ArrayDense.extend([Number]);
281
+ a = A([4, 5, 6])
282
+ assert.throws(() => {
283
+ delete a[2]
284
+ }, /TypeError.*hasNoHoles/, "ArrayDense should prevent deleting keys")
285
+
286
+ })
287
+
288
+ QUnit.test("Arraymodel as ObjectModel default prop", function (assert) {
289
+ class OM extends ObjectModel({
290
+ a: ArrayModel(Number)
291
+ }).defaultTo({
292
+ a: []
293
+ }) { }
294
+
295
+ let o = new OM();
296
+
297
+ assert.ok(Array.isArray(o.a), "ArrayModel works as ObjectModel default prop")
298
+ o.a.push(1, 2, 3)
299
+ assert.equal(o.a.length, 3, "ArrayModel as ObjectModel default prop can be mutated")
300
+
292
301
  })
@@ -97,6 +97,15 @@ QUnit.test("default values", function (assert) {
97
97
 
98
98
  });
99
99
 
100
+ QUnit.test("validate defaut values provided", function (assert) {
101
+ assert.throws(function () {
102
+ BasicModel(Number).defaultTo()
103
+ }, /TypeError.*expecting Number, got undefined*/, "invalid default value provided: undefined");
104
+ assert.throws(function () {
105
+ BasicModel(String).defaultTo(666)
106
+ }, /TypeError.*expecting String, got Number 666*/, "invalid default value provided: wrong type");
107
+ })
108
+
100
109
  QUnit.test("Assertions", function (assert) {
101
110
 
102
111
  function isOdd(n) {
@@ -155,6 +155,18 @@ QUnit.test("default values", function (assert) {
155
155
 
156
156
  })
157
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
+
158
170
  QUnit.test("assertions", function (assert) {
159
171
 
160
172
  const MapMax3 = MapModel(Number, String).assert(function maxEntries(map) {
@@ -148,6 +148,15 @@ QUnit.test("defaults values", function (assert) {
148
148
 
149
149
  })
150
150
 
151
+ QUnit.test("validate defaut values provided", function (assert) {
152
+ assert.throws(function () {
153
+ SetModel(Number).defaultTo()
154
+ }, /TypeError.*expecting Set of Number, got undefined*/, "invalid default value provided: undefined");
155
+ assert.throws(function () {
156
+ SetModel(Number).defaultTo(new Set(["foo", "bar"]))
157
+ }, /TypeError.*expecting Set value to be Number, got String \"foo\"*/, "invalid default value provided: wrong type");
158
+ })
159
+
151
160
  QUnit.test("assertions", function (assert) {
152
161
 
153
162
  const SetMax3 = SetModel(String).assert(function maxEntries(set) {