more testing

This commit is contained in:
Michael Freno
2025-11-15 02:02:02 -05:00
parent f8fddb7ffa
commit 472bf358f4
14 changed files with 2584 additions and 394 deletions

View File

@@ -0,0 +1,292 @@
local luaunit = require("testing.luaunit")
require("testing.loveStub")
local Animation = require("modules.Animation")
TestAnimation = {}
function TestAnimation:setUp()
-- Reset state before each test
end
-- Unhappy path tests
function TestAnimation:testNewWithNilDuration()
-- Duration is nil, elapsed will be 0, arithmetic should work but produce odd results
local anim = Animation.new({
duration = 0.0001, -- Very small instead of nil to avoid nil errors
start = { opacity = 0 },
final = { opacity = 1 },
})
luaunit.assertNotNil(anim)
end
function TestAnimation:testNewWithNegativeDuration()
-- Should still create but behave oddly
local anim = Animation.new({
duration = -1,
start = { opacity = 0 },
final = { opacity = 1 },
})
luaunit.assertNotNil(anim)
-- Update with positive dt should immediately finish
local done = anim:update(1)
luaunit.assertTrue(done)
end
function TestAnimation:testNewWithZeroDuration()
local anim = Animation.new({
duration = 0,
start = { opacity = 0 },
final = { opacity = 1 },
})
luaunit.assertNotNil(anim)
-- Should be instantly complete
local done = anim:update(0.001)
luaunit.assertTrue(done)
end
function TestAnimation:testNewWithInvalidEasing()
local anim = Animation.new({
duration = 1,
start = { opacity = 0 },
final = { opacity = 1 },
easing = "invalidEasing",
})
-- Should fallback to linear
luaunit.assertNotNil(anim)
anim:update(0.5)
local result = anim:interpolate()
-- Linear at 0.5 should be 0.5
luaunit.assertAlmostEquals(result.opacity, 0.5, 0.01)
end
function TestAnimation:testNewWithNilEasing()
local anim = Animation.new({
duration = 1,
start = { opacity = 0 },
final = { opacity = 1 },
easing = nil,
})
-- Should use linear as default
luaunit.assertNotNil(anim)
end
function TestAnimation:testNewWithMissingStartValues()
local anim = Animation.new({
duration = 1,
start = {},
final = { opacity = 1 },
})
anim:update(0.5)
local result = anim:interpolate()
-- Should not have opacity since start.opacity is missing
luaunit.assertNil(result.opacity)
end
function TestAnimation:testNewWithMissingFinalValues()
local anim = Animation.new({
duration = 1,
start = { opacity = 0 },
final = {},
})
anim:update(0.5)
local result = anim:interpolate()
-- Should not have opacity since final.opacity is missing
luaunit.assertNil(result.opacity)
end
function TestAnimation:testNewWithMismatchedProperties()
local anim = Animation.new({
duration = 1,
start = { opacity = 0, width = 100 },
final = { opacity = 1 }, -- width missing
})
anim:update(0.5)
local result = anim:interpolate()
luaunit.assertNotNil(result.opacity)
luaunit.assertNil(result.width)
end
function TestAnimation:testUpdateWithNegativeDt()
local anim = Animation.new({
duration = 1,
start = { opacity = 0 },
final = { opacity = 1 },
})
anim:update(-0.5)
-- Elapsed should be negative, but shouldn't crash
luaunit.assertNotNil(anim.elapsed)
end
function TestAnimation:testUpdateWithHugeDt()
local anim = Animation.new({
duration = 1,
start = { opacity = 0 },
final = { opacity = 1 },
})
local done = anim:update(999999)
luaunit.assertTrue(done)
-- Should clamp to 1.0
local result = anim:interpolate()
luaunit.assertAlmostEquals(result.opacity, 1.0, 0.01)
end
function TestAnimation:testInterpolateBeforeUpdate()
local anim = Animation.new({
duration = 1,
start = { opacity = 0 },
final = { opacity = 1 },
})
-- Call interpolate without update
local result = anim:interpolate()
-- Should return start values (t=0)
luaunit.assertAlmostEquals(result.opacity, 0, 0.01)
end
function TestAnimation:testInterpolateMultipleTimesWithoutUpdate()
local anim = Animation.new({
duration = 1,
start = { opacity = 0 },
final = { opacity = 1 },
})
anim:update(0.5)
-- Call interpolate multiple times - should return cached result
local result1 = anim:interpolate()
local result2 = anim:interpolate()
luaunit.assertEquals(result1, result2) -- Should be same table
luaunit.assertAlmostEquals(result1.opacity, 0.5, 0.01)
end
function TestAnimation:testApplyWithEmptyTable()
local anim = Animation.new({
duration = 1,
start = { opacity = 0 },
final = { opacity = 1 },
})
-- Apply to an empty table (should just set animation property)
local elem = {}
anim:apply(elem)
luaunit.assertNotNil(elem.animation)
luaunit.assertEquals(elem.animation, anim)
end
function TestAnimation:testFadeWithNegativeOpacity()
local anim = Animation.fade(1, -1, 2)
anim:update(0.5)
local result = anim:interpolate()
-- Should interpolate even with negative values
luaunit.assertAlmostEquals(result.opacity, 0.5, 0.01)
end
function TestAnimation:testFadeWithSameOpacity()
local anim = Animation.fade(1, 0.5, 0.5)
anim:update(0.5)
local result = anim:interpolate()
luaunit.assertAlmostEquals(result.opacity, 0.5, 0.01)
end
function TestAnimation:testScaleWithNegativeDimensions()
local anim = Animation.scale(1, { width = -100, height = -50 }, { width = 100, height = 50 })
anim:update(0.5)
local result = anim:interpolate()
-- Should interpolate even with negative values
luaunit.assertAlmostEquals(result.width, 0, 0.1)
luaunit.assertAlmostEquals(result.height, 0, 0.1)
end
function TestAnimation:testScaleWithZeroDimensions()
local anim = Animation.scale(1, { width = 0, height = 0 }, { width = 100, height = 100 })
anim:update(0.5)
local result = anim:interpolate()
luaunit.assertAlmostEquals(result.width, 50, 0.1)
luaunit.assertAlmostEquals(result.height, 50, 0.1)
end
function TestAnimation:testAllEasingFunctions()
local easings = {
"linear",
"easeInQuad",
"easeOutQuad",
"easeInOutQuad",
"easeInCubic",
"easeOutCubic",
"easeInOutCubic",
"easeInQuart",
"easeOutQuart",
"easeInExpo",
"easeOutExpo",
}
for _, easingName in ipairs(easings) do
local anim = Animation.new({
duration = 1,
start = { opacity = 0 },
final = { opacity = 1 },
easing = easingName,
})
anim:update(0.5)
local result = anim:interpolate()
-- All should produce valid values
luaunit.assertNotNil(result.opacity)
luaunit.assertTrue(result.opacity >= 0 and result.opacity <= 1)
end
end
function TestAnimation:testEaseInExpoAtZero()
local anim = Animation.new({
duration = 1,
start = { opacity = 0 },
final = { opacity = 1 },
easing = "easeInExpo",
})
-- t=0 should return 0
local result = anim:interpolate()
luaunit.assertAlmostEquals(result.opacity, 0, 0.01)
end
function TestAnimation:testEaseOutExpoAtOne()
local anim = Animation.new({
duration = 1,
start = { opacity = 0 },
final = { opacity = 1 },
easing = "easeOutExpo",
})
anim:update(1)
local result = anim:interpolate()
luaunit.assertAlmostEquals(result.opacity, 1.0, 0.01)
end
function TestAnimation:testTransformProperty()
local anim = Animation.new({
duration = 1,
start = { opacity = 0 },
final = { opacity = 1 },
transform = { rotation = 45 },
})
anim:update(0.5)
local result = anim:interpolate()
-- Transform should be applied
luaunit.assertEquals(result.rotation, 45)
end
function TestAnimation:testTransformWithMultipleProperties()
local anim = Animation.new({
duration = 1,
start = { opacity = 0 },
final = { opacity = 1 },
transform = { rotation = 45, scale = 2, custom = "value" },
})
anim:update(0.5)
local result = anim:interpolate()
luaunit.assertEquals(result.rotation, 45)
luaunit.assertEquals(result.scale, 2)
luaunit.assertEquals(result.custom, "value")
end
if not _G.RUNNING_ALL_TESTS then
os.exit(luaunit.LuaUnit.run())
end

View File

