;; Number-tower tests: SmallInteger / Float / Fraction. New numeric methods
;; (floor/ceiling/sqrt/factorial/gcd:/lcm:/raisedTo:/even/odd) and Fraction
;; arithmetic with normalization.

(set! st-test-pass 0)
(set! st-test-fail 0)
(set! st-test-fails (list))

(st-bootstrap-classes!)
(define ev (fn (src) (smalltalk-eval src)))
(define evp (fn (src) (smalltalk-eval-program src)))

;; ── 1. New SmallInteger / Float methods ──
(st-test "floor of 3.7"      (ev "3.7 floor")       3)
(st-test "floor of -3.2"     (ev "-3.2 floor")      -4)
(st-test "ceiling of 3.2"    (ev "3.2 ceiling")     4)
(st-test "ceiling of -3.7"   (ev "-3.7 ceiling")    -3)
(st-test "truncated of 3.7"  (ev "3.7 truncated")   3)
(st-test "truncated of -3.7" (ev "-3.7 truncated")  -3)
(st-test "rounded of 3.4"    (ev "3.4 rounded")     3)
(st-test "rounded of 3.5"    (ev "3.5 rounded")     4)
(st-test "sqrt of 16"        (ev "16 sqrt")         4)
(st-test "squared"           (ev "7 squared")       49)
(st-test "raisedTo:"         (ev "2 raisedTo: 10")  1024)
(st-test "factorial 0"       (ev "0 factorial")     1)
(st-test "factorial 1"       (ev "1 factorial")     1)
(st-test "factorial 5"       (ev "5 factorial")     120)
(st-test "factorial 10"      (ev "10 factorial")    3628800)

(st-test "even/odd 4"  (ev "4 even") true)
(st-test "even/odd 5"  (ev "5 even") false)
(st-test "odd 3"       (ev "3 odd")  true)
(st-test "odd 4"       (ev "4 odd")  false)

(st-test "gcd of 24 18"      (ev "24 gcd: 18")      6)
(st-test "gcd 0 7"            (ev "0 gcd: 7")        7)
(st-test "gcd negative"       (ev "-12 gcd: 8")     4)
(st-test "lcm of 4 6"         (ev "4 lcm: 6")        12)

(st-test "isInteger on int"   (ev "42 isInteger")   true)
(st-test "isInteger on float" (ev "3.14 isInteger") false)
(st-test "isFloat on float"   (ev "3.14 isFloat")   true)
(st-test "isNumber"           (ev "42 isNumber")    true)

;; ── 2. Fraction class ──
(st-test "Fraction class exists" (st-class-exists? "Fraction") true)
(st-test "Fraction < Number"
  (st-class-inherits-from? "Fraction" "Number") true)

(st-test "Fraction creation"
  (str (evp "^ (Fraction numerator: 1 denominator: 2) printString"))
  "1/2")

(st-test "Fraction reduction at construction"
  (str (evp "^ (Fraction numerator: 6 denominator: 8) printString"))
  "3/4")

(st-test "Fraction sign normalization (denom positive)"
  (str (evp "^ (Fraction numerator: 1 denominator: -2) printString"))
  "-1/2")

(st-test "Fraction numerator accessor"
  (evp "^ (Fraction numerator: 6 denominator: 8) numerator") 3)

(st-test "Fraction denominator accessor"
  (evp "^ (Fraction numerator: 6 denominator: 8) denominator") 4)

;; ── 3. Fraction arithmetic ──
(st-test "Fraction addition"
  (str
    (evp
      "^ ((Fraction numerator: 1 denominator: 2) + (Fraction numerator: 1 denominator: 3)) printString"))
  "5/6")

(st-test "Fraction subtraction"
  (str
    (evp
      "^ ((Fraction numerator: 3 denominator: 4) - (Fraction numerator: 1 denominator: 4)) printString"))
  "1/2")

(st-test "Fraction multiplication"
  (str
    (evp
      "^ ((Fraction numerator: 2 denominator: 3) * (Fraction numerator: 3 denominator: 4)) printString"))
  "1/2")

(st-test "Fraction division"
  (str
    (evp
      "^ ((Fraction numerator: 1 denominator: 2) / (Fraction numerator: 1 denominator: 4)) printString"))
  "2/1")

(st-test "Fraction negated"
  (str (evp "^ (Fraction numerator: 1 denominator: 3) negated printString"))
  "-1/3")

(st-test "Fraction reciprocal"
  (str (evp "^ (Fraction numerator: 2 denominator: 5) reciprocal printString"))
  "5/2")

;; ── 4. Fraction equality + ordering ──
(st-test "Fraction equality after reduce"
  (evp
    "^ (Fraction numerator: 4 denominator: 8) = (Fraction numerator: 1 denominator: 2)")
  true)

(st-test "Fraction inequality"
  (evp
    "^ (Fraction numerator: 1 denominator: 3) = (Fraction numerator: 1 denominator: 4)")
  false)

(st-test "Fraction less-than"
  (evp
    "^ (Fraction numerator: 1 denominator: 3) < (Fraction numerator: 1 denominator: 2)")
  true)

;; ── 5. Fraction asFloat ──
(st-test "Fraction asFloat 1/2"
  (evp "^ (Fraction numerator: 1 denominator: 2) asFloat") (/ 1 2))

(st-test "Fraction asFloat 3/4"
  (evp "^ (Fraction numerator: 3 denominator: 4) asFloat") (/ 3 4))

;; ── 6. Fraction predicates ──
(st-test "Fraction isFraction"
  (evp "^ (Fraction numerator: 1 denominator: 2) isFraction") true)

(st-test "Fraction class name"
  (evp "^ (Fraction numerator: 1 denominator: 2) class name") "Fraction")

(list st-test-pass st-test-fail)
