mirror of
https://github.com/Reuh/classtoi.git
synced 2025-10-27 20:29:31 +00:00
Added tests, fixed __index, custom constructor return values, 0.1.4
This commit is contained in:
parent
0214c99cc4
commit
cc53045d4d
4 changed files with 426 additions and 11 deletions
246
test.lua
Normal file
246
test.lua
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
local T = require("knife-test")
|
||||
|
||||
-- luacheck: ignore T
|
||||
T("Given the base class", function(T)
|
||||
local class = require("classtoi")
|
||||
|
||||
-- Inheritance
|
||||
T("When subclassed with an attribute", function(T)
|
||||
local Thing = class {
|
||||
attribute = "thing"
|
||||
}
|
||||
|
||||
T:assert(Thing.attribute == "thing", "Then the attribute should be set on the subclass")
|
||||
T:assert(class.attribute == nil, "Then the attribute shouldn't be set on the base class'")
|
||||
|
||||
T:assert(class.is(Thing), "Then the subclass should be a subclass of the base class (class.is)")
|
||||
T:assert(Thing:is(class), "Then the subclass should be a subclass of the base class (subclass:is)")
|
||||
|
||||
T("When the subclass is instanced", function(T)
|
||||
local thing = Thing:new()
|
||||
|
||||
T:assert(thing.attribute == "thing", "Then the attribute should be kept")
|
||||
|
||||
T:assert(class.is(thing), "Then the object should be a subclass of the base class (class.is(object))")
|
||||
T:assert(thing:is(class), "Then the object should be a subclass of the base class (object:is(class))")
|
||||
T:assert(thing:is(Thing), "Then the object should be a subclass of the subclass (object:is(subclass))")
|
||||
T:assert(Thing.is(thing), "Then the object should be a subclass of the subclass (subclass.is(object))")
|
||||
|
||||
T("When setting the attribute on the instance", function(T)
|
||||
thing.attribute = "not the same thing"
|
||||
|
||||
T:assert(thing.attribute == "not the same thing", "Then the attribute should be set for the object")
|
||||
T:assert(Thing.attribute == "thing", "Then the attribute should be kept for the subclass")
|
||||
end)
|
||||
end)
|
||||
|
||||
T("When the subclassed is subclassed with two parents", function(T)
|
||||
local OtherThing = class {
|
||||
attribute = "other thing",
|
||||
other = true
|
||||
}
|
||||
|
||||
local SubThing = Thing(OtherThing)
|
||||
|
||||
T:assert(SubThing.attribute == "other thing", "Then the last added parent should have priority")
|
||||
|
||||
local SubOtherThing = class(Thing, OtherThing)
|
||||
|
||||
T:assert(SubOtherThing.attribute == "thing", "Then the left-most class should have priority")
|
||||
|
||||
T:assert(SubThing.other and SubOtherThing.other, "Then new attribute should be always inherited")
|
||||
|
||||
T("When adding a method to the first subclass", function(T)
|
||||
Thing.action = function(self, arg)
|
||||
self.attribute = arg
|
||||
end
|
||||
|
||||
T("When calling it on the first subclass", function(T)
|
||||
Thing:action("new thing")
|
||||
|
||||
T:assert(Thing.attribute == "new thing", "Then it affect the first subclass")
|
||||
T:assert(SubOtherThing.attribute == "new thing", "Then it affect children wich inherit the modified attribute")
|
||||
T:assert(SubThing.attribute == "other thing", "Then it doesn't affect children which doesn't inherit the modified attribute")
|
||||
end)
|
||||
|
||||
T("When calling it on another subclass", function(T)
|
||||
SubOtherThing:action("new thing")
|
||||
|
||||
T:assert(Thing.attribute == "thing", "Then it doesn't affect the parent subclass")
|
||||
T:assert(SubOtherThing.attribute == "new thing", "Then it affect the subclass")
|
||||
T:assert(SubThing.attribute == "other thing", "Then it doesn't affect other subclasses")
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
||||
-- Constructor
|
||||
T("When subclassed with a constructor", function(T)
|
||||
local Thing = class {
|
||||
attribute = "class",
|
||||
|
||||
new = function(self, arg)
|
||||
self.attribute = arg or "object"
|
||||
end
|
||||
}
|
||||
|
||||
T:assert(Thing.attribute == "class", "Then the class should not call the constructor itself")
|
||||
|
||||
T("When the subclass is instanced without arguments", function(T)
|
||||
local thing = Thing:new()
|
||||
|
||||
T:assert(thing.attribute == "object", "Then the constructor should have been called on the object without arguments")
|
||||
T:assert(Thing.attribute == "class", "Then the constructor should not be called on the class")
|
||||
end)
|
||||
|
||||
T("When the subclass is instanced without arguments", function(T)
|
||||
local thing = Thing:new("stuff")
|
||||
|
||||
T:assert(thing.attribute == "stuff", "Then the constructor should have been called on the object with arguments")
|
||||
T:assert(Thing.attribute == "class", "Then the constructor should not be called on the class")
|
||||
end)
|
||||
|
||||
T("When the subclass is subclassed and instanced with another constructor", function(T)
|
||||
local SubThing = Thing {
|
||||
new = function(self)
|
||||
self.sub = true
|
||||
Thing.new(self, "a whole new thing")
|
||||
end
|
||||
}
|
||||
|
||||
local subthing = SubThing:new()
|
||||
|
||||
T:assert(subthing.sub, "Then the new constructor is called on the new instance")
|
||||
T:assert(not SubThing.sub, "Then the new constructor is not called on the class")
|
||||
|
||||
T:assert(subthing.attribute == "a whole new thing", "Then the parent new method was correctly accessed and called on the new instance")
|
||||
T:assert(SubThing.attribute == "class", "Then the parent new method was not called on the class")
|
||||
end)
|
||||
end)
|
||||
T("When subclassed with a constructor returning non-nil values and instanced", function(T)
|
||||
local Thing = class {
|
||||
new = function(self, arg)
|
||||
return true, arg
|
||||
end
|
||||
}
|
||||
|
||||
local thing, other = Thing:new("mostly useless but cool")
|
||||
|
||||
T:assert(thing == true and other == "mostly useless but cool", "Then the constructor return value should be returned instead of an object")
|
||||
end)
|
||||
|
||||
-- Usual metamethods
|
||||
T("When subclassed with a metamethod", function(T)
|
||||
local Thing = class {
|
||||
value = 0,
|
||||
__add = function(self, other)
|
||||
self.value = self.value + other
|
||||
return self
|
||||
end
|
||||
}
|
||||
|
||||
T:assert(Thing.value == 0, "Then the attribute is set on the subclass")
|
||||
|
||||
Thing = Thing + 5
|
||||
|
||||
T:assert(Thing.value == 5, "Then the metamethod is correctly called on the subclass")
|
||||
T:assert(class.value == nil, "Then the metamethod doesn't affect the base class")
|
||||
|
||||
T("When the subclass is instancied", function(T)
|
||||
local thing = Thing:new()
|
||||
thing = thing + 5
|
||||
|
||||
T:assert(thing.value == 10, "Then the metamethod is correctly called on the instance")
|
||||
T:assert(Thing.value == 5, "Then the metamethod doesn't affect the parent class")
|
||||
end)
|
||||
end)
|
||||
|
||||
-- Redefining usual special class methods
|
||||
T("When a subclass redefine one of the default class methods", function(T)
|
||||
local Thing = class {
|
||||
is = function(self)
|
||||
return "mashed potatoes"
|
||||
end,
|
||||
|
||||
__call = function(self, arg)
|
||||
return "hot potatoes with "..arg
|
||||
end
|
||||
}
|
||||
|
||||
T:assert(Thing:is(class) == true, "Then defaults methods are still used on the class")
|
||||
T:assert(Thing():is(class) == true, "Then defaults metamethods are still used on the class")
|
||||
|
||||
T("When the subclass is instancied", function(T)
|
||||
local thing = Thing:new()
|
||||
|
||||
T:assert(thing:is(class) == "mashed potatoes", "Then the redefined method is used on the instance")
|
||||
T:assert(thing("melted raclette") == "hot potatoes with melted raclette", "Then the redefined metamethod is used on the instance")
|
||||
end)
|
||||
end)
|
||||
|
||||
-- Redefining __index
|
||||
T("When subclassed with an __index metamethod", function(T)
|
||||
local Thing = class {
|
||||
value = "other",
|
||||
|
||||
__index = function(self, key)
|
||||
if key == "attribute" then
|
||||
return "thing"
|
||||
elseif key == "another" then
|
||||
return self.value
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
T:assert(Thing.attribute == "thing", "Then the metamethod is called as expected")
|
||||
T:assert(Thing.value == "other", "Then attribute access still works as expected")
|
||||
T:assert(Thing.another == "other", "Then the metamethod seems to correctly pass a class as the first argument")
|
||||
|
||||
T("When the subclass is instanced", function(T)
|
||||
local thing = Thing:new()
|
||||
|
||||
T:assert(thing.attribute == "thing", "Then the metamethod is called as expected")
|
||||
T:assert(thing.value == "other", "Then attribute access still works as expected")
|
||||
T:assert(thing.another == "other", "Then the metamethod seems to correctly pass a class as the first argument")
|
||||
|
||||
T("When changing a value returned by the metamethod on the instance", function(T)
|
||||
thing.value = "new thing"
|
||||
|
||||
T:assert(thing.another == "new thing", "Then the metamethod was correctly called with the instance as the first argument")
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
||||
-- Defining __inherit
|
||||
T("When subclassed with an __inherit method", function(T)
|
||||
local Thing = class {
|
||||
attribute = "thing",
|
||||
replace = false,
|
||||
__inherit = function(self, inheritingClass)
|
||||
inheritingClass.works = true
|
||||
if self.replace then
|
||||
return { attribute = "other thing" }
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
T:assert(Thing.works == true, "Then the __inherit method was correctly called on the class creation")
|
||||
|
||||
T("When subclassing the subclass", function(T)
|
||||
Thing.works = "ok"
|
||||
local SubThing = Thing()
|
||||
|
||||
T:assert(SubThing.attribute == "thing", "Then the child class still inherit the subclass")
|
||||
T:assert(SubThing.works == true, "Then the __inherit method was correctly called on the inheriting class")
|
||||
T:assert(Thing.works == "ok", "Then the __inherit method was correctly called on the inherited class")
|
||||
end)
|
||||
|
||||
T("When subclassing the subclass with a return value", function(T)
|
||||
Thing.replace = true
|
||||
local SubThing = Thing()
|
||||
|
||||
T:assert(SubThing.attribute == "other thing", "Then the child class inherited the return value")
|
||||
T:assert(SubThing.works == true, "Then the __inherit method was correctly called on the inheriting class")
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
Loading…
Add table
Add a link
Reference in a new issue