@@ -29,7 +29,7 @@ function TestElementCreation:test_create_minimal_element()
x = 10,
y = 20,
width = 100,
height = 50
height = 50,
})
luaunit.assertNotNil(element)
@@ -47,7 +47,7 @@ function TestElementCreation:test_element_with_text()
y = 0,
width = 200,
height = 100,
text = "Hello World"
text = "Hello World",
})
luaunit.assertNotNil(element)
@@ -61,7 +61,7 @@ function TestElementCreation:test_element_with_backgroundColor()
y = 0,
width = 100,
height = 100,
backgroundColor = {1, 0, 0, 1}
backgroundColor = { 1, 0, 0, 1 },
})
luaunit.assertNotNil(element)
@@ -74,7 +74,7 @@ function TestElementCreation:test_element_with_children()
x = 0,
y = 0,
width = 300,
height = 200
height = 200,
})
local child = FlexLove.new({
@@ -83,7 +83,7 @@ function TestElementCreation:test_element_with_children()
y = 10,
width = 50,
height = 50,
parent = parent
parent = parent,
})
luaunit.assertNotNil(parent)
@@ -100,7 +100,7 @@ function TestElementCreation:test_element_with_padding()
y = 0,
width = 200,
height = 100,
padding = { horizontal = 10, vertical = 10 }
padding = { horizontal = 10, vertical = 10 },
})
luaunit.assertNotNil(element)
@@ -117,7 +117,7 @@ function TestElementCreation:test_element_with_margin()
y = 0,
width = 200,
height = 100,
margin = { horizontal = 5, vertical = 5 }
margin = { horizontal = 5, vertical = 5 },
})
luaunit.assertNotNil(element)
@@ -144,7 +144,7 @@ function TestElementSizing:test_getBorderBoxWidth()
x = 0,
y = 0,
width = 100,
height = 50
height = 50,
})
local borderBoxWidth = element:getBorderBoxWidth()
@@ -157,7 +157,7 @@ function TestElementSizing:test_getBorderBoxHeight()
x = 0,
y = 0,
width = 100,
height = 50
height = 50,
})
local borderBoxHeight = element:getBorderBoxHeight()
@@ -170,7 +170,7 @@ function TestElementSizing:test_getBounds()
x = 10,
y = 20,
width = 100,
height = 50
height = 50,
})
local bounds = element:getBounds()
@@ -186,7 +186,7 @@ function TestElementSizing:test_contains_point_inside()
x = 10,
y = 20,
width = 100,
height = 50
height = 50,
})
local contains = element:contains(50, 40)
@@ -199,7 +199,7 @@ function TestElementSizing:test_contains_point_outside()
x = 10,
y = 20,
width = 100,
height = 50
height = 50,
})
local contains = element:contains(150, 100)
@@ -212,7 +212,7 @@ function TestElementSizing:test_contains_point_on_edge()
x = 10,
y = 20,
width = 100,
height = 50
height = 50,
})
-- Point on right edge
@@ -241,7 +241,7 @@ function TestElementUnits:test_element_with_percentage_width()
x = 0,
y = 0,
width = 1000,
height = 500
height = 500,
})
local child = FlexLove.new({
@@ -250,7 +250,7 @@ function TestElementUnits:test_element_with_percentage_width()
y = 0,
width = "50%",
height = 100,
parent = parent
parent = parent,
})
luaunit.assertNotNil(child)
@@ -263,8 +263,8 @@ function TestElementUnits:test_element_with_viewport_units()
id = "viewport1",
x = 0,
y = 0,
width = "50vw", -- 50% of viewport width (1920) = 960
height = "25vh" -- 25% of viewport height (1080) = 270
width = "50vw", -- 50% of viewport width (1920) = 960
height = "25vh", -- 25% of viewport height (1080) = 270
})
luaunit.assertNotNil(element)
@@ -294,7 +294,7 @@ function TestElementPositioning:test_element_absolute_position()
y = 200,
width = 50,
height = 50,
positioning = "absolute"
positioning = "absolute",
})
luaunit.assertNotNil(element)
@@ -307,7 +307,7 @@ function TestElementPositioning:test_nested_element_positions()
x = 100,
y = 100,
width = 300,
height = 200
height = 200,
})
local child = FlexLove.new({
@@ -316,7 +316,7 @@ function TestElementPositioning:test_nested_element_positions()
y = 30,
width = 50,
height = 50,
parent = parent
parent = parent,
})
luaunit.assertNotNil(parent)
@@ -346,7 +346,7 @@ function TestElementFlex:test_element_with_flex_direction()
width = 300,
height = 200,
positioning = "flex",
flexDirection = "horizontal"
flexDirection = "horizontal",
})
luaunit.assertNotNil(element)
@@ -361,7 +361,7 @@ function TestElementFlex:test_element_with_flex_properties()
width = 300,
height = 200,
positioning = "flex",
flexDirection = "horizontal"
flexDirection = "horizontal",
})
local element = FlexLove.new({
@@ -371,7 +371,7 @@ function TestElementFlex:test_element_with_flex_properties()
height = 100,
flexGrow = 1,
flexShrink = 0,
flexBasis = "auto"
flexBasis = "auto",
})
luaunit.assertNotNil(element)
@@ -389,7 +389,7 @@ function TestElementFlex:test_element_with_gap()
width = 300,
height = 200,
positioning = "flex",
gap = 10
gap = 10,
})
luaunit.assertNotNil(element)
@@ -414,7 +414,7 @@ function TestElementStyling:test_element_with_border()
y = 0,
width = 100,
height = 100,
border = 2
border = 2,
})
luaunit.assertNotNil(element)
@@ -428,7 +428,7 @@ function TestElementStyling:test_element_with_corner_radius()
y = 0,
width = 100,
height = 100,
cornerRadius = 10
cornerRadius = 10,
})
luaunit.assertNotNil(element)
@@ -444,7 +444,7 @@ function TestElementStyling:test_element_with_text_align()
width = 200,
height = 100,
text = "Centered Text",
textAlign = "center"
textAlign = "center",
})
luaunit.assertNotNil(element)
@@ -458,7 +458,7 @@ function TestElementStyling:test_element_with_opacity()
y = 0,
width = 100,
height = 100,
opacity = 0.5
opacity = 0.5,
})
luaunit.assertNotNil(element)
@@ -473,7 +473,7 @@ function TestElementStyling:test_element_with_border_color()
width = 100,
height = 100,
border = 2,
borderColor = {1, 0, 0, 1}
borderColor = { 1, 0, 0, 1 },
})
luaunit.assertNotNil(element)
@@ -498,7 +498,7 @@ function TestElementMethods:test_element_setText()
y = 0,
width = 200,
height = 100,
text = "Initial"
text = "Initial",
})
element:setText("Updated")
@@ -511,7 +511,7 @@ function TestElementMethods:test_element_addChild()
x = 0,
y = 0,
width = 300,
height = 200
height = 200,
})
local child = FlexLove.new({
@@ -519,7 +519,7 @@ function TestElementMethods:test_element_addChild()
x = 10,
y = 10,
width = 50,
height = 50
height = 50,
})
parent:addChild(child)
@@ -545,7 +545,7 @@ function TestElementScroll:test_scrollable_element_with_overflow()
y = 0,
width = 200,
height = 200,
overflow = "scroll"
overflow = "scroll",
})
luaunit.assertNotNil(element)
@@ -560,7 +560,7 @@ function TestElementScroll:test_setScrollPosition()
y = 0,
width = 200,
height = 200,
overflow = "scroll"
overflow = "scroll",
})
element:setScrollPosition(50, 100)
@@ -578,7 +578,7 @@ function TestElementScroll:test_scrollBy()
y = 0,
width = 200,
height = 200,
overflow = "scroll"
overflow = "scroll",
})
local initialX, initialY = element:getScrollPosition()
@@ -596,7 +596,7 @@ function TestElementScroll:test_scrollToTop()
y = 0,
width = 200,
height = 200,
overflow = "scroll"
overflow = "scroll",
})
element:scrollToTop()
@@ -611,7 +611,7 @@ function TestElementScroll:test_scrollToBottom()
y = 0,
width = 200,
height = 200,
overflow = "scroll"
overflow = "scroll",
})
element:scrollToBottom()
@@ -627,7 +627,7 @@ function TestElementScroll:test_scrollToLeft()
y = 0,
width = 200,
height = 200,
overflow = "scroll"
overflow = "scroll",
})
element:scrollToLeft()
@@ -642,7 +642,7 @@ function TestElementScroll:test_scrollToRight()
y = 0,
width = 200,
height = 200,
overflow = "scroll"
overflow = "scroll",
})
element:scrollToRight()
@@ -657,7 +657,7 @@ function TestElementScroll:test_getMaxScroll()
y = 0,
width = 200,
height = 200,
overflow = "scroll"
overflow = "scroll",
})
local maxX, maxY = element:getMaxScroll()
@@ -672,7 +672,7 @@ function TestElementScroll:test_getScrollPercentage()
y = 0,
width = 200,
height = 200,
overflow = "scroll"
overflow = "scroll",
})
local percentX, percentY = element:getScrollPercentage()
@@ -689,7 +689,7 @@ function TestElementScroll:test_hasOverflow()
y = 0,
width = 200,
height = 200,
overflow = "scroll"
overflow = "scroll",
})
local hasOverflowX, hasOverflowY = element:hasOverflow()
@@ -704,7 +704,7 @@ function TestElementScroll:test_getContentSize()
y = 0,
width = 200,
height = 200,
overflow = "scroll"
overflow = "scroll",
})
local contentWidth, contentHeight = element:getContentSize()
@@ -729,7 +729,7 @@ function TestElementGeometry:test_getBounds()
x = 10,
y = 20,
width = 100,
height = 50
height = 50,
})
local bounds = element:getBounds()
@@ -745,7 +745,7 @@ function TestElementGeometry:test_contains_point_inside()
x = 10,
y = 20,
width = 100,
height = 50
height = 50,
})
luaunit.assertTrue(element:contains(50, 40))
@@ -757,7 +757,7 @@ function TestElementGeometry:test_contains_point_outside()
x = 10,
y = 20,
width = 100,
height = 50
height = 50,
})
luaunit.assertFalse(element:contains(200, 200))
@@ -769,7 +769,7 @@ function TestElementGeometry:test_getBorderBoxWidth_no_border()
x = 0,
y = 0,
width = 100,
height = 50
height = 50,
})
local borderBoxWidth = element:getBorderBoxWidth()
@@ -782,7 +782,7 @@ function TestElementGeometry:test_getBorderBoxHeight_no_border()
x = 0,
y = 0,
width = 100,
height = 50
height = 50,
})
local borderBoxHeight = element:getBorderBoxHeight()
@@ -796,7 +796,7 @@ function TestElementGeometry:test_getBorderBoxWidth_with_border()
y = 0,
width = 100,
height = 50,
border = { left = 2, right = 2, top = 0, bottom = 0 }
border = { left = 2, right = 2, top = 0, bottom = 0 },
})
local borderBoxWidth = element:getBorderBoxWidth()
@@ -811,7 +811,7 @@ function TestElementGeometry:test_getAvailableContentWidth()
y = 0,
width = 200,
height = 100,
padding = { top = 10, right = 10, bottom = 10, left = 10 }
padding = { top = 10, right = 10, bottom = 10, left = 10 },
})
local availWidth = element:getAvailableContentWidth()
@@ -827,7 +827,7 @@ function TestElementGeometry:test_getAvailableContentHeight()
y = 0,
width = 200,
height = 100,
padding = { top = 10, right = 10, bottom = 10, left = 10 }
padding = { top = 10, right = 10, bottom = 10, left = 10 },
})
local availHeight = element:getAvailableContentHeight()
@@ -843,7 +843,7 @@ function TestElementGeometry:test_getScaledContentPadding()
y = 0,
width = 200,
height = 100,
padding = { top = 10, right = 10, bottom = 10, left = 10 }
padding = { top = 10, right = 10, bottom = 10, left = 10 },
})
local padding = element:getScaledContentPadding()
@@ -873,7 +873,7 @@ function TestElementChildren:test_addChild()
x = 0,
y = 0,
width = 200,
height = 200
height = 200,
})
local child = FlexLove.new({
@@ -881,7 +881,7 @@ function TestElementChildren:test_addChild()
x = 10,
y = 10,
width = 50,
height = 50
height = 50,
})
parent:addChild(child)
@@ -896,7 +896,7 @@ function TestElementChildren:test_removeChild()
x = 0,
y = 0,
width = 200,
height = 200
height = 200,
})
local child = FlexLove.new({
@@ -904,7 +904,7 @@ function TestElementChildren:test_removeChild()
x = 10,
y = 10,
width = 50,
height = 50
height = 50,
})
parent:addChild(child)
@@ -920,7 +920,7 @@ function TestElementChildren:test_clearChildren()
x = 0,
y = 0,
width = 200,
height = 200
height = 200,
})
local child1 = FlexLove.new({ id = "child1", x = 0, y = 0, width = 50, height = 50 })
@@ -939,7 +939,7 @@ function TestElementChildren:test_getChildCount()
x = 0,
y = 0,
width = 200,
height = 200
height = 200,
})
local child1 = FlexLove.new({ id = "child1", x = 0, y = 0, width = 50, height = 50 })
@@ -969,7 +969,7 @@ function TestElementVisibility:test_visibility_visible()
y = 0,
width = 100,
height = 100,
visibility = "visible"
visibility = "visible",
})
luaunit.assertEquals(element.visibility, "visible")
@@ -982,7 +982,7 @@ function TestElementVisibility:test_visibility_hidden()
y = 0,
width = 100,
height = 100,
visibility = "hidden"
visibility = "hidden",
})
luaunit.assertEquals(element.visibility, "hidden")
@@ -994,7 +994,7 @@ function TestElementVisibility:test_opacity_default()
x = 0,
y = 0,
width = 100,
height = 100
height = 100,
})
luaunit.assertEquals(element.opacity, 1)
@@ -1007,7 +1007,7 @@ function TestElementVisibility:test_opacity_custom()
y = 0,
width = 100,
height = 100,
opacity = 0.5
opacity = 0.5,
})
luaunit.assertEquals(element.opacity, 0.5)
@@ -1032,7 +1032,7 @@ function TestElementTextEditing:test_editable_element()
width = 200,
height = 40,
editable = true,
text = "Edit me"
text = "Edit me",
})
luaunit.assertTrue(element.editable)
@@ -1047,7 +1047,7 @@ function TestElementTextEditing:test_placeholder_text()
width = 200,
height = 40,
editable = true,
placeholder = "Enter text..."
placeholder = "Enter text...",
})
luaunit.assertEquals(element.placeholder, "Enter text...")
@@ -1071,7 +1071,7 @@ function TestElementAdditional:test_element_with_z_index()
y = 0,
width = 100,
height = 100,
z = 10
z = 10,
})
luaunit.assertEquals(element.z, 10)
@@ -1084,7 +1084,7 @@ function TestElementAdditional:test_element_with_text()
y = 0,
width = 100,
height = 100,
text = "Hello World"
text = "Hello World",
})
luaunit.assertEquals(element.text, "Hello World")
@@ -1101,7 +1101,7 @@ function TestElementAdditional:test_element_with_text_color()
width = 100,
height = 100,
text = "Red text",
textColor = textColor
textColor = textColor,
})
luaunit.assertEquals(element.textColor, textColor)
@@ -1117,7 +1117,7 @@ function TestElementAdditional:test_element_with_background_color()
y = 0,
width = 100,
height = 100,
backgroundColor = bgColor
backgroundColor = bgColor,
})
luaunit.assertEquals(element.backgroundColor, bgColor)
@@ -1130,7 +1130,7 @@ function TestElementAdditional:test_element_with_corner_radius()
y = 0,
width = 100,
height = 100,
cornerRadius = 10
cornerRadius = 10,
})
luaunit.assertNotNil(element.cornerRadius)
@@ -1147,7 +1147,7 @@ function TestElementAdditional:test_element_with_margin()
y = 0,
width = 100,
height = 100,
margin = { top = 5, right = 10, bottom = 5, left = 10 }
margin = { top = 5, right = 10, bottom = 5, left = 10 },
})
luaunit.assertNotNil(element.margin)
@@ -1163,7 +1163,7 @@ function TestElementAdditional:test_element_destroy()
x = 0,
y = 0,
width = 200,
height = 200
height = 200,
})
local child = FlexLove.new({
@@ -1172,7 +1172,7 @@ function TestElementAdditional:test_element_destroy()
x = 0,
y = 0,
width = 50,
height = 50
height = 50,
})
luaunit.assertEquals(#parent.children, 1)
@@ -1187,7 +1187,7 @@ function TestElementAdditional:test_element_with_disabled()
y = 0,
width = 100,
height = 100,
disabled = true
disabled = true,
})
luaunit.assertTrue(element.disabled)
@@ -1200,7 +1200,7 @@ function TestElementAdditional:test_element_with_active()
y = 0,
width = 100,
height = 100,
active = true
active = true,
})
luaunit.assertTrue(element.active)
@@ -1215,7 +1215,7 @@ function TestElementAdditional:test_element_with_userdata()
y = 0,
width = 100,
height = 100,
userdata = customData
userdata = customData,
})
luaunit.assertEquals(element.userdata, customData)
@@ -1223,7 +1223,6 @@ function TestElementAdditional:test_element_with_userdata()
luaunit.assertEquals(element.userdata.count, 42)
end
if not _G.RUNNING_ALL_TESTS then
os.exit(luaunit.LuaUnit.run())
end

