127 lines
4.4 KiB
GDScript
127 lines
4.4 KiB
GDScript
extends SceneTree
|
||
|
||
var failures := 0
|
||
|
||
|
||
func _initialize() -> void:
|
||
call_deferred("_run")
|
||
|
||
|
||
func _run() -> void:
|
||
_test_basic_arithmetic()
|
||
_test_decimal_and_chained_operations()
|
||
_test_percent_and_sign()
|
||
_test_square_root()
|
||
_test_repeated_equals()
|
||
_test_backspace_and_clear()
|
||
_test_error_recovery()
|
||
await _test_runtime_panel_behavior()
|
||
quit(1 if failures > 0 else 0)
|
||
|
||
|
||
func _calculator():
|
||
return load("res://scripts/ui/calculator_panel.gd").new()
|
||
|
||
|
||
func _press(calculator, tokens: Array) -> void:
|
||
for token in tokens:
|
||
calculator.press_token(str(token))
|
||
|
||
|
||
func _test_basic_arithmetic() -> void:
|
||
var calculator = _calculator()
|
||
_press(calculator, ["9", "+", "6", "="])
|
||
_assert(calculator.get_display_text() == "15", "calculator should add operands")
|
||
calculator.reset_calculation()
|
||
_press(calculator, ["9", "−", "4", "="])
|
||
_assert(calculator.get_display_text() == "5", "calculator should subtract operands")
|
||
calculator.reset_calculation()
|
||
_press(calculator, ["7", "×", "8", "="])
|
||
_assert(calculator.get_display_text() == "56", "calculator should multiply operands")
|
||
calculator.reset_calculation()
|
||
_press(calculator, ["8", "÷", "4", "="])
|
||
_assert(calculator.get_display_text() == "2", "calculator should divide operands")
|
||
calculator.free()
|
||
|
||
|
||
func _test_decimal_and_chained_operations() -> void:
|
||
var calculator = _calculator()
|
||
_press(calculator, ["1", ".", "5", "+", "2", ".", "5", "×", "2", "="])
|
||
_assert(calculator.get_display_text() == "8", "calculator should evaluate chained handheld operations left to right")
|
||
calculator.free()
|
||
|
||
|
||
func _test_percent_and_sign() -> void:
|
||
var calculator = _calculator()
|
||
_press(calculator, ["5", "%"])
|
||
_assert(calculator.get_display_text() == "0.05", "percent should convert the displayed operand to a fraction")
|
||
_press(calculator, ["±"])
|
||
_assert(calculator.get_display_text() == "-0.05", "sign toggle should negate the displayed operand")
|
||
calculator.free()
|
||
|
||
|
||
func _test_square_root() -> void:
|
||
var calculator = _calculator()
|
||
_press(calculator, ["8", "1", "√"])
|
||
_assert(calculator.get_display_text() == "9", "square root should replace the displayed operand")
|
||
calculator.free()
|
||
|
||
|
||
func _test_repeated_equals() -> void:
|
||
var calculator = _calculator()
|
||
_press(calculator, ["5", "+", "2", "=", "="])
|
||
_assert(calculator.get_display_text() == "9", "repeated equals should replay the last binary operation")
|
||
calculator.free()
|
||
|
||
|
||
func _test_backspace_and_clear() -> void:
|
||
var calculator = _calculator()
|
||
_press(calculator, ["1", "2", "3", "⌫"])
|
||
_assert(calculator.get_display_text() == "12", "backspace should remove the final entry digit")
|
||
_press(calculator, ["AC"])
|
||
_assert(calculator.get_display_text() == "0", "clear should reset the display")
|
||
calculator.free()
|
||
|
||
|
||
func _test_error_recovery() -> void:
|
||
var calculator = _calculator()
|
||
_press(calculator, ["8", "÷", "0", "="])
|
||
_assert(calculator.get_display_text() == "Error", "division by zero should display an error")
|
||
_press(calculator, ["4"])
|
||
_assert(calculator.get_display_text() == "4", "digit entry should recover from an error")
|
||
_press(calculator, ["±", "√"])
|
||
_assert(calculator.get_display_text() == "Error", "square root of a negative operand should display an error")
|
||
calculator.free()
|
||
|
||
|
||
func _test_runtime_panel_behavior() -> void:
|
||
var host := Control.new()
|
||
host.size = Vector2(360, 640)
|
||
root.add_child(host)
|
||
var calculator = _calculator()
|
||
host.add_child(calculator)
|
||
await process_frame
|
||
calculator.open_panel()
|
||
await process_frame
|
||
_assert(calculator.visible, "calculator should open as a floating panel")
|
||
_assert(calculator.size.x <= 336.0, "calculator should fit a narrow web viewport")
|
||
_press(calculator, ["2", "+", "3", "="])
|
||
calculator.close_panel()
|
||
calculator.open_panel()
|
||
_assert(calculator.get_display_text() == "5", "closing and reopening should preserve the active-session value")
|
||
calculator.position = Vector2(1000, 1000)
|
||
calculator._clamp_to_viewport()
|
||
_assert(calculator.position.x + calculator.size.x <= calculator.get_viewport_rect().size.x, "calculator dragging should remain horizontally bounded")
|
||
_assert(calculator.position.y + calculator.size.y <= calculator.get_viewport_rect().size.y, "calculator dragging should remain vertically bounded")
|
||
calculator.reset_calculation()
|
||
_assert(calculator.get_display_text() == "0", "session reset should clear calculator state")
|
||
host.queue_free()
|
||
await process_frame
|
||
|
||
|
||
func _assert(condition: bool, message: String) -> void:
|
||
if condition:
|
||
return
|
||
failures += 1
|
||
push_error(message)
|