2026-06-06 13:28:59 +00:00
|
|
|
package calc
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"errors"
|
|
|
|
|
"testing"
|
|
|
|
|
)
|
|
|
|
|
|
2026-06-06 13:29:36 +00:00
|
|
|
func TestNewEngine_Defaults(t *testing.T) {
|
2026-06-06 13:28:59 +00:00
|
|
|
e := NewEngine()
|
|
|
|
|
if e.CurrentBase() != BaseDEC {
|
|
|
|
|
t.Errorf("expected DEC, got %s", e.CurrentBase())
|
|
|
|
|
}
|
2026-06-06 13:29:36 +00:00
|
|
|
if got := e.FormatForDisplay(); got != "0" {
|
|
|
|
|
t.Errorf("initial display: want 0, got %s", got)
|
2026-06-06 13:28:59 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestCycleBase_IntegerOK(t *testing.T) {
|
|
|
|
|
e := NewEngine()
|
2026-06-06 13:29:36 +00:00
|
|
|
e.accumulator = 42
|
|
|
|
|
e.entry = ""
|
2026-06-06 13:28:59 +00:00
|
|
|
|
|
|
|
|
if err := e.CycleBase(); err != nil {
|
2026-06-06 13:29:36 +00:00
|
|
|
t.Fatalf("unexpected error: %v", err)
|
2026-06-06 13:28:59 +00:00
|
|
|
}
|
|
|
|
|
if e.CurrentBase() != BaseHEX {
|
2026-06-06 13:29:36 +00:00
|
|
|
t.Errorf("expected HEX, got %s", e.CurrentBase())
|
|
|
|
|
}
|
|
|
|
|
if got := e.FormatForDisplay(); got != "2A" {
|
|
|
|
|
t.Errorf("hex of 42: want 2A, got %s", got)
|
2026-06-06 13:28:59 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestCycleBase_FractionalCERR(t *testing.T) {
|
|
|
|
|
e := NewEngine()
|
2026-06-06 13:29:36 +00:00
|
|
|
// 23/6 = 3.8333...
|
|
|
|
|
e.accumulator = 23.0 / 6.0
|
|
|
|
|
e.entry = ""
|
2026-06-06 13:28:59 +00:00
|
|
|
|
|
|
|
|
err := e.CycleBase()
|
|
|
|
|
if !errors.Is(err, ErrConversionNotPossible) {
|
|
|
|
|
t.Fatalf("expected ErrConversionNotPossible, got %v", err)
|
|
|
|
|
}
|
|
|
|
|
if e.CurrentBase() != BaseDEC {
|
2026-06-06 13:29:36 +00:00
|
|
|
t.Error("base must remain DEC after CERR")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestBasicArithmetic(t *testing.T) {
|
|
|
|
|
e := NewEngine()
|
|
|
|
|
|
|
|
|
|
// 2 + 3 =
|
|
|
|
|
e.EnterDigit('2')
|
|
|
|
|
e.SetOperator("+")
|
|
|
|
|
e.EnterDigit('3')
|
|
|
|
|
e.Equals()
|
|
|
|
|
|
|
|
|
|
if got := e.FormatForDisplay(); got != "5" {
|
|
|
|
|
t.Errorf("2+3: want 5, got %s", got)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// * 4 =
|
|
|
|
|
e.SetOperator("*")
|
|
|
|
|
e.EnterDigit('4')
|
|
|
|
|
e.Equals()
|
|
|
|
|
if got := e.FormatForDisplay(); got != "20" {
|
|
|
|
|
t.Errorf("5*4: want 20, got %s", got)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestMOD(t *testing.T) {
|
|
|
|
|
e := NewEngine()
|
|
|
|
|
e.EnterDigit('2')
|
|
|
|
|
e.EnterDigit('3')
|
|
|
|
|
e.SetOperator("mod")
|
|
|
|
|
e.EnterDigit('6')
|
|
|
|
|
e.Equals()
|
|
|
|
|
|
|
|
|
|
if got := e.FormatForDisplay(); got != "5" {
|
|
|
|
|
t.Errorf("23 mod 6: want 5, got %s", got)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestFractionalThenBASE_CERR(t *testing.T) {
|
|
|
|
|
e := NewEngine()
|
|
|
|
|
|
|
|
|
|
// 1 / 3 = 0.333...
|
|
|
|
|
e.EnterDigit('1')
|
|
|
|
|
e.SetOperator("/")
|
|
|
|
|
e.EnterDigit('3')
|
|
|
|
|
e.Equals()
|
|
|
|
|
|
|
|
|
|
if e.IsInteger() {
|
|
|
|
|
t.Error("1/3 should not be integer")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err := e.CycleBase()
|
|
|
|
|
if !errors.Is(err, ErrConversionNotPossible) {
|
|
|
|
|
t.Fatalf("expected CERR on fractional BASE, got %v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestClearAndBackspace(t *testing.T) {
|
|
|
|
|
e := NewEngine()
|
|
|
|
|
e.EnterDigit('1')
|
|
|
|
|
e.EnterDigit('2')
|
|
|
|
|
e.EnterDigit('3')
|
|
|
|
|
e.Backspace()
|
|
|
|
|
if got := e.FormatForDisplay(); got != "12" {
|
|
|
|
|
t.Errorf("backspace: want 12, got %s", got)
|
|
|
|
|
}
|
|
|
|
|
e.ClearEntry()
|
|
|
|
|
if got := e.FormatForDisplay(); got != "0" {
|
|
|
|
|
t.Errorf("clear entry: want 0, got %s", got)
|
|
|
|
|
}
|
|
|
|
|
e.AllClear()
|
|
|
|
|
if e.CurrentBase() != BaseDEC {
|
|
|
|
|
t.Error("all clear should reset base to DEC for MVP")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestChangeSign(t *testing.T) {
|
|
|
|
|
e := NewEngine()
|
|
|
|
|
e.EnterDigit('5')
|
|
|
|
|
e.ChangeSign()
|
|
|
|
|
if got := e.FormatForDisplay(); got != "-5" {
|
|
|
|
|
t.Errorf("sign: want -5, got %s", got)
|
2026-06-06 13:28:59 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-06 13:29:36 +00:00
|
|
|
// More tests (entry buffer, multi-op, decimal point, etc.) will be added as the
|
|
|
|
|
// TUI spike exercises real usage. The CERR path is the critical one for BASE.
|