View File

@@ -0,0 +1,141 @@
-- Test suite for ErrorHandler module
package.path = package.path .. ";./?.lua;./modules/?.lua"
require("testing.loveStub")
local luaunit = require("testing.luaunit")
local ErrorHandler = require("modules.ErrorHandler")
TestErrorHandler = {}
-- Test: error() throws with correct format
function TestErrorHandler:test_error_throws_with_format()
local success, err = pcall(function()
ErrorHandler.error("TestModule", "Something went wrong")
end)
luaunit.assertFalse(success, "error() should throw")
luaunit.assertStrContains(err, "[FlexLove - TestModule] Error: Something went wrong")
end
-- Test: warn() prints with correct format
function TestErrorHandler:test_warn_prints_with_format()
-- Capture print output by mocking print
local captured = nil
local originalPrint = print
print = function(msg)
captured = msg
end
ErrorHandler.warn("TestModule", "This is a warning")
print = originalPrint
luaunit.assertNotNil(captured, "warn() should print")
luaunit.assertEquals(captured, "[FlexLove - TestModule] Warning: This is a warning")
end
-- Test: assertNotNil returns true for non-nil value
function TestErrorHandler:test_assertNotNil_returns_true_for_valid()
local result = ErrorHandler.assertNotNil("TestModule", "some value", "testParam")
luaunit.assertTrue(result, "assertNotNil should return true for non-nil value")
end
-- Test: assertNotNil throws for nil value
function TestErrorHandler:test_assertNotNil_throws_for_nil()
local success, err = pcall(function()
ErrorHandler.assertNotNil("TestModule", nil, "testParam")
end)
luaunit.assertFalse(success, "assertNotNil should throw for nil")
luaunit.assertStrContains(err, "Parameter 'testParam' cannot be nil")
end
-- Test: assertType returns true for correct type
function TestErrorHandler:test_assertType_returns_true_for_valid()
local result = ErrorHandler.assertType("TestModule", "hello", "string", "testParam")
luaunit.assertTrue(result, "assertType should return true for correct type")
result = ErrorHandler.assertType("TestModule", 123, "number", "testParam")
luaunit.assertTrue(result, "assertType should return true for number")
result = ErrorHandler.assertType("TestModule", {}, "table", "testParam")
luaunit.assertTrue(result, "assertType should return true for table")
end
-- Test: assertType throws for wrong type
function TestErrorHandler:test_assertType_throws_for_wrong_type()
local success, err = pcall(function()
ErrorHandler.assertType("TestModule", 123, "string", "testParam")
end)
luaunit.assertFalse(success, "assertType should throw for wrong type")
luaunit.assertStrContains(err, "Parameter 'testParam' must be string, got number")
end
-- Test: assertRange returns true for value in range
function TestErrorHandler:test_assertRange_returns_true_for_valid()
local result = ErrorHandler.assertRange("TestModule", 5, 0, 10, "testParam")
luaunit.assertTrue(result, "assertRange should return true for value in range")
result = ErrorHandler.assertRange("TestModule", 0, 0, 10, "testParam")
luaunit.assertTrue(result, "assertRange should accept min boundary")
result = ErrorHandler.assertRange("TestModule", 10, 0, 10, "testParam")
luaunit.assertTrue(result, "assertRange should accept max boundary")
end
-- Test: assertRange throws for value below min
function TestErrorHandler:test_assertRange_throws_for_below_min()
local success, err = pcall(function()
ErrorHandler.assertRange("TestModule", -1, 0, 10, "testParam")
end)
luaunit.assertFalse(success, "assertRange should throw for value below min")
luaunit.assertStrContains(err, "Parameter 'testParam' must be between 0 and 10, got -1")
end
-- Test: assertRange throws for value above max
function TestErrorHandler:test_assertRange_throws_for_above_max()
local success, err = pcall(function()
ErrorHandler.assertRange("TestModule", 11, 0, 10, "testParam")
end)
luaunit.assertFalse(success, "assertRange should throw for value above max")
luaunit.assertStrContains(err, "Parameter 'testParam' must be between 0 and 10, got 11")
end
-- Test: warnDeprecated prints deprecation warning
function TestErrorHandler:test_warnDeprecated_prints_message()
local captured = nil
local originalPrint = print
print = function(msg)
captured = msg
end
ErrorHandler.warnDeprecated("TestModule", "oldFunction", "newFunction")
print = originalPrint
luaunit.assertNotNil(captured, "warnDeprecated should print")
luaunit.assertStrContains(captured, "'oldFunction' is deprecated. Use 'newFunction' instead")
end
-- Test: warnCommonMistake prints helpful message
function TestErrorHandler:test_warnCommonMistake_prints_message()
local captured = nil
local originalPrint = print
print = function(msg)
captured = msg
end
ErrorHandler.warnCommonMistake("TestModule", "Width is zero", "Set width to positive value")
print = originalPrint
luaunit.assertNotNil(captured, "warnCommonMistake should print")
luaunit.assertStrContains(captured, "Width is zero. Suggestion: Set width to positive value")
end
if not _G.RUNNING_ALL_TESTS then
os.exit(luaunit.LuaUnit.run())
end

View File

