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)