1
0
Fork 0
mirror of https://github.com/Reuh/classtoi.git synced 2025-10-27 12:19:31 +00:00
classtoi/test/test.lua

248 lines
8.9 KiB
Lua

-- note: this will test again the classtoi-heavy featureset only
local T = require("knife-test")
-- luacheck: ignore T
T("Given the base class", function(T)
local class = dofile(arg[1] or "../classtoi-heavy.lua")
-- 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)