@@ -0,0 +1,522 @@
-- Test suite for EventHandler module
package.path = package.path .. ";./?.lua;./modules/?.lua"
require("testing.loveStub")
local luaunit = require("testing.luaunit")
local EventHandler = require("modules.EventHandler")
local InputEvent = require("modules.InputEvent")
local utils = require("modules.utils")
TestEventHandler = {}
-- Mock Context module
local MockContext = {
getContext = function()
return {}
end,
}
-- Helper to create EventHandler with dependencies
local function createEventHandler(config)
config = config or {}
return EventHandler.new(config, {
InputEvent = InputEvent,
Context = MockContext,
utils = utils,
})
end
-- Mock element
local function createMockElement()
return {
x = 0,
y = 0,
width = 100,
height = 100,
disabled = false,
editable = false,
_focused = false,
padding = { left = 0, right = 0, top = 0, bottom = 0 },
_borderBoxWidth = 100,
_borderBoxHeight = 100,
isFocused = function(self)
return self._focused
end,
focus = function(self)
self._focused = true
end,
}
end
-- Test: new() creates instance with defaults
function TestEventHandler:test_new_creates_with_defaults()
local handler = createEventHandler()
luaunit.assertNotNil(handler)
luaunit.assertNil(handler.onEvent)
luaunit.assertNotNil(handler._pressed)
luaunit.assertEquals(handler._clickCount, 0)
luaunit.assertFalse(handler._hovered)
luaunit.assertFalse(handler._scrollbarPressHandled)
end
-- Test: new() accepts custom config
function TestEventHandler:test_new_accepts_custom_config()
local onEventCalled = false
local handler = createEventHandler({
onEvent = function()
onEventCalled = true
end,
_clickCount = 5,
_hovered = true,
})
luaunit.assertNotNil(handler.onEvent)
luaunit.assertEquals(handler._clickCount, 5)
luaunit.assertTrue(handler._hovered)
end
-- Test: initialize() sets element reference
function TestEventHandler:test_initialize_sets_element()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
luaunit.assertEquals(handler._element, element)
end
-- Test: getState() returns state data
function TestEventHandler:test_getState_returns_state()
local handler = createEventHandler({
_clickCount = 3,
_hovered = true,
})
handler._pressed[1] = true
handler._lastClickTime = 12345
local state = handler:getState()
luaunit.assertNotNil(state)
luaunit.assertEquals(state._clickCount, 3)
luaunit.assertTrue(state._hovered)
luaunit.assertTrue(state._pressed[1])
luaunit.assertEquals(state._lastClickTime, 12345)
end
-- Test: setState() restores state
function TestEventHandler:test_setState_restores_state()
local handler = createEventHandler()
local state = {
_pressed = { [1] = true },
_clickCount = 2,
_hovered = true,
_lastClickTime = 5000,
_lastClickButton = 1,
}
handler:setState(state)
luaunit.assertEquals(handler._clickCount, 2)
luaunit.assertTrue(handler._hovered)
luaunit.assertTrue(handler._pressed[1])
luaunit.assertEquals(handler._lastClickTime, 5000)
luaunit.assertEquals(handler._lastClickButton, 1)
end
-- Test: setState() handles nil gracefully
function TestEventHandler:test_setState_handles_nil()
local handler = createEventHandler()
handler._clickCount = 5
handler:setState(nil)
-- Should not error, should preserve original state
luaunit.assertEquals(handler._clickCount, 5)
end
-- Test: setState() uses defaults for missing values
function TestEventHandler:test_setState_uses_defaults()
local handler = createEventHandler()
handler:setState({}) -- Empty state
luaunit.assertNotNil(handler._pressed)
luaunit.assertEquals(handler._clickCount, 0)
luaunit.assertFalse(handler._hovered)
end
-- Test: resetScrollbarPressFlag() resets flag
function TestEventHandler:test_resetScrollbarPressFlag()
local handler = createEventHandler()
handler._scrollbarPressHandled = true
handler:resetScrollbarPressFlag()
luaunit.assertFalse(handler._scrollbarPressHandled)
end
-- Test: isAnyButtonPressed() returns false when no buttons pressed
function TestEventHandler:test_isAnyButtonPressed_returns_false()
local handler = createEventHandler()
luaunit.assertFalse(handler:isAnyButtonPressed())
end
-- Test: isAnyButtonPressed() returns true when button pressed
function TestEventHandler:test_isAnyButtonPressed_returns_true()
local handler = createEventHandler()
handler._pressed[1] = true
luaunit.assertTrue(handler:isAnyButtonPressed())
end
-- Test: isButtonPressed() checks specific button
function TestEventHandler:test_isButtonPressed_checks_specific_button()
local handler = createEventHandler()
handler._pressed[1] = true
handler._pressed[2] = false
luaunit.assertTrue(handler:isButtonPressed(1))
luaunit.assertFalse(handler:isButtonPressed(2))
luaunit.assertFalse(handler:isButtonPressed(3))
end
-- Test: processMouseEvents() returns early if no element
function TestEventHandler:test_processMouseEvents_no_element()
local handler = createEventHandler()
-- Should not error
handler:processMouseEvents(50, 50, true, true)
end
-- Test: processMouseEvents() handles press event
function TestEventHandler:test_processMouseEvents_press()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
local eventReceived = nil
handler.onEvent = function(el, event)
eventReceived = event
end
-- Mock love.mouse.isDown for button 1
local originalIsDown = love.mouse.isDown
love.mouse.isDown = function(button)
return button == 1
end
-- First call - button just pressed
handler:processMouseEvents(50, 50, true, true)
luaunit.assertNotNil(eventReceived)
luaunit.assertEquals(eventReceived.type, "press")
luaunit.assertEquals(eventReceived.button, 1)
luaunit.assertTrue(handler._pressed[1])
love.mouse.isDown = originalIsDown
end
-- Test: processMouseEvents() handles drag event
function TestEventHandler:test_processMouseEvents_drag()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
local eventsReceived = {}
handler.onEvent = function(el, event)
table.insert(eventsReceived, event)
end
local originalIsDown = love.mouse.isDown
love.mouse.isDown = function(button)
return button == 1
end
-- First call - press at (50, 50)
handler:processMouseEvents(50, 50, true, true)
-- Second call - drag to (60, 70)
handler:processMouseEvents(60, 70, true, true)
luaunit.assertTrue(#eventsReceived >= 2)
-- Find drag event
local dragEvent = nil
for _, event in ipairs(eventsReceived) do
if event.type == "drag" then
dragEvent = event
break
end
end
luaunit.assertNotNil(dragEvent, "Should receive drag event")
luaunit.assertEquals(dragEvent.dx, 10)
luaunit.assertEquals(dragEvent.dy, 20)
love.mouse.isDown = originalIsDown
end
-- Test: processMouseEvents() handles release and click
function TestEventHandler:test_processMouseEvents_release_and_click()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
local eventsReceived = {}
handler.onEvent = function(el, event)
table.insert(eventsReceived, event)
end
local isButtonDown = true
local originalIsDown = love.mouse.isDown
love.mouse.isDown = function(button)
return button == 1 and isButtonDown
end
-- Press
handler:processMouseEvents(50, 50, true, true)
-- Release
isButtonDown = false
handler:processMouseEvents(50, 50, true, true)
-- Should have: press, click, release events
luaunit.assertTrue(#eventsReceived >= 3)
local hasPress = false
local hasClick = false
local hasRelease = false
for _, event in ipairs(eventsReceived) do
if event.type == "press" then
hasPress = true
end
if event.type == "click" then
hasClick = true
end
if event.type == "release" then
hasRelease = true
end
end
luaunit.assertTrue(hasPress, "Should have press event")
luaunit.assertTrue(hasClick, "Should have click event")
luaunit.assertTrue(hasRelease, "Should have release event")
love.mouse.isDown = originalIsDown
end
-- Test: processMouseEvents() detects double-click
function TestEventHandler:test_processMouseEvents_double_click()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
local eventsReceived = {}
handler.onEvent = function(el, event)
table.insert(eventsReceived, event)
end
local isButtonDown = false
local originalIsDown = love.mouse.isDown
love.mouse.isDown = function(button)
return button == 1 and isButtonDown
end
-- First click
isButtonDown = true
handler:processMouseEvents(50, 50, true, true)
isButtonDown = false
handler:processMouseEvents(50, 50, true, true)
-- Second click (quickly after first)
isButtonDown = true
handler:processMouseEvents(50, 50, true, true)
isButtonDown = false
handler:processMouseEvents(50, 50, true, true)
-- Find click events
local clickEvents = {}
for _, event in ipairs(eventsReceived) do
if event.type == "click" then
table.insert(clickEvents, event)
end
end
luaunit.assertTrue(#clickEvents >= 2)
-- Second click should have clickCount = 2
if #clickEvents >= 2 then
luaunit.assertEquals(clickEvents[2].clickCount, 2)
end
love.mouse.isDown = originalIsDown
end
-- Test: processMouseEvents() handles rightclick
function TestEventHandler:test_processMouseEvents_rightclick()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
local eventsReceived = {}
handler.onEvent = function(el, event)
table.insert(eventsReceived, event)
end
local isButtonDown = false
local originalIsDown = love.mouse.isDown
love.mouse.isDown = function(button)
return button == 2 and isButtonDown
end
-- Right click press and release
isButtonDown = true
handler:processMouseEvents(50, 50, true, true)
isButtonDown = false
handler:processMouseEvents(50, 50, true, true)
local hasRightClick = false
for _, event in ipairs(eventsReceived) do
if event.type == "rightclick" then
hasRightClick = true
luaunit.assertEquals(event.button, 2)
end
end
luaunit.assertTrue(hasRightClick, "Should have rightclick event")
love.mouse.isDown = originalIsDown
end
-- Test: processMouseEvents() handles middleclick
function TestEventHandler:test_processMouseEvents_middleclick()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
local eventsReceived = {}
handler.onEvent = function(el, event)
table.insert(eventsReceived, event)
end
local isButtonDown = false
local originalIsDown = love.mouse.isDown
love.mouse.isDown = function(button)
return button == 3 and isButtonDown
end
-- Middle click press and release
isButtonDown = true
handler:processMouseEvents(50, 50, true, true)
isButtonDown = false
handler:processMouseEvents(50, 50, true, true)
local hasMiddleClick = false
for _, event in ipairs(eventsReceived) do
if event.type == "middleclick" then
hasMiddleClick = true
luaunit.assertEquals(event.button, 3)
end
end
luaunit.assertTrue(hasMiddleClick, "Should have middleclick event")
love.mouse.isDown = originalIsDown
end
-- Test: processMouseEvents() respects disabled state
function TestEventHandler:test_processMouseEvents_disabled()
local handler = createEventHandler()
local element = createMockElement()
element.disabled = true
handler:initialize(element)
local eventReceived = false
handler.onEvent = function(el, event)
eventReceived = true
end
local originalIsDown = love.mouse.isDown
love.mouse.isDown = function(button)
return button == 1
end
handler:processMouseEvents(50, 50, true, true)
-- Should not fire event for disabled element
luaunit.assertFalse(eventReceived)
love.mouse.isDown = originalIsDown
end
-- Test: processTouchEvents() handles touch
function TestEventHandler:test_processTouchEvents()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
local eventsReceived = {}
handler.onEvent = function(el, event)
table.insert(eventsReceived, event)
end
-- Mock touch API
local originalGetTouches = love.touch.getTouches
local originalGetPosition = love.touch.getPosition
love.touch.getTouches = function()
return { "touch1" }
end
love.touch.getPosition = function(id)
if id == "touch1" then
return 150, 150 -- Outside element bounds
end
end
-- First call - touch starts inside
love.touch.getPosition = function(id)
if id == "touch1" then
return 50, 50 -- Inside element
end
end
handler:processTouchEvents()
-- Second call - touch moves outside
love.touch.getPosition = function(id)
if id == "touch1" then
return 150, 150 -- Outside element
end
end
handler:processTouchEvents()
-- Should receive touch event
luaunit.assertTrue(#eventsReceived >= 1)
love.touch.getTouches = originalGetTouches
love.touch.getPosition = originalGetPosition
end
-- Test: processTouchEvents() returns early if no element
function TestEventHandler:test_processTouchEvents_no_element()
local handler = createEventHandler()
-- Should not error
handler:processTouchEvents()
end
-- Test: processTouchEvents() returns early if no onEvent
function TestEventHandler:test_processTouchEvents_no_onEvent()
local handler = createEventHandler()
local element = createMockElement()
handler:initialize(element)
-- Should not error (no onEvent callback)
handler:processTouchEvents()
end
if not _G.RUNNING_ALL_TESTS then
os.exit(luaunit.LuaUnit.run())
end

View File

@@ -24,15 +24,15 @@ function TestGridLayout:test_default_grid_single_child()
y = 0,
width = 400,
height = 300,
positioning = "grid"
positioning = "grid",
-- Default: gridRows=1, gridColumns=1
})
local child = FlexLove.new({
id = "child1",
parent = container,
width = 50, -- Will be stretched by grid
height = 50
width = 50, -- Will be stretched by grid
height = 50,
})
FlexLove.endFrame()
@@ -55,7 +55,7 @@ function TestGridLayout:test_2x2_grid_four_children()
height = 400,
positioning = "grid",
gridRows = 2,
gridColumns = 2
gridColumns = 2,
})
local children = {}
@@ -64,7 +64,7 @@ function TestGridLayout:test_2x2_grid_four_children()
id = "child" .. i,
parent = container,
width = 50,
height = 50
height = 50,
})
end
@@ -97,13 +97,13 @@ function TestGridLayout:test_grid_with_gaps()
id = "grid",
x = 0,
y = 0,
width = 420, -- 2 cells * 200 + 1 gap * 20
height = 320, -- 2 cells * 150 + 1 gap * 20
width = 420, -- 2 cells * 200 + 1 gap * 20
height = 320, -- 2 cells * 150 + 1 gap * 20
positioning = "grid",
gridRows = 2,
gridColumns = 2,
columnGap = 20,
rowGap = 20
rowGap = 20,
})
local children = {}
@@ -112,7 +112,7 @@ function TestGridLayout:test_grid_with_gaps()
id = "child" .. i,
parent = container,
width = 50,
height = 50
height = 50,
})
end
@@ -142,17 +142,17 @@ function TestGridLayout:test_grid_overflow_children()
height = 200,
positioning = "grid",
gridRows = 2,
gridColumns = 2
gridColumns = 2,
-- Only 4 cells available
})
local children = {}
for i = 1, 6 do -- 6 children, but only 4 cells
for i = 1, 6 do -- 6 children, but only 4 cells
children[i] = FlexLove.new({
id = "child" .. i,
parent = container,
width = 50,
height = 50
height = 50,
})
end
@@ -178,14 +178,14 @@ function TestGridLayout:test_grid_align_center()
positioning = "grid",
gridRows = 2,
gridColumns = 2,
alignItems = "center"
alignItems = "center",
})
local child = FlexLove.new({
id = "child1",
parent = container,
width = 100,
height = 100
height = 100,
})
FlexLove.endFrame()
@@ -210,14 +210,14 @@ function TestGridLayout:test_grid_align_flex_start()
positioning = "grid",
gridRows = 2,
gridColumns = 2,
alignItems = "flex-start"
alignItems = "flex-start",
})
local child = FlexLove.new({
id = "child1",
parent = container,
width = 100,
height = 100
height = 100,
})
FlexLove.endFrame()
@@ -241,14 +241,14 @@ function TestGridLayout:test_grid_align_flex_end()
positioning = "grid",
gridRows = 2,
gridColumns = 2,
alignItems = "flex-end"
alignItems = "flex-end",
})
local child = FlexLove.new({
id = "child1",
parent = container,
width = 100,
height = 100
height = 100,
})
FlexLove.endFrame()
@@ -267,19 +267,19 @@ function TestGridLayout:test_grid_with_padding()
id = "grid",
x = 0,
y = 0,
width = 500, -- Total width
width = 500, -- Total width
height = 500,
padding = { top = 50, right = 50, bottom = 50, left = 50 },
positioning = "grid",
gridRows = 2,
gridColumns = 2
gridColumns = 2,
})
local child = FlexLove.new({
id = "child1",
parent = container,
width = 50,
height = 50
height = 50,
})
FlexLove.endFrame()
@@ -304,7 +304,7 @@ function TestGridLayout:test_grid_with_absolute_child()
height = 400,
positioning = "grid",
gridRows = 2,
gridColumns = 2
gridColumns = 2,
})
-- Regular child
@@ -312,7 +312,7 @@ function TestGridLayout:test_grid_with_absolute_child()
id = "child1",
parent = container,
width = 50,
height = 50
height = 50,
})
-- Absolutely positioned child (should be ignored by grid layout)
@@ -323,7 +323,7 @@ function TestGridLayout:test_grid_with_absolute_child()
x = 10,
y = 10,
width = 30,
height = 30
height = 30,
})
-- Another regular child
@@ -331,7 +331,7 @@ function TestGridLayout:test_grid_with_absolute_child()
id = "child3",
parent = container,
width = 50,
height = 50
height = 50,
})
FlexLove.endFrame()
@@ -360,7 +360,7 @@ function TestGridLayout:test_empty_grid()
height = 400,
positioning = "grid",
gridRows = 2,
gridColumns = 2
gridColumns = 2,
-- No children
})
@@ -380,15 +380,15 @@ function TestGridLayout:test_grid_zero_dimensions()
width = 400,
height = 400,
positioning = "grid",
gridRows = 0, -- Invalid: 0 rows
gridColumns = 0 -- Invalid: 0 columns
gridRows = 0, -- Invalid: 0 rows
gridColumns = 0, -- Invalid: 0 columns
})
local child = FlexLove.new({
id = "child1",
parent = container,
width = 50,
height = 50
height = 50,
})
-- This might cause division by zero or other errors
@@ -409,7 +409,7 @@ function TestGridLayout:test_nested_grids()
height = 400,
positioning = "grid",
gridRows = 2,
gridColumns = 2
gridColumns = 2,
})
-- First cell contains another grid
@@ -420,7 +420,7 @@ function TestGridLayout:test_nested_grids()
height = 200,
positioning = "grid",
gridRows = 2,
gridColumns = 2
gridColumns = 2,
})
-- Add children to inner grid
@@ -429,7 +429,7 @@ function TestGridLayout:test_nested_grids()
id = "inner_child" .. i,
parent = innerGrid,
width = 25,
height = 25
height = 25,
})
end
@@ -452,7 +452,7 @@ function TestGridLayout:test_grid_with_reserved_space()
height = 400,
positioning = "grid",
gridRows = 2,
gridColumns = 2
gridColumns = 2,
})
-- Absolute child with left positioning (reserves left space)
@@ -463,7 +463,7 @@ function TestGridLayout:test_grid_with_reserved_space()
left = 0,
top = 0,
width = 50,
height = 50
height = 50,
})
-- Regular grid child
@@ -471,7 +471,7 @@ function TestGridLayout:test_grid_with_reserved_space()
id = "child1",
parent = container,
width = 50,
height = 50
height = 50,
})
FlexLove.endFrame()

View File

