joii
Version:
Javascript Object Inheritance Implementation
279 lines (208 loc) • 14.2 kB
JavaScript
/* Javascript Object Inheritance Implementation ______ ________
* (c) 2016 <harold@iedema.me> __ / / __ \/ _/ _/
* Licensed under MIT. / // / /_/ // /_/ /
* ------------------------------------------------------ \___/\____/___/__*/
var JOII = require('../../dist/joii').JOII;
/**
* Tests inheritance of instantiated class defintions.
*/
test('ClassBuilder:StaticTest', function(assert) {
var TestClass1 = JOII.ClassBuilder("TestClass1", {}, function (TestClass1) { return {
'private static number static_private_num' : 1,
'protected static number static_protected_num' : 1,
'public static number static_num' : 1,
'public number instance_num' : 1,
'public static function test' : function() {
TestClass1.static_num = 2;
this.instance_num = 3; // doesn't actually exist in the static scope
return true;
},
'public function test' : function() {
this.static_num = 4; // doesn't actually exist in the instance scope
this.instance_num = 5;
return false;
},
'public function test2' : function() {
TestClass1.static_num = 6;
return true;
},
'public function test3' : function() {
TestClass1.static_num = 7;
return true;
},
'public static function testGet()' : function() {
return TestClass1.getStaticProtectedNum();
}
}});
var a1 = new TestClass1();
// try setting static members from within a static function
assert.strictEqual(TestClass1.getStaticNum(), 1, "TestClass1.getStaticNum() == 1");
assert.strictEqual(TestClass1.test(), true, "Static function TestClass1.test() called successfully");
assert.strictEqual(TestClass1.getStaticNum(), 2, "TestClass1.getStaticNum() == 2");
//verify initial instance member value - TestClass1.test() attempted to change it using "this" from within a static function (shouldn't have worked)
assert.strictEqual(a1.getInstanceNum(), 1, "a1.getInstanceNum() == 1");
assert.strictEqual(a1.test(), false, "Instance function a1.test() called successfully");
assert.strictEqual(a1.getInstanceNum(), 5, "a1.getInstanceNum() == 5");
assert.strictEqual(TestClass1.getStaticNum(), 2, "TestClass1.getStaticNum() == 2");
assert.strictEqual(a1.test2(), true, "a1.test2() == true");
assert.strictEqual(TestClass1.getStaticNum(), 6, "TestClass1.getStaticNum() == 6");
assert.strictEqual(a1.test3(), true, "a1.test2() == true");
assert.strictEqual(TestClass1.getStaticNum(), 7, "TestClass1.getStaticNum() == 7");
assert.strictEqual(TestClass1.testGet(), 1, "TestClass1.testGet() == 1");
var TestClass2 = JOII.ClassBuilder("TestClass2", {'extends': TestClass1}, function (TestClass2) { return {
'public static immutable string static_str' : 'test',
'public static function test(string)' : function(str) {
TestClass2.static_str = str;
},
'public static function test(number)' : function(num) {
TestClass2.setStaticProtectedNum(num);
}
}});
var a2 = new TestClass2();
// try setting static members from within a static function (inherited). Should be affecting the member in TestClass1.
assert.strictEqual(TestClass2.getStaticNum(), 7, "TestClass2.getStaticNum() == 7");
assert.strictEqual(TestClass2.test(), true, "Static function TestClass2.test() called successfully");
assert.strictEqual(TestClass2.getStaticNum(), 2, "TestClass2.getStaticNum() == 2");
assert.strictEqual(TestClass1.getStaticNum(), 2, "TestClass1.getStaticNum() == 2");
//verify initial instance member value - TestClass2.test() attempted to change it using "this" from within a static function (shouldn't have worked)
assert.strictEqual(a2.getInstanceNum(), 1, "a2.getInstanceNum() == 1");
assert.strictEqual(a2.test(), false, "Instance function a2.test() called successfully");
assert.strictEqual(a2.getInstanceNum(), 5, "a2.getInstanceNum() == 5");
assert.strictEqual(TestClass2.getStaticNum(), 2, "TestClass2.getStaticNum() == 2");
assert.strictEqual(TestClass1.getStaticNum(), 2, "TestClass1.getStaticNum() == 2");
assert.strictEqual(a2.test2(), true, "a2.test2() == true");
assert.strictEqual(TestClass2.getStaticNum(), 6, "TestClass2.getStaticNum() == 6");
assert.strictEqual(TestClass1.getStaticNum(), 6, "TestClass1.getStaticNum() == 6");
assert.strictEqual(a2.test3(), true, "a2.test2() == true");
assert.strictEqual(TestClass2.getStaticNum(), 7, "TestClass2.getStaticNum() == 7");
assert.strictEqual(TestClass1.getStaticNum(), 7, "TestClass1.getStaticNum() == 7");
TestClass2.setStaticNum(8);
assert.strictEqual(TestClass2.getStaticNum(), 8, "TestClass2.getStaticNum() == 8");
assert.strictEqual(TestClass1.getStaticNum(), 8, "TestClass1.getStaticNum() == 8");
assert.strictEqual(TestClass2.testGet(), 1, "TestClass2.testGet() == 1");
TestClass2.test(2);
assert.strictEqual(TestClass1.testGet(), 2, "TestClass1.testGet() == 2");
assert.strictEqual(TestClass2.testGet(), 2, "TestClass2.testGet() == 2");
assert.throws(function() {
TestClass2.setStaticProtectedNum(2);
}, function(err) { return err.message === 'TestClass2.setStaticProtectedNum is not a function'; }, 'Validate: Static protected visibility.');
assert.throws(function() {
TestClass2.setStaticStr('new test');
}, function(err) { return err.message === 'TestClass2.setStaticStr is not a function'; }, 'Validate: Static immutable.');
assert.strictEqual(TestClass2.getStaticStr(), 'test', "TestClass2.getStaticStr() == 'test'");
assert.throws(function() {
TestClass1.getStaticStr();
}, function(err) { return err.message === 'TestClass1.getStaticStr is not a function'; }, 'Validate: TestClass1.getStaticStr doesn\'t exist');
var TestClass3 = JOII.ClassBuilder("TestClass3", {'extends': TestClass2}, function (TestClass3) { return {
}});
// overloaded static method on an inherited class, changing immutable static member
TestClass3.test('new test');
assert.throws(function() {
TestClass3.setStaticStr('newer test');
}, function(err) { return err.message === 'TestClass3.setStaticStr is not a function'; }, 'Validate: Static immutable.');
assert.strictEqual(TestClass3.getStaticStr(), 'new test', "TestClass3.getStaticStr() == 'new test'");
assert.strictEqual(TestClass2.getStaticStr(), 'new test', "TestClass2.getStaticStr() == 'new test'");
var a3 = new TestClass3();
// try setting static members from within a static function (inherited). Should be affecting the member in TestClass1.
assert.strictEqual(TestClass3.getStaticNum(), 8, "TestClass3.getStaticNum() == 8");
assert.strictEqual(TestClass3.test(), true, "Static function TestClass3.test() called successfully");
assert.strictEqual(TestClass3.getStaticNum(), 2, "TestClass3.getStaticNum() == 2");
assert.strictEqual(TestClass1.getStaticNum(), 2, "TestClass1.getStaticNum() == 2");
//verify initial instance member value - TestClass3.test() attempted to change it using "this" from within a static function (shouldn't have worked)
assert.strictEqual(a3.getInstanceNum(), 1, "a3.getInstanceNum() == 1");
assert.strictEqual(a3.test(), false, "Instance function a3.test() called successfully");
assert.strictEqual(a3.getInstanceNum(), 5, "a3.getInstanceNum() == 5");
assert.strictEqual(TestClass3.getStaticNum(), 2, "TestClass3.getStaticNum() == 2");
assert.strictEqual(TestClass1.getStaticNum(), 2, "TestClass1.getStaticNum() == 2");
assert.strictEqual(a3.test2(), true, "a3.test2() == true");
assert.strictEqual(TestClass3.getStaticNum(), 6, "TestClass3.getStaticNum() == 6");
assert.strictEqual(TestClass1.getStaticNum(), 6, "TestClass1.getStaticNum() == 6");
assert.strictEqual(a3.test3(), true, "a3.test2() == true");
assert.strictEqual(TestClass3.getStaticNum(), 7, "TestClass3.getStaticNum() == 7");
assert.strictEqual(TestClass1.getStaticNum(), 7, "TestClass1.getStaticNum() == 7");
var TestStaticInterface = JOII.InterfaceBuilder('TestStaticInterface', {
'public nullable string name' : null,
'protected static number age' : null,
'public static function myTest(string)' : function(a) {}
});
assert.throws(function() {
var InterfaceTestClass = JOII.ClassBuilder("InterfaceTestClass", {'implements': TestStaticInterface}, function (InterfaceTestClass) { return {
'public static nullable string name' : null,
'protected static number age' : null,
'public static function myTest(string)' : function(a) {}
}});
}, function(err) { return err === 'Class must implement public nullable string "name" as defined in the interface TestStaticInterface.'; }, 'Validate: Implementation must match non-static descriptor.');
assert.throws(function() {
var InterfaceTestClass = JOII.ClassBuilder("InterfaceTestClass", {'implements': TestStaticInterface}, function (InterfaceTestClass) { return {
'public nullable string name' : null,
'protected number age' : null,
'public static function myTest(string)' : function(a) {}
}});
}, function(err) { return err === 'Class must implement protected static number "age" as defined in the interface TestStaticInterface.'; }, 'Validate: Property implementation must match static descriptor.');
assert.throws(function() {
var InterfaceTestClass = JOII.ClassBuilder("InterfaceTestClass", {'implements': TestStaticInterface}, function (InterfaceTestClass) { return {
'public nullable string name' : null,
'protected static number age' : null,
'public function myTest(string)' : function(a) {}
}});
}, function(err) { return err === 'Class must implement public static function "myTest" as defined in the interface TestStaticInterface.'; }, 'Validate: Method implementation must match static descriptor.');
assert.throws(function() {
var InterfaceTestClass = JOII.ClassBuilder("InterfaceTestClass", {'implements': TestStaticInterface}, function (InterfaceTestClass) { return {
'public nullable string name' : null,
'protected static number age' : null,
'public static function myTest(number)' : function(a) {}
}});
}, function(err) { return err === 'Method myTest does not match the parameter types as defined in the interface TestStaticInterface.'; }, 'Validate: Method implementation must match static descriptor and parameter types.');
// shouldn't throw anything
var InterfaceTestClass = JOII.ClassBuilder("InterfaceTestClass", {'implements': TestStaticInterface}, function (InterfaceTestClass) { return {
'public nullable string name' : null,
'protected static number age' : null,
'public static function myTest(string)' : function(a) {}
}});
assert.throws(function() {
var StaticTestClass = JOII.ClassBuilder("StaticTestClass", {'static': true}, function (StaticTestClass) { return {
'public string name' : null
}});
}, function(err) { return err === "Member name is non-static. A static class cannot contain non-static members."; }, 'Validate: Static class must contain only static members.');
var StaticTestClass = JOII.ClassBuilder("StaticTestClass", {'static': true}, function (StaticTestClass) { return {
'public static string person' : 'bob'
}});
assert.throws(function() {
var newTest = new StaticTestClass();
}, function(err) { return err === "A static class cannot be instantiated."; }, 'Validate: Static classes cannot be instantiated.');
assert.strictEqual(StaticTestClass.getPerson(), 'bob', "StaticTestClass.getPerson() == 'bob'");
StaticTestClass.setPerson('joe')
assert.strictEqual(StaticTestClass.getPerson(), 'joe', "StaticTestClass.getPerson() == 'joe'");
var TestClass4 = JOII.ClassBuilder("TestClass4", {}, function (TestClass4) { return {
'public static TestClass4 instance' : null,
'protected number num' : 1,
'public static function construct' : function() {
TestClass4.instance = new TestClass4();
},
'public static function test()' : function() {
return false;
},
'public function test()' : function() {
return true;
},
'__call(string)' : function(str) {
return "Success: " + str;
},
'__call(number)' : function(num) {
return num * 2;
},
'public static function test(number)' : function(num) {
return TestClass4(num);
},
'public static function test(string)' : function(str) {
return TestClass4(str);
}
}});
assert.strictEqual(TestClass4.getInstance().test(), true, "TestClass4.getInstance().test() == true");
assert.throws(function() {
TestClass4.getInstance().getNum();
}, function(err) { return err.message === "TestClass4.getInstance(...).getNum is not a function"; }, 'Validate: In class self instantiate returned outer scope.');
assert.strictEqual(TestClass4.getInstance().test(), true, "TestClass4.getInstance().test() == true");
assert.strictEqual(TestClass4.test("testing"), "Success: testing", "Testing in-class _call");
assert.strictEqual(TestClass4.test(4), 8, "Testing in-class _call overload");
});