1 | /* Javascript Object Inheritance Implementation ______ ________ |
||
2 | * (c) 2016 <[email protected]> __ / / __ \/ _/ _/ |
||
3 | * Licensed under MIT. / // / /_/ // /_/ / |
||
4 | * ------------------------------------------------------ \___/\____/___/__*/ |
||
5 | var JOII = require('../../dist/joii').JOII; |
||
6 | |||
7 | /** |
||
8 | * Tests function overloading |
||
9 | */ |
||
10 | test('ClassBuilder:FunctionOverloadingTests', function(assert) { |
||
11 | |||
12 | try { |
||
0 ignored issues
–
show
|
|||
13 | // *************************** |
||
14 | // Abstract tests |
||
15 | // *************************** |
||
16 | |||
17 | // An abstract property must also have a functional one in the same class. |
||
18 | assert.throws(function() { |
||
19 | var a = JOII.ClassBuilder({}, { |
||
20 | 'abstract public function test(string)': function() { } |
||
21 | }); new a(); |
||
22 | }, function(err) { return err === 'Missing abstract member implementation of test(string)'; }, 'Validate: Missing implementation of abstract properties.'); |
||
23 | |||
24 | // An abstract property must be implemented by a child class. |
||
25 | assert.throws(function() { |
||
26 | var a = JOII.ClassBuilder({}, { 'abstract public function test(string)': function() { } }); |
||
27 | var b = JOII.ClassBuilder({ 'extends': a }, {}); new b(); |
||
28 | }, function(err) { return err === 'Missing abstract member implementation of test(string)'; }, 'Validate: Missing implementation of abstract properties.'); |
||
29 | |||
30 | // A final property cannot be implemented by a child class. |
||
31 | assert.throws(function() { |
||
32 | var a = JOII.ClassBuilder({}, { |
||
33 | 'final public function test(string)': function() { }, |
||
34 | 'public function test(string, num)': function() { } |
||
35 | }); |
||
36 | var b = JOII.ClassBuilder({ 'extends': a }, { 'public function test(string)': function() { } }); new b(); |
||
37 | }, function(err) { return err === 'Final member "test(string)" cannot be overwritten.'; }, 'Validate: Missing implementation of abstract properties.'); |
||
38 | |||
39 | // A final property cannot be implemented by a child class. |
||
40 | assert.throws(function() { |
||
41 | var a = JOII.ClassBuilder({}, { |
||
42 | 'final public function test(string)': function() { }, |
||
43 | 'final public function test(string, num)': function() { } |
||
44 | }); |
||
45 | var b = JOII.ClassBuilder({ 'extends': a }, { 'final public function test(string)': function() { } }); new b(); |
||
46 | }, function(err) { return err === 'Final member "test(string)" cannot be overwritten.'; }, 'Validate: Missing implementation of abstract properties.'); |
||
47 | |||
48 | // This shouldn't throw an error |
||
49 | var a = JOII.ClassBuilder({}, { |
||
50 | 'public function test(string)': function() { }, |
||
51 | 'final public function test(string, num)': function() { } |
||
52 | }); |
||
53 | var b = JOII.ClassBuilder({ 'extends': a }, { 'final public function test(string)': function() { } }); |
||
54 | new b(); |
||
55 | |||
56 | // This shouldn't throw an error |
||
57 | var a = JOII.ClassBuilder({}, { |
||
0 ignored issues
–
show
|
|||
58 | 'abstract public function test(string)': function() { }, |
||
59 | 'public function test(string, num)': function() { } |
||
60 | }); |
||
61 | var b = JOII.ClassBuilder({ 'extends': a }, { 'final public function test(string)': function() { } }); |
||
0 ignored issues
–
show
|
|||
62 | new b(); |
||
63 | |||
64 | // This shouldn't throw an error |
||
65 | var a = JOII.ClassBuilder({}, { |
||
0 ignored issues
–
show
|
|||
66 | 'abstract public function test(string)': function() { }, |
||
67 | 'final public function test(string, num)': function() { } |
||
68 | }); |
||
69 | var b = JOII.ClassBuilder({ 'extends': a }, { 'public function test(string)': function() { } }); |
||
0 ignored issues
–
show
|
|||
70 | new b(); |
||
71 | |||
72 | |||
73 | // An abstract property must be implemented by a child class. |
||
74 | assert.throws(function() { |
||
75 | var a = JOII.ClassBuilder({}, { |
||
76 | 'abstract public function test(number)': function() { }, |
||
77 | 'abstract public function test(string)': function() { } |
||
78 | }); |
||
79 | var b = JOII.ClassBuilder({ 'extends': a }, { |
||
80 | 'public function test(string)': function() { } |
||
81 | }); new b(); |
||
82 | }, function(err) { return err === 'Missing abstract member implementation of test(number)'; }, 'Validate: Missing implementation of abstract properties.'); |
||
83 | |||
84 | // An abstract property must be implemented by a child class. |
||
85 | assert.throws(function() { |
||
86 | var a = JOII.ClassBuilder({}, { |
||
87 | 'abstract public function test(number)': function() { }, |
||
88 | 'abstract public function test(string)': function() { } |
||
89 | }); |
||
90 | var b = JOII.ClassBuilder({ 'extends': a }, { |
||
91 | 'public function test(number)': function() { } |
||
92 | }); new b(); |
||
93 | }, function(err) { return err === 'Missing abstract member implementation of test(string)'; }, 'Validate: Missing implementation of abstract properties (different order).'); |
||
94 | |||
95 | // Visibility of an abstract property may not change. |
||
96 | assert.throws(function() { |
||
97 | var a = JOII.ClassBuilder({}, { 'abstract public function test(string)': function() { } }); |
||
98 | var b = JOII.ClassBuilder({ 'extends': a }, { 'protected function test(string)': function() { } }); new b(); |
||
99 | }, function(err) { return err === 'Member "test" must be public as defined in the parent class.'; }, 'Validate: Visibility change of abstract implementation.'); |
||
100 | |||
101 | // This should _not_ throw an exception. |
||
102 | var a = JOII.ClassBuilder({}, { |
||
0 ignored issues
–
show
|
|||
103 | 'abstract public function test(number)': function() { }, |
||
104 | 'abstract public function test(string)': function() { } |
||
105 | }); |
||
106 | var b = JOII.ClassBuilder({ 'extends': a }, { |
||
0 ignored issues
–
show
|
|||
107 | 'public function test(number)': function() { }, |
||
108 | 'public function test(string)': function() { } |
||
109 | }); |
||
110 | new b(); |
||
111 | |||
112 | // Defining an abstract and functional property in the same class is valid. (beware of declaration order) |
||
113 | var c = JOII.ClassBuilder({}, { |
||
114 | 'abstract public function test(string)': function() { }, |
||
115 | 'public function test(string)': function() { } |
||
116 | }); |
||
117 | new c(); |
||
118 | |||
119 | // Implement abstract property in the middle of the inheritance chain. |
||
120 | var c1 = JOII.ClassBuilder({}, { 'abstract public function test(string)': function() { } }); |
||
121 | var c2 = JOII.ClassBuilder({ 'extends': c1 }, {}); |
||
122 | var c3 = JOII.ClassBuilder({ 'extends': c2 }, { 'public function test(string)': function() { } }); |
||
123 | var c4 = JOII.ClassBuilder({ 'extends': c3 }, {}); |
||
124 | |||
125 | // Should not throw exception for missing an abstract implementation. |
||
126 | new c4(); |
||
127 | |||
128 | |||
129 | // *************************** |
||
130 | // Call tests |
||
131 | // *************************** |
||
132 | |||
133 | var C1 = JOII.ClassBuilder({ |
||
134 | '__call(number)': function(p) { return 1 + p; }, |
||
135 | '__call(string)': function(p) { return p + " passed"; } |
||
136 | }); |
||
137 | assert.strictEqual(C1(1), 2, '__call number overload function OK.'); |
||
138 | assert.strictEqual(C1("test"), "test passed", '__call string overload function OK.'); |
||
139 | |||
140 | // __call may not return "this", because it references to the static |
||
141 | // definition of the class body. |
||
142 | assert.throws(function() { |
||
143 | var a = JOII.ClassBuilder({ 'public function foo': function() { }, '__call(number)': function() { return this; } }); a(1); |
||
144 | }, function(err) { return err === '__call cannot return itself.'; }, '__call cannot return itself.'); |
||
145 | |||
146 | // Test the context of a static call. |
||
147 | var C2 = JOII.ClassBuilder({ |
||
148 | a: 1, |
||
149 | b: "test", |
||
150 | |||
151 | '__call(number)': function(val) { |
||
152 | this.a = val; |
||
153 | }, |
||
154 | '__call(string)': function(val) { |
||
155 | this.b = val; |
||
156 | } |
||
0 ignored issues
–
show
|
|||
157 | , |
||
0 ignored issues
–
show
|
|||
158 | '__call()': function() { |
||
159 | return this.a; |
||
160 | } |
||
161 | }); |
||
162 | |||
163 | var c2 = new C2(); |
||
0 ignored issues
–
show
|
|||
164 | assert.strictEqual(c2.getA(), 1, 'c2.getA() returns this.a (1)'); |
||
165 | assert.strictEqual(c2.getB(), "test", 'c2.getB() returns this.b ("test")'); |
||
166 | assert.strictEqual(C2(), 1, '__call returns this.a (1)'); |
||
167 | |||
168 | |||
169 | // Update the value, THEN create another instance and check again... |
||
170 | C2(2); |
||
171 | C2("test again"); |
||
172 | var c2a = new C2(); |
||
173 | assert.strictEqual(C2(), 2, '__call returns this.a (2)'); |
||
174 | assert.strictEqual(c2.getA(), 1, 'c2.getA() returns this.a (1)'); |
||
175 | assert.strictEqual(c2a.getA(), 1, 'c2a.getA() returns this.a (1)'); |
||
176 | assert.strictEqual(c2.getB(), "test", 'c2.getB() returns this.b ("test")'); |
||
177 | assert.strictEqual(c2a.getB(), "test", 'c2a.getB() returns this.b ("test")'); |
||
178 | |||
179 | |||
180 | // 3.1.0: Custom callable method names. |
||
181 | |||
182 | var C3 = Class({ |
||
183 | '<>(number)': function(val) { return val + 1; }, |
||
184 | '<>(string)': function(val) { return val + " passed"; } |
||
185 | }); |
||
186 | assert.strictEqual(C3(4), 5, 'New default call number overload method "<>" used.'); |
||
187 | assert.strictEqual(C3("test"), "test passed", 'New default call string overload method "<>" used.'); |
||
188 | |||
189 | JOII.Config.addCallable('execute'); |
||
190 | var C4 = Class({ |
||
191 | 'execute(number)': function(val) { return val + 1; }, |
||
192 | 'execute(string)': function(val) { return val + " passed"; } |
||
193 | }); |
||
194 | assert.strictEqual(C4(4), 5, 'Custom call number overload method "execute" used.'); |
||
195 | assert.strictEqual(C4("test"), "test passed", 'Custom call string overload method "execute" used.'); |
||
196 | JOII.Config.removeCallable('execute'); |
||
197 | |||
198 | |||
199 | |||
200 | // *************************** |
||
201 | // General overloading tests |
||
202 | // *************************** |
||
203 | |||
204 | |||
205 | |||
206 | var UniqueTestClass = JOII.ClassBuilder('UniqueTestClass', { |
||
207 | x: 6, |
||
208 | y: "something else" |
||
209 | }); |
||
210 | |||
211 | var SuperClass = JOII.ClassBuilder('SuperClass', { |
||
212 | a: 1, |
||
213 | b: "test", |
||
214 | |||
215 | 'test(number)': function(val) { |
||
216 | this.a = val; |
||
217 | }, |
||
218 | 'test(string)': function(val) { |
||
219 | this.b = val; |
||
220 | }, |
||
221 | 'test(UniqueTestClass)': function(val) { |
||
222 | this.a = val.getX(); |
||
223 | this.b = val.getY(); |
||
224 | }, |
||
225 | 'test(object)': function(val) { |
||
226 | if ('a' in val) { |
||
227 | this.a = val.a; |
||
228 | } |
||
229 | if ('b' in val) { |
||
230 | this.b = val.b; |
||
231 | } |
||
232 | } |
||
233 | }); |
||
234 | |||
235 | var sc = new SuperClass(); |
||
236 | |||
237 | sc.test(2); |
||
238 | assert.strictEqual(sc.getA(), 2, 'sc.getA() returns this.a (2)'); |
||
239 | |||
240 | sc.test("success"); |
||
241 | assert.strictEqual(sc.getB(), "success", 'sc.getB() returns this.b ("success")'); |
||
242 | |||
243 | sc.test({ a: 5, b: "passed" }); |
||
244 | assert.strictEqual(sc.getA(), 5, 'sc.getA() returns this.a (5)'); |
||
245 | assert.strictEqual(sc.getB(), "passed", 'sc.getB() returns this.b ("passed")'); |
||
246 | |||
247 | |||
248 | var testClass = new UniqueTestClass(); |
||
249 | sc.test(testClass); |
||
250 | assert.strictEqual(sc.getA(), 6, 'sc.getA() returns this.a (6)'); |
||
251 | assert.strictEqual(sc.getB(), "something else", 'sc.getB() returns this.b ("something else")'); |
||
252 | |||
253 | |||
254 | var SubClass1 = JOII.ClassBuilder('SubClass1', { 'extends': SuperClass }, { |
||
255 | 'test(number)': function(val) { |
||
256 | this.a = val * 2; |
||
257 | }, |
||
258 | 'test(number, string)': function(num, str) { |
||
259 | this.a = num * 4; |
||
260 | this.b = str + " passed"; |
||
261 | }, |
||
262 | 'test(string, number)': function(str, num) { |
||
263 | this.test(num); |
||
264 | this.test(str); |
||
265 | } |
||
266 | }); |
||
267 | |||
268 | |||
269 | var subc = new SubClass1(); |
||
270 | |||
271 | // first, test the methods that were inherited and not overridden |
||
272 | subc.test("success"); |
||
273 | assert.strictEqual(subc.getB(), "success", 'subc.getB() returns this.b ("success")'); |
||
274 | |||
275 | subc.test({ a: 5, b: "passed" }); |
||
276 | assert.strictEqual(subc.getA(), 5, 'subc.getA() returns this.a (5)'); |
||
277 | assert.strictEqual(subc.getB(), "passed", 'subc.getB() returns this.b ("passed")'); |
||
278 | |||
279 | // test override |
||
280 | subc.test(5); |
||
281 | assert.strictEqual(subc.getA(), 10, 'subc.getA() returns this.a (10)'); |
||
282 | |||
283 | // test added overload |
||
284 | subc.test(10, "testing"); |
||
285 | assert.strictEqual(subc.getA(), 40, 'subc.getA() returns this.a (40)'); |
||
286 | assert.strictEqual(subc.getB(), "testing passed", 'subc.getB() returns this.b ("testing passed")'); |
||
287 | |||
288 | // test overload calling different overloads, from different levels of inheritance |
||
289 | subc.test("asdf", 100); |
||
290 | assert.strictEqual(subc.getA(), 200, 'subc.getA() returns this.a (200)'); |
||
291 | assert.strictEqual(subc.getB(), "asdf", 'subc.getB() returns this.b ("asdf")'); |
||
292 | |||
293 | |||
294 | var CustomClass = JOII.ClassBuilder('CustomClass', { |
||
295 | 'SubClass1 custom': null, |
||
296 | 'construct(number)': function(num) { |
||
297 | this.custom = new SubClass1(); |
||
298 | this.custom.test(num); |
||
299 | }, |
||
300 | 'construct(string)': function(str) { |
||
301 | this.custom = new SubClass1(); |
||
302 | this.custom.test(str); |
||
303 | }, |
||
304 | 'construct(number, string)': function(num, str) { |
||
305 | this.custom = new SubClass1(); |
||
306 | this.custom.test(num, str); |
||
307 | }, |
||
308 | 'test(number)': function(num) { |
||
309 | this.custom.test(num); |
||
310 | }, |
||
311 | 'test(string)': function(str) { |
||
312 | this.custom.test(str); |
||
313 | }, |
||
314 | 'test(SubClass1)': function(val) { |
||
315 | this.custom = val; |
||
316 | } |
||
317 | }); |
||
318 | |||
319 | var custom1 = new CustomClass(5); |
||
320 | assert.strictEqual(custom1.getCustom().getA(), 10, 'custom1.getCustom().getA() returns this.custom.a (10)'); |
||
321 | |||
322 | var custom2 = new CustomClass("success"); |
||
323 | assert.strictEqual(custom2.getCustom().getB(), "success", 'custom1.getCustom().getB() returns this.custom.a ("success")'); |
||
324 | |||
325 | |||
326 | subc.test("asdf", 100); |
||
327 | custom2.test(subc); |
||
328 | assert.strictEqual(custom2.getCustom().getA(), 200, 'custom2.getCustom().getA() returns this.custom.a (200)'); |
||
329 | assert.strictEqual(custom2.getCustom().getB(), "asdf", 'custom2.getCustom().getB() returns this.custom.b ("asdf")'); |
||
330 | |||
331 | |||
332 | |||
333 | assert.throws(function() { |
||
334 | custom2.test(1, 2, 3, 4); |
||
335 | }, function(err) { return err === 'Couldn\'t find a function handler to match: test(number, number, number, number).'; }, 'Validate: No matching overload.'); |
||
336 | |||
337 | assert.throws(function() { |
||
338 | var c5 = JOII.ClassBuilder({ |
||
339 | 'construct( number )': function(num) { }, |
||
340 | 'construct(number)': function(num) { } |
||
341 | }); |
||
342 | new c5(); |
||
343 | }, function(err) { return err === 'Member "construct(number)" is defined twice.'; }, 'Validate: Duplicate function overload.'); |
||
344 | |||
345 | assert.throws(function() { |
||
346 | var c6 = JOII.ClassBuilder({ |
||
347 | 'public test(number)': function(num) { }, |
||
348 | 'private test(number)': function(num) { } |
||
349 | }); |
||
350 | new c6(); |
||
351 | }, function(err) { return err === 'Member test: inconsistent visibility.'; }, 'Validate: Consistent visibility of overloads.'); |
||
352 | |||
353 | assert.throws(function() { |
||
354 | var c7 = JOII.ClassBuilder({ |
||
355 | 'test(number)': function(num) { }, |
||
356 | 'test(str)': 'invalid' |
||
357 | }); |
||
358 | new c7(); |
||
359 | }, function(err) { return err === 'Member test specifies parameters, but it\'s value isn\'t a function.'; }, 'Validate: Function body.'); |
||
360 | |||
361 | assert.throws(function() { |
||
362 | var c8 = JOII.ClassBuilder({ |
||
363 | 'test(number)': function(num) { }, |
||
364 | 'test': 'invalid' |
||
365 | }); |
||
366 | new c8(); |
||
367 | }, function(err) { return err === 'Member test overloads an existing function, but it\'s value isn\'t a function.'; }, 'Validate: Consistent overloads.'); |
||
368 | |||
369 | assert.throws(function() { |
||
370 | var c9 = JOII.ClassBuilder({ |
||
371 | 'test': 'invalid', |
||
372 | 'test(number)': function(num) { } |
||
373 | }); |
||
374 | new c9(); |
||
375 | }, function(err) { return err === 'Member test overloads an existing property, but the previous property isn\'t a function.'; }, 'Validate: Consistent overloads (reverse order).'); |
||
376 | |||
377 | |||
378 | // *************************** |
||
379 | // Variadic overloading tests |
||
380 | // *************************** |
||
381 | |||
382 | |||
383 | var C10 = JOII.ClassBuilder({ |
||
384 | 'variadic(number)': function(num) { |
||
385 | return "variadic (number): " + num; |
||
386 | }, |
||
387 | 'variadic(number, string)': function(num, str) { |
||
388 | return "variadic (number, string): " + str + ": " + num; |
||
389 | }, |
||
390 | 'variadic(number, ...)': function(num, args) { |
||
391 | return "variadic (number, ...): " + num + ' = ' + args.join(', '); |
||
392 | }, |
||
393 | 'variadic(number, string, ...)': function(num, str, args) { |
||
394 | return "variadic (number, string, ...): " + str + ": " + num + ' = ' + args.join(', '); |
||
395 | } |
||
396 | }); |
||
397 | var c10 = new C10(); |
||
398 | |||
399 | assert.strictEqual(c10.variadic(1), "variadic (number): 1", 'c10.variadic(1) returns variadic (number): 1'); |
||
400 | assert.strictEqual(c10.variadic(1, "Test"), "variadic (number, string): Test: 1", 'c10.variadic(1, "Test") returns variadic (number, string): Test: 1'); |
||
401 | |||
402 | assert.strictEqual(c10.variadic(1, 2), "variadic (number, ...): 1 = 2", 'c10.variadic(1, 2) returns "variadic (number, ...): 1 = 2"'); |
||
403 | assert.strictEqual(c10.variadic(1, 2, "asdf"), "variadic (number, ...): 1 = 2, asdf", 'c10.variadic(1, 2, "asdf") returns "variadic (number, ...): 1 = 2, asdf"'); |
||
404 | assert.strictEqual(c10.variadic(1, "asdf", 2, 3), "variadic (number, string, ...): asdf: 1 = 2, 3", 'c10.variadic(1, "asdf", 2, 3) returns "variadic (number, string, ...): asdf: 1 = 2, 3"'); |
||
405 | |||
406 | |||
407 | assert.throws(function() { |
||
408 | var c11 = JOII.ClassBuilder({ |
||
409 | 'variadic(string, ..., string)': function(num, str, args) { } |
||
410 | }); |
||
411 | new c11(); |
||
412 | }, function(err) { return err === 'Member variadic: Variadic parameter (...) must be the last in the function parameter list.'; }, 'Validate: Variadic last function parameter.'); |
||
413 | |||
414 | |||
415 | |||
416 | |||
417 | |||
418 | |||
419 | |||
420 | var ValueClass = Class('ValueClass', { |
||
421 | id: 6, |
||
422 | value: "", |
||
423 | 'construct()': function() { }, |
||
424 | 'construct(number, string)': function(id, val) { |
||
425 | this.id = id; |
||
426 | this.value = val; |
||
427 | }, |
||
428 | 'construct(ValueClass)': function(vc) { |
||
429 | this.id = vc.id; |
||
430 | this.value = vc.value; |
||
431 | }, |
||
432 | }); |
||
433 | |||
434 | var LookupClass = Class('LookupClass', { |
||
435 | 'private object table': [], |
||
436 | |||
437 | // lookup a value object by id |
||
438 | 'get(number)': function(num) { |
||
439 | for (var i in this.table) { |
||
440 | var val = this.table[i]; |
||
441 | if (val.getId() == num) { |
||
442 | return val; |
||
443 | } |
||
444 | } |
||
445 | }, |
||
446 | |||
447 | // overload the get function to lookup a value object by it's value |
||
448 | 'get(string)': function(str) { |
||
449 | for (var i in this.table) { |
||
450 | var val = this.table[i]; |
||
451 | if (val.getValue() == str) { |
||
452 | return val; |
||
453 | } |
||
454 | } |
||
455 | }, |
||
456 | |||
457 | // add a new value, by providing a ValueClass object |
||
458 | 'add(ValueClass)': function(vc) { |
||
459 | this.table.push(vc); |
||
460 | }, |
||
461 | |||
462 | // add a new value, by providing an numeric id and string value |
||
463 | 'add(number, string)': function(id, val) { |
||
464 | var vc = new ValueClass(); |
||
465 | vc.setId(id); |
||
466 | vc.setValue(val); |
||
467 | |||
468 | // call the add function above with our new ValueClass object |
||
469 | this.add(vc); |
||
470 | }, |
||
471 | |||
472 | // add a new value, by providing an anonymous object containing the id and value |
||
473 | 'add(object)': function(obj) { |
||
474 | if ('id' in obj && 'value' in obj) { |
||
475 | var vc = new ValueClass(); |
||
476 | vc.setId(obj.id); |
||
477 | vc.setValue(obj.value); |
||
478 | |||
479 | // call the add function above with our new ValueClass object |
||
480 | this.add(vc); |
||
481 | } |
||
482 | }, |
||
483 | |||
484 | // add several new values at the same time |
||
485 | 'add(...)': function(args) { |
||
486 | for (var i in args) { |
||
487 | var val = args[i]; |
||
488 | this.add(val); |
||
489 | } |
||
490 | } |
||
491 | }); |
||
492 | |||
493 | |||
494 | |||
495 | |||
496 | |||
497 | var table = new LookupClass(); |
||
498 | |||
499 | var value1 = new ValueClass(1, 'bob'); |
||
500 | |||
501 | // add an instance of ValueClass |
||
502 | table.add(value1); |
||
503 | |||
504 | // add with a number and string |
||
505 | table.add(2, 'joe'); |
||
506 | |||
507 | // add an anonymous object |
||
508 | table.add({ |
||
509 | id: 3, |
||
510 | value: 'sam' |
||
511 | }); |
||
512 | |||
513 | // create a few different objects |
||
514 | var value2 = new ValueClass(4, 'george'); |
||
515 | var value3 = new ValueClass(7, 'bill'); |
||
516 | |||
517 | var obj1 = { |
||
518 | id: 5, |
||
519 | value: 'jenny' |
||
520 | }; |
||
521 | |||
522 | var obj2 = { |
||
523 | id: 6, |
||
524 | value: 'laura' |
||
525 | }; |
||
526 | |||
527 | |||
528 | // add several things at once |
||
529 | table.add(value2, obj1, obj2, value3); |
||
530 | |||
531 | |||
532 | assert.strictEqual(table.get(5).getValue(), "jenny", 'Verify: table.get(5).getValue() == "jenny"'); |
||
533 | assert.strictEqual(table.get(2).getValue(), "joe", 'Verify: table.get(2).getValue() == "joe"'); |
||
534 | assert.strictEqual(table.get("sam").getId(), 3, 'Verify: table.get("sam").getId() == 3'); |
||
535 | assert.strictEqual(table.get("laura").getId(), 6, 'Verify: table.get("laura").getId() == 6'); |
||
536 | assert.strictEqual(table.get(4).getValue(), "george", 'Verify: table.get(4).getValue() == "george"'); |
||
537 | |||
538 | |||
539 | |||
540 | |||
541 | |||
542 | var IMyInterface = Interface('IMyInterface', { |
||
543 | // Interface body ... |
||
544 | }); |
||
545 | |||
546 | var RandomClass = Class('RandomClass', { implements: IMyInterface }, {}); |
||
547 | |||
548 | var MyClass2 = Class('MyClass2', { |
||
549 | |||
550 | // anything which implements IMyInterface will be passed here |
||
551 | 'test(IMyInterface)': function(val) { |
||
552 | return 1; |
||
553 | }, |
||
554 | |||
555 | // RandomClass implements IMyInterface, so the above method will always match it. |
||
556 | // This method will NEVER be called |
||
557 | 'test(RandomClass)': function(val) { |
||
558 | return 2; |
||
559 | } |
||
560 | }); |
||
561 | |||
562 | var mc = new MyClass2(); |
||
563 | var rc = new RandomClass(); |
||
564 | |||
565 | assert.strictEqual(mc.test(rc), 1, 'Verify: Overloads order of operations with parent matching'); |
||
566 | |||
567 | var MyClass3 = Class('MyClass3', { |
||
568 | |||
569 | // ALL JOII classes ultimately inherit from object, |
||
570 | // so this will override ALL other one parameter methods if placed above them |
||
571 | // unless they're other native types (such as string) |
||
572 | 'test(object)': function(val) { |
||
573 | return 3; |
||
574 | }, |
||
575 | |||
576 | // RandomClass is an object, so the above method will always match it. |
||
577 | // This method will NEVER be called |
||
578 | 'test(RandomClass)': function(val) { |
||
579 | return 4; |
||
580 | }, |
||
581 | |||
582 | // This method WILL be called, because it has an extra parameter to match against |
||
583 | 'test(RandomClass, string)': function(val, str) { |
||
584 | return 5; |
||
585 | } |
||
586 | }); |
||
587 | |||
588 | var mc = new MyClass3(); |
||
0 ignored issues
–
show
|
|||
589 | |||
590 | assert.strictEqual(mc.test(rc), 3, 'Verify: Overloads order of operations with parent matching'); |
||
591 | assert.strictEqual(mc.test(rc, "test"), 5, 'Verify: Overloads order of operations with parent matching'); |
||
592 | |||
593 | } |
||
594 | catch (e) { |
||
595 | QUnit.pushFailure(e); |
||
596 | } |
||
597 | |||
598 | }); |
||
599 |
Strict mode is a way to opt-in to a restricted variant of JavaScript. It eliminates some common pitfalls by being less lenient and raising more errors.
Besides, it is also used to fix certain mistakes which made it difficult for JavaScript runtimes to perform certain optimizations.
We generally recommend to only enable strict mode on the function scope and not in the global scope as that might break third-party scripts on your website.