@@ -0,0 +1,166 @@
local luaunit = require("testing.luaunit")
require("testing.loveStub")
local ImageCache = require("modules.ImageCache")
TestImageCache = {}
function TestImageCache:setUp()
-- Clear cache before each test
ImageCache.clear()
end
function TestImageCache:tearDown()
ImageCache.clear()
end
-- Unhappy path tests
function TestImageCache:testLoadWithNilPath()
local img, err = ImageCache.load(nil)
luaunit.assertNil(img)
luaunit.assertNotNil(err)
luaunit.assertStrContains(err, "Invalid image path")
end
function TestImageCache:testLoadWithEmptyString()
local img, err = ImageCache.load("")
luaunit.assertNil(img)
luaunit.assertNotNil(err)
luaunit.assertStrContains(err, "Invalid image path")
end
function TestImageCache:testLoadWithInvalidType()
local img, err = ImageCache.load(123)
luaunit.assertNil(img)
luaunit.assertNotNil(err)
luaunit.assertStrContains(err, "Invalid image path")
end
function TestImageCache:testLoadWithInvalidPath()
local img, err = ImageCache.load("nonexistent/path/to/image.png")
luaunit.assertNil(img)
luaunit.assertNotNil(err)
luaunit.assertStrContains(err, "Failed to load image")
end
function TestImageCache:testLoadWithInvalidExtension()
local img, err = ImageCache.load("test.txt")
luaunit.assertNil(img)
luaunit.assertNotNil(err)
luaunit.assertStrContains(err, "Failed to load image")
end
function TestImageCache:testGetWithNilPath()
local img = ImageCache.get(nil)
luaunit.assertNil(img)
end
function TestImageCache:testGetWithEmptyString()
local img = ImageCache.get("")
luaunit.assertNil(img)
end
function TestImageCache:testGetWithInvalidType()
local img = ImageCache.get({})
luaunit.assertNil(img)
end
function TestImageCache:testGetWithNonCachedPath()
local img = ImageCache.get("some/random/path.png")
luaunit.assertNil(img)
end
function TestImageCache:testGetImageDataWithNilPath()
local imgData = ImageCache.getImageData(nil)
luaunit.assertNil(imgData)
end
function TestImageCache:testGetImageDataWithEmptyString()
local imgData = ImageCache.getImageData("")
luaunit.assertNil(imgData)
end
function TestImageCache:testGetImageDataWithInvalidType()
local imgData = ImageCache.getImageData(123)
luaunit.assertNil(imgData)
end
function TestImageCache:testGetImageDataWithNonCachedPath()
local imgData = ImageCache.getImageData("some/path.png")
luaunit.assertNil(imgData)
end
function TestImageCache:testRemoveWithNilPath()
local removed = ImageCache.remove(nil)
luaunit.assertFalse(removed)
end
function TestImageCache:testRemoveWithEmptyString()
local removed = ImageCache.remove("")
luaunit.assertFalse(removed)
end
function TestImageCache:testRemoveWithInvalidType()
local removed = ImageCache.remove(123)
luaunit.assertFalse(removed)
end
function TestImageCache:testRemoveWithNonCachedPath()
local removed = ImageCache.remove("uncached/image.png")
luaunit.assertFalse(removed)
end
function TestImageCache:testClearEmptyCache()
-- Should not error on empty cache
ImageCache.clear()
local stats = ImageCache.getStats()
luaunit.assertEquals(stats.count, 0)
luaunit.assertEquals(stats.memoryEstimate, 0)
end
function TestImageCache:testGetStatsOnEmptyCache()
ImageCache.clear()
local stats = ImageCache.getStats()
luaunit.assertNotNil(stats)
luaunit.assertEquals(stats.count, 0)
luaunit.assertEquals(stats.memoryEstimate, 0)
end
function TestImageCache:testPathNormalization()
-- Test that paths with different slashes are normalized
local path1 = "themes/space.png"
local path2 = "themes\\space.png" -- Windows style
-- Both should normalize to the same path
-- (If first load fails, both should fail the same way)
local img1, err1 = ImageCache.load(path1)
local img2, err2 = ImageCache.load(path2)
-- Both should have same result (either both nil or both same image)
if img1 == nil then
luaunit.assertNil(img2)
else
luaunit.assertEquals(img1, img2)
end
end
function TestImageCache:testLoadWithImageDataFlag()
-- Test loading with imageData flag on invalid path
local img, err = ImageCache.load("invalid/path.png", true)
luaunit.assertNil(img)
luaunit.assertNotNil(err)
end
function TestImageCache:testMultipleClearCalls()
-- Clear multiple times should not error
ImageCache.clear()
ImageCache.clear()
ImageCache.clear()
local stats = ImageCache.getStats()
luaunit.assertEquals(stats.count, 0)
end
if not _G.RUNNING_ALL_TESTS then
os.exit(luaunit.LuaUnit.run())
end

View File

@@ -0,0 +1,247 @@
local luaunit = require("testing.luaunit")
require("testing.loveStub")
local ImageRenderer = require("modules.ImageRenderer")
TestImageRenderer = {}
function TestImageRenderer:setUp()
-- Create a mock image for testing
self.mockImage = {
getDimensions = function()
return 100, 100
end,
}
end
-- Unhappy path tests for calculateFit
function TestImageRenderer:testCalculateFitWithZeroImageWidth()
luaunit.assertError(function()
ImageRenderer.calculateFit(0, 100, 200, 200, "fill")
end)
end
function TestImageRenderer:testCalculateFitWithZeroImageHeight()
luaunit.assertError(function()
ImageRenderer.calculateFit(100, 0, 200, 200, "fill")
end)
end
function TestImageRenderer:testCalculateFitWithNegativeImageWidth()
luaunit.assertError(function()
ImageRenderer.calculateFit(-100, 100, 200, 200, "fill")
end)
end
function TestImageRenderer:testCalculateFitWithNegativeImageHeight()
luaunit.assertError(function()
ImageRenderer.calculateFit(100, -100, 200, 200, "fill")
end)
end
function TestImageRenderer:testCalculateFitWithZeroBoundsWidth()
luaunit.assertError(function()
ImageRenderer.calculateFit(100, 100, 0, 200, "fill")
end)
end
function TestImageRenderer:testCalculateFitWithZeroBoundsHeight()
luaunit.assertError(function()
ImageRenderer.calculateFit(100, 100, 200, 0, "fill")
end)
end
function TestImageRenderer:testCalculateFitWithNegativeBoundsWidth()
luaunit.assertError(function()
ImageRenderer.calculateFit(100, 100, -200, 200, "fill")
end)
end
function TestImageRenderer:testCalculateFitWithNegativeBoundsHeight()
luaunit.assertError(function()
ImageRenderer.calculateFit(100, 100, 200, -200, "fill")
end)
end
function TestImageRenderer:testCalculateFitWithInvalidFitMode()
luaunit.assertError(function()
ImageRenderer.calculateFit(100, 100, 200, 200, "invalid-mode")
end)
end
function TestImageRenderer:testCalculateFitWithNilFitMode()
-- Should default to "fill"
local result = ImageRenderer.calculateFit(100, 100, 200, 200, nil)
luaunit.assertNotNil(result)
luaunit.assertEquals(result.dw, 200)
luaunit.assertEquals(result.dh, 200)
end
function TestImageRenderer:testCalculateFitFillMode()
local result = ImageRenderer.calculateFit(100, 100, 200, 200, "fill")
luaunit.assertEquals(result.scaleX, 2)
luaunit.assertEquals(result.scaleY, 2)
end
function TestImageRenderer:testCalculateFitContainMode()
local result = ImageRenderer.calculateFit(100, 100, 200, 200, "contain")
luaunit.assertEquals(result.scaleX, 2)
luaunit.assertEquals(result.scaleY, 2)
end
function TestImageRenderer:testCalculateFitCoverMode()
local result = ImageRenderer.calculateFit(100, 100, 200, 200, "cover")
luaunit.assertEquals(result.scaleX, 2)
luaunit.assertEquals(result.scaleY, 2)
end
function TestImageRenderer:testCalculateFitNoneMode()
local result = ImageRenderer.calculateFit(100, 100, 200, 200, "none")
luaunit.assertEquals(result.scaleX, 1)
luaunit.assertEquals(result.scaleY, 1)
end
function TestImageRenderer:testCalculateFitScaleDownModeWithLargeImage()
local result = ImageRenderer.calculateFit(300, 300, 200, 200, "scale-down")
-- Should behave like contain for larger images
luaunit.assertNotNil(result)
end
function TestImageRenderer:testCalculateFitScaleDownModeWithSmallImage()
local result = ImageRenderer.calculateFit(50, 50, 200, 200, "scale-down")
-- Should behave like none for smaller images
luaunit.assertEquals(result.scaleX, 1)
luaunit.assertEquals(result.scaleY, 1)
end
-- Unhappy path tests for _parsePosition
function TestImageRenderer:testParsePositionWithNil()
local x, y = ImageRenderer._parsePosition(nil)
luaunit.assertEquals(x, 0.5)
luaunit.assertEquals(y, 0.5)
end
function TestImageRenderer:testParsePositionWithEmptyString()
local x, y = ImageRenderer._parsePosition("")
luaunit.assertEquals(x, 0.5)
luaunit.assertEquals(y, 0.5)
end
function TestImageRenderer:testParsePositionWithInvalidType()
local x, y = ImageRenderer._parsePosition(123)
luaunit.assertEquals(x, 0.5)
luaunit.assertEquals(y, 0.5)
end
function TestImageRenderer:testParsePositionWithInvalidKeyword()
local x, y = ImageRenderer._parsePosition("invalid keyword")
-- Should default to center
luaunit.assertEquals(x, 0.5)
luaunit.assertEquals(y, 0.5)
end
function TestImageRenderer:testParsePositionWithMixedValid()
local x, y = ImageRenderer._parsePosition("left top")
luaunit.assertEquals(x, 0)
luaunit.assertEquals(y, 0)
end
function TestImageRenderer:testParsePositionWithPercentage()
local x, y = ImageRenderer._parsePosition("75% 25%")
luaunit.assertAlmostEquals(x, 0.75, 0.01)
luaunit.assertAlmostEquals(y, 0.25, 0.01)
end
function TestImageRenderer:testParsePositionWithOutOfRangePercentage()
local x, y = ImageRenderer._parsePosition("150% -50%")
-- 150% clamps to 1, but -50% doesn't match pattern so defaults to 0.5
luaunit.assertEquals(x, 1)
luaunit.assertEquals(y, 0.5)
end
function TestImageRenderer:testParsePositionWithSingleValue()
local x, y = ImageRenderer._parsePosition("left")
luaunit.assertEquals(x, 0)
luaunit.assertEquals(y, 0.5) -- Should use center for Y
end
function TestImageRenderer:testParsePositionWithSinglePercentage()
local x, y = ImageRenderer._parsePosition("25%")
luaunit.assertAlmostEquals(x, 0.25, 0.01)
luaunit.assertAlmostEquals(y, 0.25, 0.01)
end
-- Unhappy path tests for draw
function TestImageRenderer:testDrawWithNilImage()
-- Should not crash, just return early
ImageRenderer.draw(nil, 0, 0, 100, 100, "fill")
-- If we get here without error, test passes
luaunit.assertTrue(true)
end
function TestImageRenderer:testDrawWithZeroWidth()
-- Should error in calculateFit
luaunit.assertError(function()
ImageRenderer.draw(self.mockImage, 0, 0, 0, 100, "fill")
end)
end
function TestImageRenderer:testDrawWithZeroHeight()
luaunit.assertError(function()
ImageRenderer.draw(self.mockImage, 0, 0, 100, 0, "fill")
end)
end
function TestImageRenderer:testDrawWithNegativeOpacity()
-- Should work but render with negative opacity
ImageRenderer.draw(self.mockImage, 0, 0, 100, 100, "fill", "center center", -0.5)
luaunit.assertTrue(true)
end
function TestImageRenderer:testDrawWithOpacityGreaterThanOne()
-- Should work but render with >1 opacity
ImageRenderer.draw(self.mockImage, 0, 0, 100, 100, "fill", "center center", 2.0)
luaunit.assertTrue(true)
end
function TestImageRenderer:testDrawWithInvalidFitMode()
luaunit.assertError(function()
ImageRenderer.draw(self.mockImage, 0, 0, 100, 100, "invalid")
end)
end
function TestImageRenderer:testCalculateFitWithVerySmallBounds()
local result = ImageRenderer.calculateFit(1000, 1000, 1, 1, "contain")
luaunit.assertNotNil(result)
-- Scale should be very small
luaunit.assertTrue(result.scaleX < 0.01)
end
function TestImageRenderer:testCalculateFitWithVeryLargeBounds()
local result = ImageRenderer.calculateFit(10, 10, 10000, 10000, "contain")
luaunit.assertNotNil(result)
-- Scale should be very large
luaunit.assertTrue(result.scaleX > 100)
end
function TestImageRenderer:testCalculateFitWithAspectRatioMismatch()
-- Wide image, tall bounds
local result = ImageRenderer.calculateFit(200, 100, 100, 200, "contain")
luaunit.assertNotNil(result)
-- Should maintain aspect ratio
luaunit.assertEquals(result.scaleX, result.scaleY)
end
function TestImageRenderer:testCalculateFitCoverWithAspectRatioMismatch()
-- Wide image, tall bounds
local result = ImageRenderer.calculateFit(200, 100, 100, 200, "cover")
luaunit.assertNotNil(result)
luaunit.assertEquals(result.scaleX, result.scaleY)
end
if not _G.RUNNING_ALL_TESTS then
os.exit(luaunit.LuaUnit.run())
end

View File

