diff --git a/LICENSE b/LICENSE index da6215f..3ecc9b3 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 Maxim Tuprikov +Copyright (c) 2025 Maxim Tuprikov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index c8f4669..f59de4d 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,12 @@ In this example you can inspect a variety of **Druid** components and see how th - **Input Handling** - Handles input in a stack-based manner and manage input priority - **Event Based** - Uses [Defold Event](https://github.com/Insality/defold-event) for components callbacks and communication between components +## Quick Links + +- [Basic Usage](wiki/basic_usage.md) +- [Quick API Reference](api/quick_api_reference.md) +- [List of Components](#druid-components) +- [Contributors](#contributors) ## Setup ### [Dependency](https://defold.com/manuals/libraries/#setting-up-library-dependencies) @@ -121,7 +127,7 @@ Here is full **Druid** components list. | **[Back Handler](/api/components/base/back_handler_api.md)** | Call callback on user "Back" action. It's a Android back button or keyboard backspace key | [Back Handler Example](https://insality.github.io/druid/?example=ui_example_basic_back_handler) | | | **[Static Grid](/api/components/base/static_grid_api.md)** | Logic over GUI Node. Component to manage node positions with all equal node sizes. | [Static Gid Example](https://insality.github.io/druid/?example=ui_example_basic_grid) | | | **[Hover](/api/components/base/hover_api.md)** | Logic over GUI Node. Handle hover action over node. For both: mobile touch and mouse cursor. | [Hover Example](https://insality.github.io/druid/?example=ui_example_basic_hover) | | -| **[Swipe](/api/components/base/swipe_api.md)** | Logic over GUI Node. Handle swipe gestures over node. | [Swipe Example](https://insality.github.io/druid/?example=ui_example_basic_swipe) | | +| **[Swipe](/api/components/extended/swipe_api.md)** | Logic over GUI Node. Handle swipe gestures over node. | [Swipe Example](https://insality.github.io/druid/?example=ui_example_basic_swipe) | | | **[Drag](/api/components/base/drag_api.md)** | Logic over GUI Node. Handle drag input actions. Can be useful to make on screen controlls. | [Drag Example](https://insality.github.io/druid/?example=ui_example_basic_drag) | | | **[Data List](/api/components/extended/data_list_api.md)** | Logic over Scroll and Grid components. Create only visible GUI nodes or components to make "infinity" scroll befaviour | [Data List Example](https://insality.github.io/druid/?example=ui_example_data_list_basic) | | | **[Input](/api/components/extended/input_api.md)** | Logic over GUI Node and GUI Text (or Text component). Provides basic user text input. | [Input Example](https://insality.github.io/druid/?example=ui_example_basic_input) | | @@ -137,7 +143,7 @@ Here is full **Druid** components list. ## Druid Events -All **Druid** components using [Defold Event](https://github.com/Insality/defold-event) for components callbacks. In component API ([button example](https://insality.github.io/druid/modules/Button.html#on_click)) pointed list of component events. You can manually subscribe to these events with the following API: +All **Druid** components using [Defold Event](https://github.com/Insality/defold-event) for components callbacks. In component API ([button example](/api/components/base/button_api.md#fields)) pointed list of component events. You can manually subscribe to these events with the following API: - **event:subscribe**(callback) @@ -187,8 +193,10 @@ To better understand **Druid**, read the following documentation: - [How To GUI in Defold](https://forum.defold.com/t/how-to-gui-in-defold/73256) - [Widgets](wiki/widgets.md) -- [Create custom components](wiki/creating_custom_components.md) - [Druid styles](wiki/styles.md) +- [Advanced Setup](wiki/advanced-setup.md) +- [Optimize Druid Size](wiki/optimize_druid_size.md) +- [Changelog](wiki/changelog.md) ## Licenses @@ -198,16 +206,16 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file ## Issues and suggestions -If you have any issues, questions or suggestions please [create an issue](https://github.com/Insality/druid/issues) or contact me: [insality@gmail.com](mailto:insality@gmail.com) +If you have any issues, questions or suggestions please [create an issue](https://github.com/Insality/druid/issues) ## History For a complete history of the development of **Druid**, please check the [changelog](docs_md/changelog.md). -## 👏 Contributors +## Contributors -Original idea by [AGulev](https://github.com/AGulev) +Original Druid idea by [AGulev](https://github.com/AGulev) Special thanks to all the contributors who have helped make **Druid** better! diff --git a/test/helper/mock_input.lua b/test/helper/mock_input.lua index 27e575c..4c64010 100644 --- a/test/helper/mock_input.lua +++ b/test/helper/mock_input.lua @@ -58,5 +58,11 @@ function M.input_empty_action_nil(x, y) end +function M.input_text(text) + return hash("text"), { + text = text, + } +end + return M diff --git a/test/helper/test_helper.lua b/test/helper/test_helper.lua deleted file mode 100644 index 11b027e..0000000 --- a/test/helper/test_helper.lua +++ /dev/null @@ -1,20 +0,0 @@ -local mock = require("deftest.mock.mock") - -local M = {} - --- Userdata type instead of script self ----@return vector -function M.get_context() - return vmath.vector({}) -end - - --- Callback for return value from function -function M.get_function(callback) - local listener = {} - listener.callback = function(...) if callback then return callback(...) end end - mock.mock(listener) - return function(...) return listener.callback(...) end, listener.callback -end - -return M diff --git a/test/tests/test_druid_instance.lua b/test/tests/test_druid_instance.lua index ebe1e02..62c8039 100644 --- a/test/tests/test_druid_instance.lua +++ b/test/tests/test_druid_instance.lua @@ -1,306 +1,306 @@ return function() - describe("Druid Instance", function() - local druid - local druid_instance ---@type druid.instance - local context + describe("Druid Instance", function() + local druid + local druid_instance ---@type druid.instance + local context local mock_input = require("test.helper.mock_input") - before(function() - context = vmath.vector3() - druid = require("druid.druid") - druid_instance = druid.new(context) - end) + before(function() + context = vmath.vector3() + druid = require("druid.druid") + druid_instance = druid.new(context) + end) - after(function() - -- Clean up druid instance - if druid_instance then - druid_instance:final() - druid_instance = nil - end - end) + after(function() + -- Clean up druid instance + if druid_instance then + druid_instance:final() + druid_instance = nil + end + end) - it("Should create button component", function() - local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0)) + it("Should create button component", function() + local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0)) - local on_click_calls = 0 - local function on_click() - on_click_calls = on_click_calls + 1 - end + local on_click_calls = 0 + local function on_click() + on_click_calls = on_click_calls + 1 + end - local button = druid_instance:new_button(button_node, on_click) + local button = druid_instance:new_button(button_node, on_click) - assert(button ~= nil) - assert(button.node == button_node) + assert(button ~= nil) + assert(button.node == button_node) - -- Test that button click works - druid_instance:on_input(mock_input.click_pressed(50, 25)) - druid_instance:on_input(mock_input.click_released(50, 25)) + -- Test that button click works + druid_instance:on_input(mock_input.click_pressed(50, 25)) + druid_instance:on_input(mock_input.click_released(50, 25)) - assert(on_click_calls == 1) + assert(on_click_calls == 1) - -- Clean up component - druid_instance:remove(button) - gui.delete_node(button_node) - end) + -- Clean up component + druid_instance:remove(button) + gui.delete_node(button_node) + end) - it("Should create blocker component", function() - local blocker_node = gui.new_box_node(vmath.vector3(100, 50, 0), vmath.vector3(200, 100, 0)) + it("Should create blocker component", function() + local blocker_node = gui.new_box_node(vmath.vector3(100, 50, 0), vmath.vector3(200, 100, 0)) - local blocker = druid_instance:new_blocker(blocker_node) + local blocker = druid_instance:new_blocker(blocker_node) - assert(blocker ~= nil) - assert(blocker.node == blocker_node) + assert(blocker ~= nil) + assert(blocker.node == blocker_node) - -- Test that blocker blocks input - local is_blocked = druid_instance:on_input(mock_input.click_pressed(100, 50)) + -- Test that blocker blocks input + local is_blocked = druid_instance:on_input(mock_input.click_pressed(100, 50)) - assert(is_blocked) + assert(is_blocked) - -- Clean up component - druid_instance:remove(blocker) - gui.delete_node(blocker_node) - end) + -- Clean up component + druid_instance:remove(blocker) + gui.delete_node(blocker_node) + end) - it("Should create back_handler component", function() - local on_back_calls = 0 - local function on_back() - on_back_calls = on_back_calls + 1 - end + it("Should create back_handler component", function() + local on_back_calls = 0 + local function on_back() + on_back_calls = on_back_calls + 1 + end - local back_handler = druid_instance:new_back_handler(on_back) + local back_handler = druid_instance:new_back_handler(on_back) - assert(back_handler ~= nil) + assert(back_handler ~= nil) - -- Test that back handler works - druid_instance:on_input(mock_input.key_pressed("key_back")) - druid_instance:on_input(mock_input.key_released("key_back")) + -- Test that back handler works + druid_instance:on_input(mock_input.key_pressed("key_back")) + druid_instance:on_input(mock_input.key_released("key_back")) - assert(on_back_calls == 1) + assert(on_back_calls == 1) - -- Clean up component - druid_instance:remove(back_handler) - end) + -- Clean up component + druid_instance:remove(back_handler) + end) - it("Should create hover component", function() - local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0)) + it("Should create hover component", function() + local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0)) - local on_hover_calls = 0 - local function on_hover() - on_hover_calls = on_hover_calls + 1 - end + local on_hover_calls = 0 + local function on_hover() + on_hover_calls = on_hover_calls + 1 + end - local hover = druid_instance:new_hover(button_node, on_hover) + local hover = druid_instance:new_hover(button_node, on_hover) - assert(hover ~= nil) - assert(hover.node == button_node) + assert(hover ~= nil) + assert(hover.node == button_node) - -- Test that hover works - druid_instance:on_input(mock_input.input_empty(50, 25)) + -- Test that hover works + druid_instance:on_input(mock_input.input_empty(50, 25)) - assert(on_hover_calls == 1) + assert(on_hover_calls == 1) - -- Clean up component - druid_instance:remove(hover) - gui.delete_node(button_node) - end) + -- Clean up component + druid_instance:remove(hover) + gui.delete_node(button_node) + end) - it("Should create text component", function() - local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Test Text") - gui.set_font(text_node, "druid_text_bold") + it("Should create text component", function() + local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Test Text") + gui.set_font(text_node, "druid_text_bold") - local text = druid_instance:new_text(text_node, "New Text") + local text = druid_instance:new_text(text_node, "New Text") - assert(text ~= nil) - assert(text.node == text_node) - assert(gui.get_text(text_node) == "New Text") + assert(text ~= nil) + assert(text.node == text_node) + assert(gui.get_text(text_node) == "New Text") - -- Test that text setter works - text:set_text("Updated Text") - assert(gui.get_text(text_node) == "Updated Text") + -- Test that text setter works + text:set_text("Updated Text") + assert(gui.get_text(text_node) == "Updated Text") - -- Clean up component - druid_instance:remove(text) - gui.delete_node(text_node) - end) + -- Clean up component + druid_instance:remove(text) + gui.delete_node(text_node) + end) - it("Should create grid component", function() - local parent_node = gui.new_box_node(vmath.vector3(150, 100, 0), vmath.vector3(300, 200, 0)) - local template = gui.new_box_node(vmath.vector3(10, 10, 0), vmath.vector3(20, 20, 0)) + it("Should create grid component", function() + local parent_node = gui.new_box_node(vmath.vector3(150, 100, 0), vmath.vector3(300, 200, 0)) + local template = gui.new_box_node(vmath.vector3(10, 10, 0), vmath.vector3(20, 20, 0)) - local grid = druid_instance:new_grid(parent_node, template, 3) + local grid = druid_instance:new_grid(parent_node, template, 3) - assert(grid ~= nil) - assert(grid.parent == parent_node) - assert(grid.in_row == 3) + assert(grid ~= nil) + assert(grid.parent == parent_node) + assert(grid.in_row == 3) - -- Add an item to the grid - local item = gui.clone(template) - grid:add(item) - assert(#grid.nodes == 1) + -- Add an item to the grid + local item = gui.clone(template) + grid:add(item) + assert(#grid.nodes == 1) - -- Clean up component - druid_instance:remove(grid) - gui.delete_node(parent_node) - gui.delete_node(template) - end) + -- Clean up component + druid_instance:remove(grid) + gui.delete_node(parent_node) + gui.delete_node(template) + end) - it("Should create scroll component", function() - local parent_node = gui.new_box_node(vmath.vector3(150, 100, 0), vmath.vector3(300, 200, 0)) - local content_node = gui.new_box_node(vmath.vector3(250, 200, 0), vmath.vector3(500, 400, 0)) + it("Should create scroll component", function() + local parent_node = gui.new_box_node(vmath.vector3(150, 100, 0), vmath.vector3(300, 200, 0)) + local content_node = gui.new_box_node(vmath.vector3(250, 200, 0), vmath.vector3(500, 400, 0)) - -- Setup node hierarchy for scroll - gui.set_parent(content_node, parent_node) + -- Setup node hierarchy for scroll + gui.set_parent(content_node, parent_node) - local scroll = druid_instance:new_scroll(parent_node, content_node) + local scroll = druid_instance:new_scroll(parent_node, content_node) - assert(scroll ~= nil) - assert(scroll.view_node == parent_node) - assert(scroll.content_node == content_node) + assert(scroll ~= nil) + assert(scroll.view_node == parent_node) + assert(scroll.content_node == content_node) - -- Test that scroll setters work - scroll:set_horizontal_scroll(true) + -- Test that scroll setters work + scroll:set_horizontal_scroll(true) - -- Clean up component - druid_instance:remove(scroll) - gui.delete_node(parent_node) -- This will also delete content_node as it's a child - end) + -- Clean up component + druid_instance:remove(scroll) + gui.delete_node(parent_node) -- This will also delete content_node as it's a child + end) - it("Should create drag component", function() - local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0)) + it("Should create drag component", function() + local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0)) - local on_drag_calls = 0 - local drag_dx, drag_dy + local on_drag_calls = 0 + local drag_dx, drag_dy - local function on_drag(_, dx, dy) - on_drag_calls = on_drag_calls + 1 - drag_dx, drag_dy = dx, dy - end + local function on_drag(_, dx, dy) + on_drag_calls = on_drag_calls + 1 + drag_dx, drag_dy = dx, dy + end - local drag = druid_instance:new_drag(button_node, on_drag) + local drag = druid_instance:new_drag(button_node, on_drag) drag.style.DRAG_DEADZONE = 0 - assert(drag ~= nil) - assert(drag.node == button_node) + assert(drag ~= nil) + assert(drag.node == button_node) - -- Test that drag callback works - druid_instance:on_input(mock_input.click_pressed(50, 25)) + -- Test that drag callback works + druid_instance:on_input(mock_input.click_pressed(50, 25)) druid_instance:on_input(mock_input.input_empty(60, 35)) - druid_instance:on_input(mock_input.click_released(60, 35)) + druid_instance:on_input(mock_input.click_released(60, 35)) print(drag_dx, drag_dy) - assert(on_drag_calls == 1) - assert(math.floor(drag_dx) == 10) - assert(math.floor(drag_dy) == 10) + assert(on_drag_calls == 1) + assert(math.floor(drag_dx) == 10) + assert(math.floor(drag_dy) == 10) - -- Clean up component - druid_instance:remove(drag) - gui.delete_node(button_node) - end) + -- Clean up component + druid_instance:remove(drag) + gui.delete_node(button_node) + end) - it("Should create swipe component", function() - local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0)) + it("Should create swipe component", function() + local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0)) - local on_swipe_calls = 0 - local function on_swipe() - on_swipe_calls = on_swipe_calls + 1 - end + local on_swipe_calls = 0 + local function on_swipe() + on_swipe_calls = on_swipe_calls + 1 + end - local swipe = druid_instance:new_swipe(button_node, on_swipe) + local swipe = druid_instance:new_swipe(button_node, on_swipe) - assert(swipe ~= nil) - assert(swipe.node == button_node) + assert(swipe ~= nil) + assert(swipe.node == button_node) - -- Clean up component - druid_instance:remove(swipe) - gui.delete_node(button_node) - end) + -- Clean up component + druid_instance:remove(swipe) + gui.delete_node(button_node) + end) - it("Should create timer component", function() - local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Test Text") - gui.set_font(text_node, "druid_text_bold") + it("Should create timer component", function() + local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Test Text") + gui.set_font(text_node, "druid_text_bold") - local on_timer_end_calls = 0 - local function on_timer_end() - on_timer_end_calls = on_timer_end_calls + 1 - end + local on_timer_end_calls = 0 + local function on_timer_end() + on_timer_end_calls = on_timer_end_calls + 1 + end - local timer = druid_instance:new_timer(text_node, 10, 0, on_timer_end) + local timer = druid_instance:new_timer(text_node, 10, 0, on_timer_end) - assert(timer ~= nil) - assert(timer.node == text_node) + assert(timer ~= nil) + assert(timer.node == text_node) - -- Clean up component - druid_instance:remove(timer) - gui.delete_node(text_node) - end) + -- Clean up component + druid_instance:remove(timer) + gui.delete_node(text_node) + end) - it("Should create progress component", function() - local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0)) + it("Should create progress component", function() + local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0)) - local progress = druid_instance:new_progress(button_node, "x", 0.5) + local progress = druid_instance:new_progress(button_node, "x", 0.5) - assert(progress ~= nil) - assert(progress.node == button_node) - assert(progress:get() == 0.5) + assert(progress ~= nil) + assert(progress.node == button_node) + assert(progress:get() == 0.5) - -- Test that progress setter works - progress:set_to(0.75) - assert(progress:get() == 0.75) + -- Test that progress setter works + progress:set_to(0.75) + assert(progress:get() == 0.75) - -- Clean up component - druid_instance:remove(progress) - gui.delete_node(button_node) - end) + -- Clean up component + druid_instance:remove(progress) + gui.delete_node(button_node) + end) - it("Should create layout component", function() - local parent_node = gui.new_box_node(vmath.vector3(150, 100, 0), vmath.vector3(300, 200, 0)) + it("Should create layout component", function() + local parent_node = gui.new_box_node(vmath.vector3(150, 100, 0), vmath.vector3(300, 200, 0)) - local layout = druid_instance:new_layout(parent_node) + local layout = druid_instance:new_layout(parent_node) - assert(layout ~= nil) - assert(layout.node == parent_node) + assert(layout ~= nil) + assert(layout.node == parent_node) - -- Clean up component - druid_instance:remove(layout) - gui.delete_node(parent_node) - end) + -- Clean up component + druid_instance:remove(layout) + gui.delete_node(parent_node) + end) - it("Should create hotkey component", function() - local on_hotkey_calls = 0 - local function on_hotkey() - on_hotkey_calls = on_hotkey_calls + 1 - end + it("Should create hotkey component", function() + local on_hotkey_calls = 0 + local function on_hotkey() + on_hotkey_calls = on_hotkey_calls + 1 + end - local hotkey = druid_instance:new_hotkey("key_f", on_hotkey) + local hotkey = druid_instance:new_hotkey("key_f", on_hotkey) - assert(hotkey ~= nil) + assert(hotkey ~= nil) - -- Test that hotkey works - druid_instance:on_input(mock_input.key_pressed("key_f")) - druid_instance:on_input(mock_input.key_released("key_f")) + -- Test that hotkey works + druid_instance:on_input(mock_input.key_pressed("key_f")) + druid_instance:on_input(mock_input.key_released("key_f")) - assert(on_hotkey_calls == 1) + assert(on_hotkey_calls == 1) - -- Clean up component - druid_instance:remove(hotkey) - end) + -- Clean up component + druid_instance:remove(hotkey) + end) - it("Should create container component", function() - local parent_node = gui.new_box_node(vmath.vector3(150, 100, 0), vmath.vector3(300, 200, 0)) + it("Should create container component", function() + local parent_node = gui.new_box_node(vmath.vector3(150, 100, 0), vmath.vector3(300, 200, 0)) - local layout_changed_calls = 0 - local function layout_changed() - layout_changed_calls = layout_changed_calls + 1 - end + local layout_changed_calls = 0 + local function layout_changed() + layout_changed_calls = layout_changed_calls + 1 + end - -- The container component requires a node with size - local container = druid_instance:new_container(parent_node, "fit") + -- The container component requires a node with size + local container = druid_instance:new_container(parent_node, "fit") - assert(container ~= nil) + assert(container ~= nil) - -- Clean up component - druid_instance:remove(container) - gui.delete_node(parent_node) - end) - end) + -- Clean up component + druid_instance:remove(container) + gui.delete_node(parent_node) + end) + end) end diff --git a/test/tests/test_helper.lua b/test/tests/test_helper.lua index 60a6724..1625222 100644 --- a/test/tests/test_helper.lua +++ b/test/tests/test_helper.lua @@ -1,275 +1,273 @@ return function() - describe("Helper Module", function() - local test_helper = nil - local helper = nil - local const = nil - local node1 = nil - local node2 = nil + describe("Helper Module", function() + local helper = nil + local const = nil + local node1 = nil + local node2 = nil - before(function() - test_helper = require("test.helper.test_helper") - helper = require("druid.helper") - const = require("druid.const") + before(function() + helper = require("druid.helper") + const = require("druid.const") - -- Create actual GUI nodes for testing - node1 = gui.new_box_node(vmath.vector3(0, 0, 0), vmath.vector3(100, 50, 0)) - node2 = gui.new_box_node(vmath.vector3(0, 0, 0), vmath.vector3(60, 40, 0)) - end) + -- Create actual GUI nodes for testing + node1 = gui.new_box_node(vmath.vector3(0, 0, 0), vmath.vector3(100, 50, 0)) + node2 = gui.new_box_node(vmath.vector3(0, 0, 0), vmath.vector3(60, 40, 0)) + end) - after(function() - -- Clean up nodes - if node1 then gui.delete_node(node1) end - if node2 then gui.delete_node(node2) end - end) + after(function() + -- Clean up nodes + if node1 then gui.delete_node(node1) end + if node2 then gui.delete_node(node2) end + end) - it("Should clamp values correctly", function() - assert(helper.clamp(5, 0, 10) == 5) - assert(helper.clamp(-5, 0, 10) == 0) - assert(helper.clamp(15, 0, 10) == 10) - assert(helper.clamp(5, 10, 0) == 5) -- Should swap min and max - assert(helper.clamp(5, nil, 10) == 5) -- Should handle nil min - assert(helper.clamp(15, nil, 10) == 10) -- Should handle nil min - assert(helper.clamp(5, 0, nil) == 5) -- Should handle nil max - assert(helper.clamp(-5, 0, nil) == 0) -- Should handle nil max - end) + it("Should clamp values correctly", function() + assert(helper.clamp(5, 0, 10) == 5) + assert(helper.clamp(-5, 0, 10) == 0) + assert(helper.clamp(15, 0, 10) == 10) + assert(helper.clamp(5, 10, 0) == 5) -- Should swap min and max + assert(helper.clamp(5, nil, 10) == 5) -- Should handle nil min + assert(helper.clamp(15, nil, 10) == 10) -- Should handle nil min + assert(helper.clamp(5, 0, nil) == 5) -- Should handle nil max + assert(helper.clamp(-5, 0, nil) == 0) -- Should handle nil max + end) - it("Should calculate distance correctly", function() - assert(helper.distance(0, 0, 3, 4) == 5) - assert(helper.distance(1, 1, 4, 5) == 5) - assert(helper.distance(0, 0, 0, 0) == 0) - end) + it("Should calculate distance correctly", function() + assert(helper.distance(0, 0, 3, 4) == 5) + assert(helper.distance(1, 1, 4, 5) == 5) + assert(helper.distance(0, 0, 0, 0) == 0) + end) - it("Should return sign correctly", function() - assert(helper.sign(5) == 1) - assert(helper.sign(-5) == -1) - assert(helper.sign(0) == 0) - end) + it("Should return sign correctly", function() + assert(helper.sign(5) == 1) + assert(helper.sign(-5) == -1) + assert(helper.sign(0) == 0) + end) - it("Should round numbers correctly", function() - assert(helper.round(5.5) == 6) - assert(helper.round(5.4) == 5) - assert(helper.round(5.55, 1) == 5.6) - assert(helper.round(5.54, 1) == 5.5) - end) + it("Should round numbers correctly", function() + assert(helper.round(5.5) == 6) + assert(helper.round(5.4) == 5) + assert(helper.round(5.55, 1) == 5.6) + assert(helper.round(5.54, 1) == 5.5) + end) - it("Should lerp correctly", function() - assert(helper.lerp(0, 10, 0) == 0) - assert(helper.lerp(0, 10, 1) == 10) - assert(helper.lerp(0, 10, 0.5) == 5) - end) + it("Should lerp correctly", function() + assert(helper.lerp(0, 10, 0) == 0) + assert(helper.lerp(0, 10, 1) == 10) + assert(helper.lerp(0, 10, 0.5) == 5) + end) - it("Should check if value is in array", function() - local array = {1, 2, 3, 4, 5} - assert(helper.contains(array, 3) == 3) - assert(helper.contains(array, 6) == nil) - assert(helper.contains({}, 1) == nil) - end) + it("Should check if value is in array", function() + local array = {1, 2, 3, 4, 5} + assert(helper.contains(array, 3) == 3) + assert(helper.contains(array, 6) == nil) + assert(helper.contains({}, 1) == nil) + end) - it("Should deep copy tables", function() - local original = {a = 1, b = {c = 2, d = {e = 3}}} - local copy = helper.deepcopy(original) + it("Should deep copy tables", function() + local original = {a = 1, b = {c = 2, d = {e = 3}}} + local copy = helper.deepcopy(original) - -- Test that it's a deep copy - assert(copy.a == original.a) - assert(copy.b.c == original.b.c) - assert(copy.b.d.e == original.b.d.e) + -- Test that it's a deep copy + assert(copy.a == original.a) + assert(copy.b.c == original.b.c) + assert(copy.b.d.e == original.b.d.e) - -- Modify the copy and check the original remains intact - copy.a = 100 - copy.b.c = 200 - copy.b.d.e = 300 + -- Modify the copy and check the original remains intact + copy.a = 100 + copy.b.c = 200 + copy.b.d.e = 300 - assert(original.a == 1) - assert(original.b.c == 2) - assert(original.b.d.e == 3) - end) + assert(original.a == 1) + assert(original.b.c == 2) + assert(original.b.d.e == 3) + end) - it("Should add all elements from source array to target array", function() - local target = {1, 2, 3} - local source = {4, 5, 6} + it("Should add all elements from source array to target array", function() + local target = {1, 2, 3} + local source = {4, 5, 6} - helper.add_array(target, source) - assert(#target == 6) - assert(target[4] == 4) - assert(target[5] == 5) - assert(target[6] == 6) + helper.add_array(target, source) + assert(#target == 6) + assert(target[4] == 4) + assert(target[5] == 5) + assert(target[6] == 6) - -- Test with nil source - local target2 = {1, 2, 3} - helper.add_array(target2, nil) - assert(#target2 == 3) - end) + -- Test with nil source + local target2 = {1, 2, 3} + helper.add_array(target2, nil) + assert(#target2 == 3) + end) - it("Should insert with shift policy correctly", function() - -- Test basic functionality - -- RIGHT shift - local array1 = {1, 2, 3, 4, 5} - local result1 = helper.insert_with_shift(array1, 10, 3, const.SHIFT.RIGHT) - assert(result1 == 10) -- Should return the inserted item - assert(#array1 == 6) -- Size should increase - assert(array1[3] == 10) -- Item should be at the specified position + it("Should insert with shift policy correctly", function() + -- Test basic functionality + -- RIGHT shift + local array1 = {1, 2, 3, 4, 5} + local result1 = helper.insert_with_shift(array1, 10, 3, const.SHIFT.RIGHT) + assert(result1 == 10) -- Should return the inserted item + assert(#array1 == 6) -- Size should increase + assert(array1[3] == 10) -- Item should be at the specified position - -- LEFT shift - local array2 = {1, 2, 3, 4, 5} - local result2 = helper.insert_with_shift(array2, 20, 3, const.SHIFT.LEFT) - assert(result2 == 20) -- Should return the inserted item - assert(#array2 >= 5) -- Size should be at least original size + -- LEFT shift + local array2 = {1, 2, 3, 4, 5} + local result2 = helper.insert_with_shift(array2, 20, 3, const.SHIFT.LEFT) + assert(result2 == 20) -- Should return the inserted item + assert(#array2 >= 5) -- Size should be at least original size - -- NO_SHIFT - local array3 = {1, 2, 3, 4, 5} - local result3 = helper.insert_with_shift(array3, 30, 3, const.SHIFT.NO_SHIFT) - assert(result3 == 30) -- Should return the inserted item - assert(array3[3] == 30) -- Should replace the value at the specified position - end) + -- NO_SHIFT + local array3 = {1, 2, 3, 4, 5} + local result3 = helper.insert_with_shift(array3, 30, 3, const.SHIFT.NO_SHIFT) + assert(result3 == 30) -- Should return the inserted item + assert(array3[3] == 30) -- Should replace the value at the specified position + end) - it("Should remove with shift policy correctly", function() - -- Test basic functionality - -- RIGHT shift - local array1 = {1, 2, 3, 4, 5} - local removed1 = helper.remove_with_shift(array1, 3, const.SHIFT.RIGHT) - assert(removed1 == 3) -- Should return the removed item - assert(#array1 == 4) -- Size should decrease + it("Should remove with shift policy correctly", function() + -- Test basic functionality + -- RIGHT shift + local array1 = {1, 2, 3, 4, 5} + local removed1 = helper.remove_with_shift(array1, 3, const.SHIFT.RIGHT) + assert(removed1 == 3) -- Should return the removed item + assert(#array1 == 4) -- Size should decrease - -- LEFT shift - local array2 = {1, 2, 3, 4, 5} - local removed2 = helper.remove_with_shift(array2, 3, const.SHIFT.LEFT) - assert(removed2 == 3) -- Should return the removed item + -- LEFT shift + local array2 = {1, 2, 3, 4, 5} + local removed2 = helper.remove_with_shift(array2, 3, const.SHIFT.LEFT) + assert(removed2 == 3) -- Should return the removed item - -- NO_SHIFT - local array3 = {1, 2, 3, 4, 5} - local removed3 = helper.remove_with_shift(array3, 3, const.SHIFT.NO_SHIFT) - assert(removed3 == 3) -- Should return the removed item - assert(array3[3] == nil) -- Position should be nil - assert(array3[1] == 1 and array3[2] == 2 and array3[4] == 4 and array3[5] == 5) -- Other positions should be unchanged - end) + -- NO_SHIFT + local array3 = {1, 2, 3, 4, 5} + local removed3 = helper.remove_with_shift(array3, 3, const.SHIFT.NO_SHIFT) + assert(removed3 == 3) -- Should return the removed item + assert(array3[3] == nil) -- Position should be nil + assert(array3[1] == 1 and array3[2] == 2 and array3[4] == 4 and array3[5] == 5) -- Other positions should be unchanged + end) - it("Should step values correctly", function() - assert(helper.step(0, 10, 2) == 2) - assert(helper.step(2, 10, 2) == 4) - assert(helper.step(9, 10, 2) == 10) - assert(helper.step(10, 0, 2) == 8) - assert(helper.step(2, 0, 2) == 0) - assert(helper.step(1, 0, 2) == 0) - end) + it("Should step values correctly", function() + assert(helper.step(0, 10, 2) == 2) + assert(helper.step(2, 10, 2) == 4) + assert(helper.step(9, 10, 2) == 10) + assert(helper.step(10, 0, 2) == 8) + assert(helper.step(2, 0, 2) == 0) + assert(helper.step(1, 0, 2) == 0) + end) - it("Should get node correctly", function() - -- Create a node using real GUI function - local test_node = gui.new_box_node(vmath.vector3(0, 0, 0), vmath.vector3(100, 50, 0)) - gui.set_id(test_node, "test_node_unique_id") + it("Should get node correctly", function() + -- Create a node using real GUI function + local test_node = gui.new_box_node(vmath.vector3(0, 0, 0), vmath.vector3(100, 50, 0)) + gui.set_id(test_node, "test_node_unique_id") - -- Test with node directly - local result1 = helper.get_node(test_node) - assert(result1 == test_node) + -- Test with node directly + local result1 = helper.get_node(test_node) + assert(result1 == test_node) - -- Note: Dynamically created nodes can't be reliably retrieved by ID in tests - -- but we can verify the function accepts string IDs - -- local result3 = helper.get_node("some_id") - -- We don't assert anything about result2, just make sure the function doesn't error + -- Note: Dynamically created nodes can't be reliably retrieved by ID in tests + -- but we can verify the function accepts string IDs + -- local result3 = helper.get_node("some_id") + -- We don't assert anything about result2, just make sure the function doesn't error - -- Test with nodes table - local dummy_node = {} - local nodes_table = { ["template/test_node3"] = dummy_node } - local result4 = helper.get_node("test_node3", "template", nodes_table) - assert(result4 == dummy_node) + -- Test with nodes table + local dummy_node = {} + local nodes_table = { ["template/test_node3"] = dummy_node } + local result4 = helper.get_node("test_node3", "template", nodes_table) + assert(result4 == dummy_node) - -- Clean up - gui.delete_node(test_node) - end) + -- Clean up + gui.delete_node(test_node) + end) - it("Should get pivot offset correctly", function() - -- Test with pivot constant - local center_offset = helper.get_pivot_offset(gui.PIVOT_CENTER) - assert(center_offset.x == 0) - assert(center_offset.y == 0) + it("Should get pivot offset correctly", function() + -- Test with pivot constant + local center_offset = helper.get_pivot_offset(gui.PIVOT_CENTER) + assert(center_offset.x == 0) + assert(center_offset.y == 0) - -- Test North pivot - local n_offset = helper.get_pivot_offset(gui.PIVOT_N) - assert(n_offset.x == 0) - assert(n_offset.y == 0.5) - end) + -- Test North pivot + local n_offset = helper.get_pivot_offset(gui.PIVOT_N) + assert(n_offset.x == 0) + assert(n_offset.y == 0.5) + end) - it("Should get scaled size correctly", function() - local test_node = gui.new_box_node(vmath.vector3(0, 0, 0), vmath.vector3(100, 50, 0)) - gui.set_scale(test_node, vmath.vector3(2, 3, 1)) + it("Should get scaled size correctly", function() + local test_node = gui.new_box_node(vmath.vector3(0, 0, 0), vmath.vector3(100, 50, 0)) + gui.set_scale(test_node, vmath.vector3(2, 3, 1)) - local scaled_size = helper.get_scaled_size(test_node) - assert(scaled_size.x == 200) - assert(scaled_size.y == 150) + local scaled_size = helper.get_scaled_size(test_node) + assert(scaled_size.x == 200) + assert(scaled_size.y == 150) - -- Clean up - gui.delete_node(test_node) - end) + -- Clean up + gui.delete_node(test_node) + end) - it("Should get scene scale correctly", function() - local parent_node = gui.new_box_node(vmath.vector3(0, 0, 0), vmath.vector3(100, 50, 0)) - gui.set_scale(parent_node, vmath.vector3(2, 2, 1)) + it("Should get scene scale correctly", function() + local parent_node = gui.new_box_node(vmath.vector3(0, 0, 0), vmath.vector3(100, 50, 0)) + gui.set_scale(parent_node, vmath.vector3(2, 2, 1)) - local child_node = gui.new_box_node(vmath.vector3(0, 0, 0), vmath.vector3(50, 25, 0)) - gui.set_parent(child_node, parent_node) - gui.set_scale(child_node, vmath.vector3(1.5, 1.5, 1)) + local child_node = gui.new_box_node(vmath.vector3(0, 0, 0), vmath.vector3(50, 25, 0)) + gui.set_parent(child_node, parent_node) + gui.set_scale(child_node, vmath.vector3(1.5, 1.5, 1)) - -- Without including the passed node scale - local scale1 = helper.get_scene_scale(child_node, false) - assert(scale1.x == 2) - assert(scale1.y == 2) + -- Without including the passed node scale + local scale1 = helper.get_scene_scale(child_node, false) + assert(scale1.x == 2) + assert(scale1.y == 2) - -- Including the passed node scale - local scale2 = helper.get_scene_scale(child_node, true) - assert(scale2.x == 3) - assert(scale2.y == 3) + -- Including the passed node scale + local scale2 = helper.get_scene_scale(child_node, true) + assert(scale2.x == 3) + assert(scale2.y == 3) - -- Clean up - gui.delete_node(child_node) - gui.delete_node(parent_node) - end) + -- Clean up + gui.delete_node(child_node) + gui.delete_node(parent_node) + end) - it("Should check if value is desktop/mobile/web correctly", function() - -- These tests depend on the current system, so we just make sure the functions exist - local is_desktop = helper.is_desktop() - local is_mobile = helper.is_mobile() - local is_web = helper.is_web() + it("Should check if value is desktop/mobile/web correctly", function() + -- These tests depend on the current system, so we just make sure the functions exist + local is_desktop = helper.is_desktop() + local is_mobile = helper.is_mobile() + local is_web = helper.is_web() - -- They should be boolean values - assert(type(is_desktop) == "boolean") - assert(type(is_mobile) == "boolean") - assert(type(is_web) == "boolean") - end) + -- They should be boolean values + assert(type(is_desktop) == "boolean") + assert(type(is_mobile) == "boolean") + assert(type(is_web) == "boolean") + end) - it("Should get border correctly", function() - local test_node = gui.new_box_node(vmath.vector3(0, 0, 0), vmath.vector3(100, 50, 0)) - gui.set_pivot(test_node, gui.PIVOT_CENTER) + it("Should get border correctly", function() + local test_node = gui.new_box_node(vmath.vector3(0, 0, 0), vmath.vector3(100, 50, 0)) + gui.set_pivot(test_node, gui.PIVOT_CENTER) - local border = helper.get_border(test_node) - assert(border.x == -50) -- left - assert(border.y == 25) -- top - assert(border.z == 50) -- right - assert(border.w == -25) -- bottom + local border = helper.get_border(test_node) + assert(border.x == -50) -- left + assert(border.y == 25) -- top + assert(border.z == 50) -- right + assert(border.w == -25) -- bottom - -- Test with offset - local offset = vmath.vector3(10, 20, 0) - local border_with_offset = helper.get_border(test_node, offset) - assert(border_with_offset.x == -40) -- left + offset.x - assert(border_with_offset.y == 45) -- top + offset.y - assert(border_with_offset.z == 60) -- right + offset.x - assert(border_with_offset.w == -5) -- bottom + offset.y + -- Test with offset + local offset = vmath.vector3(10, 20, 0) + local border_with_offset = helper.get_border(test_node, offset) + assert(border_with_offset.x == -40) -- left + offset.x + assert(border_with_offset.y == 45) -- top + offset.y + assert(border_with_offset.z == 60) -- right + offset.x + assert(border_with_offset.w == -5) -- bottom + offset.y - -- Clean up - gui.delete_node(test_node) - end) + -- Clean up + gui.delete_node(test_node) + end) - it("Should centrate nodes correctly", function() - local total_width = helper.centrate_nodes(10, node1, node2) + it("Should centrate nodes correctly", function() + local total_width = helper.centrate_nodes(10, node1, node2) - -- The total width should be node1 width + node2 width + margin - assert(total_width == 170) + -- The total width should be node1 width + node2 width + margin + assert(total_width == 170) - -- The first node should be positioned at -total_width/2 + node1_width/2 - local pos1 = gui.get_position(node1) - assert(pos1.x == -35) -- -170/2 + 100/2 + -- The first node should be positioned at -total_width/2 + node1_width/2 + local pos1 = gui.get_position(node1) + assert(pos1.x == -35) -- -170/2 + 100/2 - -- The second node should be positioned at pos1.x + node1_width/2 + margin + node2_width/2 - local pos2 = gui.get_position(node2) - assert(pos2.x == 55) -- -35 + 100/2 + 10 + 60/2 - end) - end) + -- The second node should be positioned at pos1.x + node1_width/2 + margin + node2_width/2 + local pos2 = gui.get_position(node2) + assert(pos2.x == 55) -- -35 + 100/2 + 10 + 60/2 + end) + end) end diff --git a/test/tests/test_input.lua b/test/tests/test_input.lua index 25f6bed..eb164a0 100644 --- a/test/tests/test_input.lua +++ b/test/tests/test_input.lua @@ -95,25 +95,20 @@ return function() druid:on_input(mock_input.click_pressed(50, 25)) druid:on_input(mock_input.click_released(50, 25)) - -- Simulate typing "Hello" - local function trigger_text_input(text) - return druid:on_input(hash("text"), {text = text}) - end - -- Type "H" - trigger_text_input("H") + druid:on_input(mock_input.input_text("H")) assert(input:get_text() == "H") assert(on_input_text_calls == 1) -- Type "e" - trigger_text_input("e") + druid:on_input(mock_input.input_text("e")) assert(input:get_text() == "He") assert(on_input_text_calls == 2) -- Type "llo" - trigger_text_input("l") - trigger_text_input("l") - trigger_text_input("o") + druid:on_input(mock_input.input_text("l")) + druid:on_input(mock_input.input_text("l")) + druid:on_input(mock_input.input_text("o")) assert(input:get_text() == "Hello") assert(on_input_text_calls == 5) @@ -134,17 +129,12 @@ return function() druid:on_input(mock_input.click_pressed(50, 25)) druid:on_input(mock_input.click_released(50, 25)) - -- Simulate backspace key - local function trigger_backspace() - return druid:on_input(hash("key_backspace"), {pressed = true}) - end - -- Delete one letter - assert(trigger_backspace() == true) + druid:on_input(hash("key_backspace"), {pressed = true}) assert(input:get_text() == "Hell") -- Delete another letter - assert(trigger_backspace() == true) + druid:on_input(hash("key_backspace"), {pressed = true}) assert(input:get_text() == "Hel") druid:remove(input) @@ -171,18 +161,23 @@ return function() druid:on_input(mock_input.click_pressed(50, 25)) druid:on_input(mock_input.click_released(50, 25)) - -- Simulate typing text - local function trigger_text_input(text) - return druid:on_input(hash("text"), {text = text}) - end - -- Type "Hello" - assert(trigger_text_input("Hello") == true) + druid:on_input(mock_input.input_text("H")) + druid:on_input(mock_input.input_text("e")) + druid:on_input(mock_input.input_text("l")) + druid:on_input(mock_input.input_text("l")) + druid:on_input(mock_input.input_text("o")) + assert(input:get_text() == "Hello") assert(on_input_full_calls == 1) -- Try to type "World" - should truncate - assert(trigger_text_input("World") == true) + druid:on_input(mock_input.input_text("W")) + druid:on_input(mock_input.input_text("o")) + druid:on_input(mock_input.input_text("r")) + druid:on_input(mock_input.input_text("l")) + druid:on_input(mock_input.input_text("d")) + assert(input:get_text() == "Hello") druid:remove(input) @@ -209,20 +204,21 @@ return function() druid:on_input(mock_input.click_pressed(50, 25)) druid:on_input(mock_input.click_released(50, 25)) - -- Simulate typing text - local function trigger_text_input(text) - return druid:on_input(hash("text"), {text = text}) - end - -- Type valid input "123" - assert(trigger_text_input("123") == true) + druid:on_input(mock_input.input_text("1")) + druid:on_input(mock_input.input_text("2")) + druid:on_input(mock_input.input_text("3")) + assert(input:get_text() == "123") assert(on_input_wrong_calls == 0) -- Type invalid input "abc" - should be rejected - assert(trigger_text_input("abc") == true) + druid:on_input(mock_input.input_text("a")) + druid:on_input(mock_input.input_text("b")) + druid:on_input(mock_input.input_text("c")) + assert(input:get_text() == "123") - assert(on_input_wrong_calls == 1) + assert(on_input_wrong_calls == 3) druid:remove(input) gui.delete_node(button_node) @@ -241,12 +237,11 @@ return function() druid:on_input(mock_input.click_pressed(50, 25)) druid:on_input(mock_input.click_released(50, 25)) - -- Simulate typing "Hello" - local function trigger_text_input(text) - return druid:on_input(hash("text"), {text = text}) - end - - assert(trigger_text_input("Hello") == true) + druid:on_input(mock_input.input_text("H")) + druid:on_input(mock_input.input_text("e")) + druid:on_input(mock_input.input_text("l")) + druid:on_input(mock_input.input_text("l")) + druid:on_input(mock_input.input_text("o")) -- Raw text should be "Hello" assert(input:get_text() == "Hello") diff --git a/test/tests/test_static_grid.lua b/test/tests/test_static_grid.lua index 0ffef0c..354a225 100644 --- a/test/tests/test_static_grid.lua +++ b/test/tests/test_static_grid.lua @@ -2,7 +2,6 @@ return function() local mock_gui = nil local mock_time = nil local mock_input = nil - local test_helper = nil local druid_system = nil local druid = nil @@ -18,14 +17,13 @@ return function() mock_gui = require("deftest.mock.gui") mock_time = require("deftest.mock.time") mock_input = require("test.helper.mock_input") - test_helper = require("test.helper.test_helper") druid_system = require("druid.druid") mock_gui.mock() mock_time.mock() mock_time.set(60) - context = test_helper.get_context() + context = vmath.vector3() druid = druid_system.new(context) parent = mock_gui.add_box("parent", 0, 0, 50, 50) diff --git a/test/tests/test_template.lua b/test/tests/test_template.lua index ebe405f..f3e2f22 100644 --- a/test/tests/test_template.lua +++ b/test/tests/test_template.lua @@ -2,7 +2,6 @@ return function() local mock_gui = nil local mock_time = nil local mock_input = nil - local test_helper = nil local druid_system = nil local druid = nil @@ -13,14 +12,13 @@ return function() mock_gui = require("deftest.mock.gui") mock_time = require("deftest.mock.time") mock_input = require("test.helper.mock_input") - test_helper = require("test.helper.test_helper") druid_system = require("druid.druid") mock_gui.mock() mock_time.mock() mock_time.set(60) - context = test_helper.get_context() + context = vmath.vector3() druid = druid_system.new(context) end) diff --git a/test/tests/test_text.lua b/test/tests/test_text.lua index 68b9544..c816841 100644 --- a/test/tests/test_text.lua +++ b/test/tests/test_text.lua @@ -1,238 +1,238 @@ return function() - describe("Text Component", function() - local mock_time - local mock_input - local druid_system + describe("Text Component", function() + local mock_time + local mock_input + local druid_system - local druid - local context + local druid + local context - before(function() - mock_time = require("deftest.mock.time") - mock_input = require("test.helper.mock_input") - druid_system = require("druid.druid") + before(function() + mock_time = require("deftest.mock.time") + mock_input = require("test.helper.mock_input") + druid_system = require("druid.druid") - mock_time.mock() - mock_time.set(0) + mock_time.mock() + mock_time.set(0) - context = vmath.vector3() - druid = druid_system.new(context) - end) + context = vmath.vector3() + druid = druid_system.new(context) + end) - after(function() - mock_time.unmock() - druid:final() - druid = nil - end) + after(function() + mock_time.unmock() + druid:final() + druid = nil + end) - it("Should create text component and set text", function() - local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Initial Text") - gui.set_font(text_node, "druid_text_bold") + it("Should create text component and set text", function() + local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Initial Text") + gui.set_font(text_node, "druid_text_bold") - local text = druid:new_text(text_node, "New Text") + local text = druid:new_text(text_node, "New Text") - assert(text ~= nil) - assert(text.node == text_node) - assert(gui.get_text(text_node) == "New Text") - assert(text:get_text() == "New Text") + assert(text ~= nil) + assert(text.node == text_node) + assert(gui.get_text(text_node) == "New Text") + assert(text:get_text() == "New Text") - -- Test that text setter works - text:set_text("Updated Text") - assert(gui.get_text(text_node) == "Updated Text") - assert(text:get_text() == "Updated Text") + -- Test that text setter works + text:set_text("Updated Text") + assert(gui.get_text(text_node) == "Updated Text") + assert(text:get_text() == "Updated Text") - druid:remove(text) - gui.delete_node(text_node) - end) + druid:remove(text) + gui.delete_node(text_node) + end) - it("Should fire on_set_text event", function() - local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Initial Text") - gui.set_font(text_node, "druid_text_bold") + it("Should fire on_set_text event", function() + local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Initial Text") + gui.set_font(text_node, "druid_text_bold") - local text = druid:new_text(text_node) + local text = druid:new_text(text_node) - local on_set_text_calls = 0 - local last_text = nil + local on_set_text_calls = 0 + local last_text = nil - text.on_set_text:subscribe(function(_, new_text) - on_set_text_calls = on_set_text_calls + 1 - last_text = new_text - end) + text.on_set_text:subscribe(function(_, new_text) + on_set_text_calls = on_set_text_calls + 1 + last_text = new_text + end) - text:set_text("Event Test") + text:set_text("Event Test") - assert(on_set_text_calls == 1) - assert(last_text == "Event Test") + assert(on_set_text_calls == 1) + assert(last_text == "Event Test") - druid:remove(text) - gui.delete_node(text_node) - end) + druid:remove(text) + gui.delete_node(text_node) + end) - it("Should change color and alpha", function() - local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Color Test") - gui.set_font(text_node, "druid_text_bold") + it("Should change color and alpha", function() + local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Color Test") + gui.set_font(text_node, "druid_text_bold") - local text = druid:new_text(text_node) + local text = druid:new_text(text_node) - local initial_color = gui.get_color(text_node) - local new_color = vmath.vector4(1, 0, 0, 1) + local initial_color = gui.get_color(text_node) + local new_color = vmath.vector4(1, 0, 0, 1) - text:set_color(new_color) - assert(gui.get_color(text_node).x == new_color.x) - assert(gui.get_color(text_node).y == new_color.y) - assert(gui.get_color(text_node).z == new_color.z) + text:set_color(new_color) + assert(gui.get_color(text_node).x == new_color.x) + assert(gui.get_color(text_node).y == new_color.y) + assert(gui.get_color(text_node).z == new_color.z) - text:set_alpha(0.5) - assert(gui.get_color(text_node).w == 0.5) + text:set_alpha(0.5) + assert(gui.get_color(text_node).w == 0.5) - druid:remove(text) - gui.delete_node(text_node) - end) + druid:remove(text) + gui.delete_node(text_node) + end) - it("Should set scale", function() - local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Scale Test") - gui.set_font(text_node, "druid_text_bold") + it("Should set scale", function() + local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Scale Test") + gui.set_font(text_node, "druid_text_bold") - local text = druid:new_text(text_node) + local text = druid:new_text(text_node) - local new_scale = vmath.vector3(2, 2, 1) - text:set_scale(new_scale) + local new_scale = vmath.vector3(2, 2, 1) + text:set_scale(new_scale) - local current_scale = gui.get_scale(text_node) - assert(current_scale.x == new_scale.x) - assert(current_scale.y == new_scale.y) + local current_scale = gui.get_scale(text_node) + assert(current_scale.x == new_scale.x) + assert(current_scale.y == new_scale.y) - druid:remove(text) - gui.delete_node(text_node) - end) + druid:remove(text) + gui.delete_node(text_node) + end) - it("Should set pivot and fire event", function() - local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Pivot Test") - gui.set_font(text_node, "druid_text_bold") + it("Should set pivot and fire event", function() + local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Pivot Test") + gui.set_font(text_node, "druid_text_bold") - local text = druid:new_text(text_node) + local text = druid:new_text(text_node) - local on_set_pivot_calls = 0 - local last_pivot = nil + local on_set_pivot_calls = 0 + local last_pivot = nil - text.on_set_pivot:subscribe(function(_, pivot) - on_set_pivot_calls = on_set_pivot_calls + 1 - last_pivot = pivot - end) + text.on_set_pivot:subscribe(function(_, pivot) + on_set_pivot_calls = on_set_pivot_calls + 1 + last_pivot = pivot + end) - text:set_pivot(gui.PIVOT_CENTER) + text:set_pivot(gui.PIVOT_CENTER) - assert(on_set_pivot_calls == 1) - assert(last_pivot == gui.PIVOT_CENTER) - assert(gui.get_pivot(text_node) == gui.PIVOT_CENTER) + assert(on_set_pivot_calls == 1) + assert(last_pivot == gui.PIVOT_CENTER) + assert(gui.get_pivot(text_node) == gui.PIVOT_CENTER) - druid:remove(text) - gui.delete_node(text_node) - end) + druid:remove(text) + gui.delete_node(text_node) + end) - it("Should set text size", function() - local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Size Test") - gui.set_font(text_node, "druid_text_bold") + it("Should set text size", function() + local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Size Test") + gui.set_font(text_node, "druid_text_bold") - local text = druid:new_text(text_node) + local text = druid:new_text(text_node) - local initial_size = gui.get_size(text_node) - local new_size = vmath.vector3(200, 100, 0) + local initial_size = gui.get_size(text_node) + local new_size = vmath.vector3(200, 100, 0) - text:set_size(new_size) + text:set_size(new_size) - -- Since setting size triggers adjust mechanisms, we can't directly check node size - -- but we can check that the internal size was updated - assert(text.start_size.x == new_size.x) - assert(text.start_size.y == new_size.y) + -- Since setting size triggers adjust mechanisms, we can't directly check node size + -- but we can check that the internal size was updated + assert(text.start_size.x == new_size.x) + assert(text.start_size.y == new_size.y) - druid:remove(text) - gui.delete_node(text_node) - end) + druid:remove(text) + gui.delete_node(text_node) + end) - it("Should handle different adjust types", function() - local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Adjust Test") - gui.set_font(text_node, "druid_text_bold") - gui.set_size(text_node, vmath.vector3(100, 50, 0)) + it("Should handle different adjust types", function() + local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Adjust Test") + gui.set_font(text_node, "druid_text_bold") + gui.set_size(text_node, vmath.vector3(100, 50, 0)) - local text = druid:new_text(text_node, "This is a very long text that should be adjusted") + local text = druid:new_text(text_node, "This is a very long text that should be adjusted") - -- Test default adjust (downscale) - local initial_adjust = text:get_text_adjust() - assert(initial_adjust == "downscale") + -- Test default adjust (downscale) + local initial_adjust = text:get_text_adjust() + assert(initial_adjust == "downscale") - -- Test no_adjust - text:set_text_adjust("no_adjust") - assert(text:get_text_adjust() == "no_adjust") + -- Test no_adjust + text:set_text_adjust("no_adjust") + assert(text:get_text_adjust() == "no_adjust") - -- Test trim - text:set_text_adjust("trim") - assert(text:get_text_adjust() == "trim") + -- Test trim + text:set_text_adjust("trim") + assert(text:get_text_adjust() == "trim") - -- Test with minimal scale - text:set_text_adjust("downscale_limited", 0.5) - assert(text:get_text_adjust() == "downscale_limited") + -- Test with minimal scale + text:set_text_adjust("downscale_limited", 0.5) + assert(text:get_text_adjust() == "downscale_limited") - druid:remove(text) - gui.delete_node(text_node) - end) + druid:remove(text) + gui.delete_node(text_node) + end) - it("Should get text size", function() - local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Text Size Test") - gui.set_font(text_node, "druid_text_bold") + it("Should get text size", function() + local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Text Size Test") + gui.set_font(text_node, "druid_text_bold") - local text = druid:new_text(text_node) + local text = druid:new_text(text_node) - local width, height = text:get_text_size() + local width, height = text:get_text_size() - assert(width > 0) - assert(height > 0) + assert(width > 0) + assert(height > 0) - druid:remove(text) - gui.delete_node(text_node) - end) + druid:remove(text) + gui.delete_node(text_node) + end) - it("Should check if text is multiline", function() - local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Single line") - gui.set_font(text_node, "druid_text_bold") - gui.set_line_break(text_node, false) + it("Should check if text is multiline", function() + local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Single line") + gui.set_font(text_node, "druid_text_bold") + gui.set_line_break(text_node, false) - local text = druid:new_text(text_node) + local text = druid:new_text(text_node) - assert(text:is_multiline() == false) + assert(text:is_multiline() == false) - -- Change to multiline - gui.set_line_break(text_node, true) + -- Change to multiline + gui.set_line_break(text_node, true) - assert(text:is_multiline() == true) + assert(text:is_multiline() == true) - druid:remove(text) - gui.delete_node(text_node) - end) + druid:remove(text) + gui.delete_node(text_node) + end) - it("Should fire on_update_text_scale event", function() - local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Scale Event Test") - gui.set_font(text_node, "druid_text_bold") - gui.set_size(text_node, vmath.vector3(100, 50, 0)) + it("Should fire on_update_text_scale event", function() + local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Scale Event Test") + gui.set_font(text_node, "druid_text_bold") + gui.set_size(text_node, vmath.vector3(100, 50, 0)) - local text = druid:new_text(text_node) + local text = druid:new_text(text_node) - local on_update_text_scale_calls = 0 - local last_scale = nil + local on_update_text_scale_calls = 0 + local last_scale = nil - text.on_update_text_scale:subscribe(function(_, scale) - on_update_text_scale_calls = on_update_text_scale_calls + 1 - last_scale = scale - end) + text.on_update_text_scale:subscribe(function(_, scale) + on_update_text_scale_calls = on_update_text_scale_calls + 1 + last_scale = scale + end) - -- Trigger scale update - text:set_text("This text is long enough to trigger scaling") + -- Trigger scale update + text:set_text("This text is long enough to trigger scaling") - assert(on_update_text_scale_calls >= 1) - assert(last_scale ~= nil) + assert(on_update_text_scale_calls >= 1) + assert(last_scale ~= nil) - druid:remove(text) - gui.delete_node(text_node) - end) - end) + druid:remove(text) + gui.delete_node(text_node) + end) + end) end