Add exam-style question calculator

This commit is contained in:
hz
2026-07-23 05:19:12 -05:00
parent ba155fd38a
commit 50f07a77a5
8 changed files with 673 additions and 4 deletions
+126
View File
@@ -0,0 +1,126 @@
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)