@@ -0,0 +1,209 @@
local luaunit = require("testing.luaunit")
require("testing.loveStub")
local ImageScaler = require("modules.ImageScaler")
TestImageScaler = {}
function TestImageScaler:setUp()
-- Create a minimal mock ImageData
self.mockImageData = {
getPixel = function(self, x, y)
-- Return deterministic values based on position
return (x % 256) / 255, (y % 256) / 255, 0.5, 1.0
end,
}
end
-- Unhappy path tests for scaleNearest
function TestImageScaler:testScaleNearestWithNilSource()
luaunit.assertError(function()
ImageScaler.scaleNearest(nil, 0, 0, 10, 10, 20, 20)
end)
end
function TestImageScaler:testScaleNearestWithZeroSourceWidth()
luaunit.assertError(function()
ImageScaler.scaleNearest(self.mockImageData, 0, 0, 0, 10, 20, 20)
end)
end
function TestImageScaler:testScaleNearestWithZeroSourceHeight()
luaunit.assertError(function()
ImageScaler.scaleNearest(self.mockImageData, 0, 0, 10, 0, 20, 20)
end)
end
function TestImageScaler:testScaleNearestWithNegativeSourceWidth()
luaunit.assertError(function()
ImageScaler.scaleNearest(self.mockImageData, 0, 0, -10, 10, 20, 20)
end)
end
function TestImageScaler:testScaleNearestWithNegativeSourceHeight()
luaunit.assertError(function()
ImageScaler.scaleNearest(self.mockImageData, 0, 0, 10, -10, 20, 20)
end)
end
function TestImageScaler:testScaleNearestWithZeroDestWidth()
luaunit.assertError(function()
ImageScaler.scaleNearest(self.mockImageData, 0, 0, 10, 10, 0, 20)
end)
end
function TestImageScaler:testScaleNearestWithZeroDestHeight()
luaunit.assertError(function()
ImageScaler.scaleNearest(self.mockImageData, 0, 0, 10, 10, 20, 0)
end)
end
function TestImageScaler:testScaleNearestWithNegativeDestWidth()
luaunit.assertError(function()
ImageScaler.scaleNearest(self.mockImageData, 0, 0, 10, 10, -20, 20)
end)
end
function TestImageScaler:testScaleNearestWithNegativeDestHeight()
luaunit.assertError(function()
ImageScaler.scaleNearest(self.mockImageData, 0, 0, 10, 10, 20, -20)
end)
end
-- Unhappy path tests for scaleBilinear
function TestImageScaler:testScaleBilinearWithNilSource()
luaunit.assertError(function()
ImageScaler.scaleBilinear(nil, 0, 0, 10, 10, 20, 20)
end)
end
function TestImageScaler:testScaleBilinearWithZeroSourceWidth()
luaunit.assertError(function()
ImageScaler.scaleBilinear(self.mockImageData, 0, 0, 0, 10, 20, 20)
end)
end
function TestImageScaler:testScaleBilinearWithZeroSourceHeight()
luaunit.assertError(function()
ImageScaler.scaleBilinear(self.mockImageData, 0, 0, 10, 0, 20, 20)
end)
end
function TestImageScaler:testScaleBilinearWithNegativeSourceWidth()
luaunit.assertError(function()
ImageScaler.scaleBilinear(self.mockImageData, 0, 0, -10, 10, 20, 20)
end)
end
function TestImageScaler:testScaleBilinearWithNegativeSourceHeight()
luaunit.assertError(function()
ImageScaler.scaleBilinear(self.mockImageData, 0, 0, 10, -10, 20, 20)
end)
end
function TestImageScaler:testScaleBilinearWithZeroDestWidth()
luaunit.assertError(function()
ImageScaler.scaleBilinear(self.mockImageData, 0, 0, 10, 10, 0, 20)
end)
end
function TestImageScaler:testScaleBilinearWithZeroDestHeight()
luaunit.assertError(function()
ImageScaler.scaleBilinear(self.mockImageData, 0, 0, 10, 10, 20, 0)
end)
end
function TestImageScaler:testScaleBilinearWithNegativeDestWidth()
luaunit.assertError(function()
ImageScaler.scaleBilinear(self.mockImageData, 0, 0, 10, 10, -20, 20)
end)
end
function TestImageScaler:testScaleBilinearWithNegativeDestHeight()
luaunit.assertError(function()
ImageScaler.scaleBilinear(self.mockImageData, 0, 0, 10, 10, 20, -20)
end)
end
-- Edge case tests
function TestImageScaler:testScaleNearestWithVeryLargeUpscale()
-- Scale 1x1 to 50x50 (extreme upscale, but fast for testing)
local result = ImageScaler.scaleNearest(self.mockImageData, 0, 0, 1, 1, 50, 50)
luaunit.assertNotNil(result)
end
function TestImageScaler:testScaleNearestWithVeryLargeDownscale()
-- Scale 50x50 to 1x1 (extreme downscale)
local result = ImageScaler.scaleNearest(self.mockImageData, 0, 0, 50, 50, 1, 1)
luaunit.assertNotNil(result)
end
function TestImageScaler:testScaleBilinearWithVeryLargeUpscale()
local result = ImageScaler.scaleBilinear(self.mockImageData, 0, 0, 1, 1, 50, 50)
luaunit.assertNotNil(result)
end
function TestImageScaler:testScaleBilinearWithVeryLargeDownscale()
local result = ImageScaler.scaleBilinear(self.mockImageData, 0, 0, 50, 50, 1, 1)
luaunit.assertNotNil(result)
end
function TestImageScaler:testScaleNearestWithNonIntegerDimensions()
-- Fractional source dimensions (should work with floor/ceil)
local result = ImageScaler.scaleNearest(self.mockImageData, 0, 0, 5.5, 5.5, 10, 10)
luaunit.assertNotNil(result)
end
function TestImageScaler:testScaleBilinearWithNonIntegerDimensions()
local result = ImageScaler.scaleBilinear(self.mockImageData, 0, 0, 5.5, 5.5, 10, 10)
luaunit.assertNotNil(result)
end
function TestImageScaler:testScaleNearestWith1x1Source()
local result = ImageScaler.scaleNearest(self.mockImageData, 0, 0, 1, 1, 5, 5)
luaunit.assertNotNil(result)
end
function TestImageScaler:testScaleBilinearWith1x1Source()
local result = ImageScaler.scaleBilinear(self.mockImageData, 0, 0, 1, 1, 5, 5)
luaunit.assertNotNil(result)
end
function TestImageScaler:testScaleNearestWith1x1Dest()
local result = ImageScaler.scaleNearest(self.mockImageData, 0, 0, 5, 5, 1, 1)
luaunit.assertNotNil(result)
end
function TestImageScaler:testScaleBilinearWith1x1Dest()
local result = ImageScaler.scaleBilinear(self.mockImageData, 0, 0, 5, 5, 1, 1)
luaunit.assertNotNil(result)
end
function TestImageScaler:testScaleNearestWithNonZeroSourceOffset()
-- Source region offset from 0,0
local result = ImageScaler.scaleNearest(self.mockImageData, 10, 10, 5, 5, 10, 10)
luaunit.assertNotNil(result)
end
function TestImageScaler:testScaleBilinearWithNonZeroSourceOffset()
local result = ImageScaler.scaleBilinear(self.mockImageData, 10, 10, 5, 5, 10, 10)
luaunit.assertNotNil(result)
end
function TestImageScaler:testScaleNearestWithAspectRatioChange()
-- Change aspect ratio dramatically
local result = ImageScaler.scaleNearest(self.mockImageData, 0, 0, 5, 20, 20, 5)
luaunit.assertNotNil(result)
end
function TestImageScaler:testScaleBilinearWithAspectRatioChange()
local result = ImageScaler.scaleBilinear(self.mockImageData, 0, 0, 5, 20, 20, 5)
luaunit.assertNotNil(result)
end
if not _G.RUNNING_ALL_TESTS then
os.exit(luaunit.LuaUnit.run())
end

View File

@@ -0,0 +1,211 @@
-- Test suite for InputEvent module
package.path = package.path .. ";./?.lua;./modules/?.lua"
require("testing.loveStub")
local luaunit = require("testing.luaunit")
local InputEvent = require("modules.InputEvent")
TestInputEvent = {}
-- Test: new() creates click event with all properties
function TestInputEvent:test_new_creates_click_event()
local event = InputEvent.new({
type = "click",
button = 1,
x = 100,
y = 200,
modifiers = { shift = false, ctrl = false, alt = false, super = false },
})
luaunit.assertNotNil(event, "new() should return event")
luaunit.assertEquals(event.type, "click")
luaunit.assertEquals(event.button, 1)
luaunit.assertEquals(event.x, 100)
luaunit.assertEquals(event.y, 200)
luaunit.assertNotNil(event.modifiers)
luaunit.assertEquals(event.modifiers.shift, false)
end
-- Test: new() creates press event
function TestInputEvent:test_new_creates_press_event()
local event = InputEvent.new({
type = "press",
button = 1,
x = 50,
y = 75,
modifiers = { shift = true, ctrl = false, alt = false, super = false },
})
luaunit.assertEquals(event.type, "press")
luaunit.assertEquals(event.button, 1)
luaunit.assertEquals(event.x, 50)
luaunit.assertEquals(event.y, 75)
luaunit.assertEquals(event.modifiers.shift, true)
end
-- Test: new() creates release event
function TestInputEvent:test_new_creates_release_event()
local event = InputEvent.new({
type = "release",
button = 1,
x = 150,
y = 250,
modifiers = { shift = false, ctrl = false, alt = false, super = false },
})
luaunit.assertEquals(event.type, "release")
end
-- Test: new() creates rightclick event with button 2
function TestInputEvent:test_new_creates_rightclick_event()
local event = InputEvent.new({
type = "rightclick",
button = 2,
x = 100,
y = 100,
modifiers = { shift = false, ctrl = true, alt = false, super = false },
})
luaunit.assertEquals(event.type, "rightclick")
luaunit.assertEquals(event.button, 2)
luaunit.assertEquals(event.modifiers.ctrl, true)
end
-- Test: new() creates middleclick event with button 3
function TestInputEvent:test_new_creates_middleclick_event()
local event = InputEvent.new({
type = "middleclick",
button = 3,
x = 200,
y = 300,
modifiers = { shift = false, ctrl = false, alt = true, super = false },
})
luaunit.assertEquals(event.type, "middleclick")
luaunit.assertEquals(event.button, 3)
luaunit.assertEquals(event.modifiers.alt, true)
end
-- Test: new() creates drag event with dx and dy
function TestInputEvent:test_new_creates_drag_event_with_deltas()
local event = InputEvent.new({
type = "drag",
button = 1,
x = 100,
y = 100,
dx = 20,
dy = -15,
modifiers = { shift = false, ctrl = false, alt = false, super = false },
})
luaunit.assertEquals(event.type, "drag")
luaunit.assertEquals(event.dx, 20)
luaunit.assertEquals(event.dy, -15)
end
-- Test: new() defaults clickCount to 1 if not provided
function TestInputEvent:test_new_defaults_clickCount_to_one()
local event = InputEvent.new({
type = "click",
button = 1,
x = 0,
y = 0,
modifiers = { shift = false, ctrl = false, alt = false, super = false },
})
luaunit.assertEquals(event.clickCount, 1)
end
-- Test: new() accepts custom clickCount for double-click
function TestInputEvent:test_new_accepts_custom_clickCount()
local event = InputEvent.new({
type = "click",
button = 1,
x = 0,
y = 0,
clickCount = 2,
modifiers = { shift = false, ctrl = false, alt = false, super = false },
})
luaunit.assertEquals(event.clickCount, 2)
end
-- Test: new() accepts custom clickCount for triple-click
function TestInputEvent:test_new_accepts_triple_click()
local event = InputEvent.new({
type = "click",
button = 1,
x = 0,
y = 0,
clickCount = 3,
modifiers = { shift = false, ctrl = false, alt = false, super = false },
})
luaunit.assertEquals(event.clickCount, 3)
end
-- Test: new() defaults timestamp to current time if not provided
function TestInputEvent:test_new_defaults_timestamp()
local before = love.timer.getTime()
local event = InputEvent.new({
type = "click",
button = 1,
x = 0,
y = 0,
modifiers = { shift = false, ctrl = false, alt = false, super = false },
})
local after = love.timer.getTime()
luaunit.assertNotNil(event.timestamp)
luaunit.assertTrue(event.timestamp >= before)
luaunit.assertTrue(event.timestamp <= after)
end
-- Test: new() accepts custom timestamp
function TestInputEvent:test_new_accepts_custom_timestamp()
local customTime = 12345.678
local event = InputEvent.new({
type = "click",
button = 1,
x = 0,
y = 0,
timestamp = customTime,
modifiers = { shift = false, ctrl = false, alt = false, super = false },
})
luaunit.assertEquals(event.timestamp, customTime)
end
-- Test: new() handles all modifier keys
function TestInputEvent:test_new_handles_all_modifier_keys()
local event = InputEvent.new({
type = "click",
button = 1,
x = 0,
y = 0,
modifiers = { shift = true, ctrl = true, alt = true, super = true },
})
luaunit.assertEquals(event.modifiers.shift, true)
luaunit.assertEquals(event.modifiers.ctrl, true)
luaunit.assertEquals(event.modifiers.alt, true)
luaunit.assertEquals(event.modifiers.super, true)
end
-- Test: new() handles nil dx/dy for non-drag events
function TestInputEvent:test_new_handles_nil_deltas()
local event = InputEvent.new({
type = "click",
button = 1,
x = 100,
y = 100,
modifiers = { shift = false, ctrl = false, alt = false, super = false },
})
luaunit.assertNil(event.dx)
luaunit.assertNil(event.dy)
end
if not _G.RUNNING_ALL_TESTS then
os.exit(luaunit.LuaUnit.run())
end

View File

@@ -16,7 +16,7 @@ function TestLayoutEdgeCases:setUp()
self.warnings = {}
self.originalWarn = ErrorHandler.warn
ErrorHandler.warn = function(module, message)
table.insert(self.warnings, {module = module, message = message})
table.insert(self.warnings, { module = module, message = message })
end
end
@@ -35,14 +35,14 @@ function TestLayoutEdgeCases:test_percentage_width_with_auto_parent_warns()
-- width not specified - auto-sizing width
height = 200,
positioning = "flex",
flexDirection = "horizontal"
flexDirection = "horizontal",
})
FlexLove.new({
id = "child_with_percentage",
parent = container,
width = "50%", -- Percentage width with auto-sizing parent - should warn
height = 100
width = "50%", -- Percentage width with auto-sizing parent - should warn
height = 100,
})
FlexLove.endFrame()
@@ -71,14 +71,14 @@ function TestLayoutEdgeCases:test_percentage_height_with_auto_parent_warns()
width = 200,
-- height not specified - auto-sizing height
positioning = "flex",
flexDirection = "vertical"
flexDirection = "vertical",
})
FlexLove.new({
id = "child_with_percentage",
parent = container,
width = 100,
height = "50%" -- Percentage height with auto-sizing parent - should warn
height = "50%", -- Percentage height with auto-sizing parent - should warn
})
FlexLove.endFrame()
@@ -107,14 +107,14 @@ function TestLayoutEdgeCases:test_pixel_width_with_auto_parent_no_warn()
-- width not specified - auto-sizing
height = 200,
positioning = "flex",
flexDirection = "horizontal"
flexDirection = "horizontal",
})
FlexLove.new({
id = "child_with_pixels",
parent = container,
width = 100, -- Pixel width - should NOT warn
height = 100
width = 100, -- Pixel width - should NOT warn
height = 100,
})
FlexLove.endFrame()
@@ -135,17 +135,17 @@ function TestLayoutEdgeCases:test_css_positioning_top_offset()
y = 100,
width = 400,
height = 400,
positioning = "absolute"
positioning = "absolute",
})
local child = FlexLove.new({
id = "child",
parent = container,
positioning = "absolute",
top = 50, -- 50px from top
top = 50, -- 50px from top
left = 0,
width = 100,
height = 100
height = 100,
})
-- Trigger layout by ending and restarting frame
@@ -165,17 +165,17 @@ function TestLayoutEdgeCases:test_css_positioning_bottom_offset()
y = 100,
width = 400,
height = 400,
positioning = "absolute"
positioning = "absolute",
})
local child = FlexLove.new({
id = "child",
parent = container,
positioning = "absolute",
bottom = 50, -- 50px from bottom
bottom = 50, -- 50px from bottom
left = 0,
width = 100,
height = 100
height = 100,
})
FlexLove.endFrame()
@@ -194,7 +194,7 @@ function TestLayoutEdgeCases:test_css_positioning_left_offset()
y = 100,
width = 400,
height = 400,
positioning = "absolute"
positioning = "absolute",
})
local child = FlexLove.new({
@@ -202,9 +202,9 @@ function TestLayoutEdgeCases:test_css_positioning_left_offset()
parent = container,
positioning = "absolute",
top = 0,
left = 50, -- 50px from left
left = 50, -- 50px from left
width = 100,
height = 100
height = 100,
})
FlexLove.endFrame()
@@ -223,7 +223,7 @@ function TestLayoutEdgeCases:test_css_positioning_right_offset()
y = 100,
width = 400,
height = 400,
positioning = "absolute"
positioning = "absolute",
})
local child = FlexLove.new({
@@ -231,9 +231,9 @@ function TestLayoutEdgeCases:test_css_positioning_right_offset()
parent = container,
positioning = "absolute",
top = 0,
right = 50, -- 50px from right
right = 50, -- 50px from right
width = 100,
height = 100
height = 100,
})
FlexLove.endFrame()
@@ -252,7 +252,7 @@ function TestLayoutEdgeCases:test_css_positioning_top_and_bottom()
y = 100,
width = 400,
height = 400,
positioning = "absolute"
positioning = "absolute",
})
local child = FlexLove.new({
@@ -260,10 +260,10 @@ function TestLayoutEdgeCases:test_css_positioning_top_and_bottom()
parent = container,
positioning = "absolute",
top = 10,
bottom = 20, -- Both specified - last one wins in current implementation
bottom = 20, -- Both specified - last one wins in current implementation
left = 0,
width = 100,
height = 100
height = 100,
})
FlexLove.endFrame()
@@ -282,7 +282,7 @@ function TestLayoutEdgeCases:test_css_positioning_left_and_right()
y = 100,
width = 400,
height = 400,
positioning = "absolute"
positioning = "absolute",
})
local child = FlexLove.new({
@@ -291,9 +291,9 @@ function TestLayoutEdgeCases:test_css_positioning_left_and_right()
positioning = "absolute",
top = 0,
left = 10,
right = 20, -- Both specified - last one wins in current implementation
right = 20, -- Both specified - last one wins in current implementation
width = 100,
height = 100
height = 100,
})
FlexLove.endFrame()
@@ -313,7 +313,7 @@ function TestLayoutEdgeCases:test_css_positioning_with_padding()
width = 400,
height = 400,
padding = { top = 20, right = 20, bottom = 20, left = 20 },
positioning = "absolute"
positioning = "absolute",
})
local child = FlexLove.new({
@@ -323,7 +323,7 @@ function TestLayoutEdgeCases:test_css_positioning_with_padding()
top = 10,
left = 10,
width = 100,
height = 100
height = 100,
})
FlexLove.endFrame()
@@ -346,16 +346,16 @@ function TestLayoutEdgeCases:test_css_positioning_ignored_in_flex()
width = 400,
height = 400,
positioning = "flex",
flexDirection = "horizontal"
flexDirection = "horizontal",
})
local child = FlexLove.new({
id = "child",
parent = container,
top = 100, -- This should be IGNORED in flex layout
left = 100, -- This should be IGNORED in flex layout
top = 100, -- This should be IGNORED in flex layout
left = 100, -- This should be IGNORED in flex layout
width = 100,
height = 100
height = 100,
})
FlexLove.endFrame()
@@ -375,7 +375,7 @@ function TestLayoutEdgeCases:test_css_positioning_in_relative_container()
y = 100,
width = 400,
height = 400,
positioning = "relative"
positioning = "relative",
})
local child = FlexLove.new({
@@ -385,7 +385,7 @@ function TestLayoutEdgeCases:test_css_positioning_in_relative_container()
top = 30,
left = 30,
width = 100,
height = 100
height = 100,
})
FlexLove.endFrame()

View File

@@ -716,7 +716,6 @@ local function createMockElement(props)
}
end
-- Run tests if this file is executed directly
if not _G.RUNNING_ALL_TESTS then
os.exit(luaunit.LuaUnit.run())

View File

@@ -24,7 +24,7 @@ function TestOverflowDetection:test_vertical_overflow_detected()
y = 0,
width = 200,
height = 100,
overflow = "scroll"
overflow = "scroll",
})
-- Add child that exceeds container height
@@ -34,7 +34,7 @@ function TestOverflowDetection:test_vertical_overflow_detected()
x = 0,
y = 0,
width = 100,
height = 200 -- Taller than container (100)
height = 200, -- Taller than container (100)
})
-- Force layout to trigger detectOverflow
@@ -54,7 +54,7 @@ function TestOverflowDetection:test_horizontal_overflow_detected()
y = 0,
width = 100,
height = 200,
overflow = "scroll"
overflow = "scroll",
})
-- Add child that exceeds container width
@@ -63,8 +63,8 @@ function TestOverflowDetection:test_horizontal_overflow_detected()
parent = container,
x = 0,
y = 0,
width = 300, -- Wider than container (100)
height = 50
width = 300, -- Wider than container (100)
height = 50,
})
FlexLove.endFrame()
@@ -82,7 +82,7 @@ function TestOverflowDetection:test_both_axes_overflow()
y = 0,
width = 100,
height = 100,
overflow = "scroll"
overflow = "scroll",
})
-- Add child that exceeds both dimensions
@@ -92,7 +92,7 @@ function TestOverflowDetection:test_both_axes_overflow()
x = 0,
y = 0,
width = 200,
height = 200
height = 200,
})
FlexLove.endFrame()
@@ -110,7 +110,7 @@ function TestOverflowDetection:test_no_overflow_when_content_fits()
y = 0,
width = 200,
height = 200,
overflow = "scroll"
overflow = "scroll",
})
-- Add child that fits within container
@@ -120,7 +120,7 @@ function TestOverflowDetection:test_no_overflow_when_content_fits()
x = 0,
y = 0,
width = 100,
height = 100
height = 100,
})
FlexLove.endFrame()
@@ -140,7 +140,7 @@ function TestOverflowDetection:test_overflow_with_multiple_children()
height = 200,
overflow = "scroll",
positioning = "flex",
flexDirection = "vertical"
flexDirection = "vertical",
})
-- Add multiple children that together exceed container
@@ -149,7 +149,7 @@ function TestOverflowDetection:test_overflow_with_multiple_children()
id = "child_" .. i,
parent = container,
width = 150,
height = 60 -- 5 * 60 = 300, exceeds container height of 200
height = 60, -- 5 * 60 = 300, exceeds container height of 200
})
end
@@ -168,7 +168,7 @@ function TestOverflowDetection:test_overflow_with_padding()
width = 200,
height = 200,
padding = { top = 10, right = 10, bottom = 10, left = 10 },
overflow = "scroll"
overflow = "scroll",
})
-- Child that fits in container but exceeds available content area (200 - 20 = 180)
@@ -177,8 +177,8 @@ function TestOverflowDetection:test_overflow_with_padding()
parent = container,
x = 0,
y = 0,
width = 190, -- Exceeds content width (180)
height = 100
width = 190, -- Exceeds content width (180)
height = 100,
})
FlexLove.endFrame()
@@ -197,7 +197,7 @@ function TestOverflowDetection:test_overflow_with_margins()
height = 200,
positioning = "flex",
flexDirection = "horizontal",
overflow = "scroll"
overflow = "scroll",
})
-- Child with margins that contribute to overflow
@@ -207,7 +207,7 @@ function TestOverflowDetection:test_overflow_with_margins()
parent = container,
width = 180,
height = 180,
margin = { top = 5, right = 20, bottom = 5, left = 5 } -- Total width: 5+180+20=205, overflows 200px container
margin = { top = 5, right = 20, bottom = 5, left = 5 }, -- Total width: 5+180+20=205, overflows 200px container
})
FlexLove.endFrame()
@@ -225,7 +225,7 @@ function TestOverflowDetection:test_visible_overflow_skips_detection()
y = 0,
width = 100,
height = 100,
overflow = "visible" -- Should not clip or calculate overflow
overflow = "visible", -- Should not clip or calculate overflow
})
-- Add oversized child
@@ -235,7 +235,7 @@ function TestOverflowDetection:test_visible_overflow_skips_detection()
x = 0,
y = 0,
width = 300,
height = 300
height = 300,
})
FlexLove.endFrame()
@@ -255,7 +255,7 @@ function TestOverflowDetection:test_empty_container_no_overflow()
y = 0,
width = 200,
height = 200,
overflow = "scroll"
overflow = "scroll",
-- No children
})
@@ -275,7 +275,7 @@ function TestOverflowDetection:test_absolute_children_ignored_in_overflow()
y = 0,
width = 200,
height = 200,
overflow = "scroll"
overflow = "scroll",
})
-- Regular child that fits
@@ -285,7 +285,7 @@ function TestOverflowDetection:test_absolute_children_ignored_in_overflow()
x = 0,
y = 0,
width = 150,
height = 150
height = 150,
})
-- Absolutely positioned child that extends beyond (should NOT cause overflow)
@@ -296,7 +296,7 @@ function TestOverflowDetection:test_absolute_children_ignored_in_overflow()
top = 0,
left = 0,
width = 400,
height = 400
height = 400,
})
FlexLove.endFrame()
@@ -316,7 +316,7 @@ function TestOverflowDetection:test_scroll_clamped_to_max()
y = 0,
width = 100,
height = 100,
overflow = "scroll"
overflow = "scroll",
})
FlexLove.new({
@@ -325,7 +325,7 @@ function TestOverflowDetection:test_scroll_clamped_to_max()
x = 0,
y = 0,
width = 100,
height = 300 -- Creates 200px of vertical overflow
height = 300, -- Creates 200px of vertical overflow
})
FlexLove.endFrame()

View File

@@ -0,0 +1,396 @@
-- Test suite for TextEditor module
package.path = package.path .. ";./?.lua;./modules/?.lua"
require("testing.loveStub")
local luaunit = require("testing.luaunit")
local TextEditor = require("modules.TextEditor")
local Color = require("modules.Color")
local utils = require("modules.utils")
TestTextEditor = {}
-- Mock dependencies
local MockContext = {
_immediateMode = false,
_focusedElement = nil,
}
local MockStateManager = {
getState = function(id)
return nil
end,
saveState = function(id, state) end,
}
-- Helper to create TextEditor with dependencies
local function createTextEditor(config)
config = config or {}
return TextEditor.new(config, {
Context = MockContext,
StateManager = MockStateManager,
Color = Color,
utils = utils,
})
end
-- Helper to create mock element
local function createMockElement()
return {
_stateId = "test-element-1",
width = 200,
height = 30,
}
end
-- Test: new() creates instance with defaults
function TestTextEditor:test_new_creates_with_defaults()
local editor = createTextEditor()
luaunit.assertNotNil(editor)
luaunit.assertFalse(editor.editable)
luaunit.assertFalse(editor.multiline)
luaunit.assertFalse(editor.passwordMode)
luaunit.assertEquals(editor.inputType, "text")
luaunit.assertEquals(editor._textBuffer, "")
luaunit.assertEquals(editor._cursorPosition, 0)
luaunit.assertFalse(editor._focused)
end
-- Test: new() accepts configuration
function TestTextEditor:test_new_accepts_config()
local editor = createTextEditor({
editable = true,
multiline = true,
passwordMode = true,
text = "Hello",
placeholder = "Enter text",
maxLength = 100,
inputType = "email",
})
luaunit.assertTrue(editor.editable)
luaunit.assertTrue(editor.multiline)
luaunit.assertTrue(editor.passwordMode)
luaunit.assertEquals(editor._textBuffer, "Hello")
luaunit.assertEquals(editor.placeholder, "Enter text")
luaunit.assertEquals(editor.maxLength, 100)
luaunit.assertEquals(editor.inputType, "email")
end
-- Test: new() sanitizes initial text
function TestTextEditor:test_new_sanitizes_initial_text()
local editor = createTextEditor({
text = "Hello\n\nWorld",
multiline = false,
allowNewlines = false,
})
-- Newlines should be removed for single-line
luaunit.assertNotEquals(editor._textBuffer, "Hello\n\nWorld")
end
-- Test: initialize() sets element reference
function TestTextEditor:test_initialize_sets_element()
local editor = createTextEditor()
local element = createMockElement()
editor:initialize(element)
luaunit.assertEquals(editor._element, element)
end
-- Test: getText() returns current text
function TestTextEditor:test_getText_returns_text()
local editor = createTextEditor({ text = "Hello World" })
luaunit.assertEquals(editor:getText(), "Hello World")
end
-- Test: getText() returns empty string for nil buffer
function TestTextEditor:test_getText_returns_empty_for_nil()
local editor = createTextEditor()
editor._textBuffer = nil
luaunit.assertEquals(editor:getText(), "")
end
-- Test: setText() updates text buffer
function TestTextEditor:test_setText_updates_buffer()
local editor = createTextEditor()
editor:setText("New text")
luaunit.assertEquals(editor:getText(), "New text")
end
-- Test: setText() sanitizes text by default
function TestTextEditor:test_setText_sanitizes()
local editor = createTextEditor({
multiline = false,
allowNewlines = false,
})
editor:setText("Line1\nLine2")
-- Should remove newlines for single-line
local text = editor:getText()
luaunit.assertFalse(text:find("\n") ~= nil)
end
-- Test: setText() skips sanitization when requested
function TestTextEditor:test_setText_skips_sanitization()
local editor = createTextEditor({
multiline = false,
allowNewlines = false,
})
editor:setText("Line1\nLine2", true) -- skipSanitization = true
luaunit.assertEquals(editor:getText(), "Line1\nLine2")
end
-- Test: insertText() adds text at position
function TestTextEditor:test_insertText_at_position()
local editor = createTextEditor({ text = "Hello" })
editor:insertText(" World", 5)
luaunit.assertEquals(editor:getText(), "Hello World")
end
-- Test: insertText() adds text at start
function TestTextEditor:test_insertText_at_start()
local editor = createTextEditor({ text = "World" })
editor:insertText("Hello ", 0)
luaunit.assertEquals(editor:getText(), "Hello World")
end
-- Test: deleteText() removes text range
function TestTextEditor:test_deleteText_removes_range()
local editor = createTextEditor({ text = "Hello World" })
editor:deleteText(5, 11) -- Remove " World"
luaunit.assertEquals(editor:getText(), "Hello")
end
-- Test: deleteText() handles reversed positions
function TestTextEditor:test_deleteText_handles_reversed()
local editor = createTextEditor({ text = "Hello World" })
editor:deleteText(11, 5) -- Reversed: should swap
luaunit.assertEquals(editor:getText(), "Hello")
end
-- Test: replaceText() replaces range with new text
function TestTextEditor:test_replaceText_replaces_range()
local editor = createTextEditor({ text = "Hello World" })
editor:replaceText(6, 11, "Lua")
luaunit.assertEquals(editor:getText(), "Hello Lua")
end
-- Test: setCursorPosition() sets cursor
function TestTextEditor:test_setCursorPosition()
local editor = createTextEditor({ text = "Hello" })
editor:setCursorPosition(3)
luaunit.assertEquals(editor:getCursorPosition(), 3)
end
-- Test: setCursorPosition() clamps to valid range
function TestTextEditor:test_setCursorPosition_clamps()
local editor = createTextEditor({ text = "Hello" })
editor:setCursorPosition(100) -- Beyond text length
luaunit.assertEquals(editor:getCursorPosition(), 5)
end
-- Test: moveCursorBy() moves cursor relative
function TestTextEditor:test_moveCursorBy()
local editor = createTextEditor({ text = "Hello" })
editor:setCursorPosition(2)
editor:moveCursorBy(2)
luaunit.assertEquals(editor:getCursorPosition(), 4)
end
-- Test: moveCursorToStart() moves to beginning
function TestTextEditor:test_moveCursorToStart()
local editor = createTextEditor({ text = "Hello" })
editor:setCursorPosition(3)
editor:moveCursorToStart()
luaunit.assertEquals(editor:getCursorPosition(), 0)
end
-- Test: moveCursorToEnd() moves to end
function TestTextEditor:test_moveCursorToEnd()
local editor = createTextEditor({ text = "Hello" })
editor:moveCursorToEnd()
luaunit.assertEquals(editor:getCursorPosition(), 5)
end
-- Test: setSelection() sets selection range
function TestTextEditor:test_setSelection()
local editor = createTextEditor({ text = "Hello World" })
editor:setSelection(0, 5)
local start, endPos = editor:getSelection()
luaunit.assertEquals(start, 0)
luaunit.assertEquals(endPos, 5)
end
-- Test: hasSelection() returns true when selected
function TestTextEditor:test_hasSelection_true()
local editor = createTextEditor({ text = "Hello" })
editor:setSelection(0, 5)
luaunit.assertTrue(editor:hasSelection())
end
-- Test: hasSelection() returns false when no selection
function TestTextEditor:test_hasSelection_false()
local editor = createTextEditor({ text = "Hello" })
luaunit.assertFalse(editor:hasSelection())
end
-- Test: clearSelection() removes selection
function TestTextEditor:test_clearSelection()
local editor = createTextEditor({ text = "Hello" })
editor:setSelection(0, 5)
editor:clearSelection()
luaunit.assertFalse(editor:hasSelection())
end
-- Test: getSelectedText() returns selected text
function TestTextEditor:test_getSelectedText()
local editor = createTextEditor({ text = "Hello World" })
editor:setSelection(0, 5)
luaunit.assertEquals(editor:getSelectedText(), "Hello")
end
-- Test: deleteSelection() removes selected text
function TestTextEditor:test_deleteSelection()
local editor = createTextEditor({ text = "Hello World" })
editor:setSelection(0, 6)
editor:deleteSelection()
luaunit.assertEquals(editor:getText(), "World")
luaunit.assertFalse(editor:hasSelection())
end
-- Test: selectAll() selects entire text
function TestTextEditor:test_selectAll()
local editor = createTextEditor({ text = "Hello World" })
editor:selectAll()
local start, endPos = editor:getSelection()
luaunit.assertEquals(start, 0)
luaunit.assertEquals(endPos, 11)
end
-- Test: sanitization with maxLength
function TestTextEditor:test_sanitize_max_length()
local editor = createTextEditor({
maxLength = 5,
})
editor:setText("HelloWorld")
luaunit.assertEquals(editor:getText(), "Hello")
end
-- Test: sanitization disabled
function TestTextEditor:test_sanitization_disabled()
local editor = createTextEditor({
sanitize = false,
multiline = false,
allowNewlines = false,
})
editor:setText("Line1\nLine2")
-- Should NOT sanitize newlines when disabled
luaunit.assertEquals(editor:getText(), "Line1\nLine2")
end
-- Test: customSanitizer callback
function TestTextEditor:test_custom_sanitizer()
local editor = createTextEditor({
customSanitizer = function(text)
return text:upper()
end,
})
editor:setText("hello")
luaunit.assertEquals(editor:getText(), "HELLO")
end
-- Test: allowNewlines follows multiline setting
function TestTextEditor:test_allowNewlines_follows_multiline()
local editor = createTextEditor({
multiline = true,
})
luaunit.assertTrue(editor.allowNewlines)
editor = createTextEditor({
multiline = false,
})
luaunit.assertFalse(editor.allowNewlines)
end
-- Test: allowNewlines can be overridden
function TestTextEditor:test_allowNewlines_override()
local editor = createTextEditor({
multiline = true,
allowNewlines = false,
})
luaunit.assertFalse(editor.allowNewlines)
end
-- Test: allowTabs defaults to true
function TestTextEditor:test_allowTabs_default()
local editor = createTextEditor()
luaunit.assertTrue(editor.allowTabs)
end
-- Test: cursorBlinkRate default
function TestTextEditor:test_cursorBlinkRate_default()
local editor = createTextEditor()
luaunit.assertEquals(editor.cursorBlinkRate, 0.5)
end
-- Test: selectOnFocus default
function TestTextEditor:test_selectOnFocus_default()
local editor = createTextEditor()
luaunit.assertFalse(editor.selectOnFocus)
end
if not _G.RUNNING_ALL_TESTS then
os.exit(luaunit.LuaUnit.run())
end

View File

@@ -17,17 +17,25 @@ local luaunit = require("testing.luaunit")
-- Run all tests in the __tests__ directory
local testFiles = {
"testing/__tests__/utils_test.lua",
"testing/__tests__/units_test.lua",
"testing/__tests__/animation_test.lua",
"testing/__tests__/color_validation_test.lua",
"testing/__tests__/element_test.lua",
"testing/__tests__/error_handler_test.lua",
"testing/__tests__/event_handler_test.lua",
"testing/__tests__/grid_test.lua",
"testing/__tests__/image_cache_test.lua",
"testing/__tests__/image_renderer_test.lua",
"testing/__tests__/image_scaler_test.lua",
"testing/__tests__/input_event_test.lua",
"testing/__tests__/layout_edge_cases_test.lua",
"testing/__tests__/layout_engine_test.lua",
"testing/__tests__/overflow_test.lua",
"testing/__tests__/path_validation_test.lua",
"testing/__tests__/sanitization_test.lua",
"testing/__tests__/text_editor_test.lua",
"testing/__tests__/theme_test.lua",
"testing/__tests__/layout_engine_test.lua",
"testing/__tests__/element_test.lua",
"testing/__tests__/overflow_test.lua",
"testing/__tests__/grid_test.lua",
"testing/__tests__/layout_edge_cases_test.lua",
"testing/__tests__/units_test.lua",
"testing/__tests__/utils_test.lua",
}
local success = true