Skip to content

Commit 8b67ea0

Browse files
tests: +21 across classes / generators
test_classes_more.omc (11): Point class: construct, distance_from_origin (3-4-5), translate, equals, is_instance Point/Vector; Vector class: magnitude, add; Counter class: increment x3, decrement-twice (chained via separate statements since method-chaining syntax isn't yet parseable); Stack class: push x3 + size, pop returns last. test_generators_more.omc (10): squares_to + fib_gen helpers; eager squares/fib correctness; lazy gen_count/gen_sum/gen_take on squares; substrate-fib collect + early stop; sum-of-squares formula validation (50*51*101/6 = 42925); empty generator count/sum. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 48201c5 commit 8b67ea0

2 files changed

Lines changed: 271 additions & 0 deletions

File tree

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# More class system tests.
2+
3+
fn assert_eq(actual, expected, msg) {
4+
if actual != expected {
5+
test_record_failure(msg + ": expected " + to_string(expected) + " got " + to_string(actual));
6+
}
7+
}
8+
9+
fn assert_true(cond, msg) { if !cond { test_record_failure(msg); } }
10+
11+
class Point {
12+
x;
13+
y;
14+
fn distance_from_origin(self) {
15+
h x = dict_get(self, "x");
16+
h y = dict_get(self, "y");
17+
return sqrt(x * x + y * y);
18+
}
19+
fn translate(self, dx, dy) {
20+
h nx = dict_get(self, "x") + dx;
21+
h ny = dict_get(self, "y") + dy;
22+
return Point(nx, ny);
23+
}
24+
fn equals(self, other) {
25+
if dict_get(self, "x") != dict_get(other, "x") { return 0; }
26+
if dict_get(self, "y") != dict_get(other, "y") { return 0; }
27+
return 1;
28+
}
29+
}
30+
31+
fn approx_eq(a, b, tol) {
32+
h d = a - b;
33+
if d < 0.0 { d = 0.0 - d; }
34+
return d <= tol;
35+
}
36+
37+
fn test_point_construct() {
38+
h p = Point(3, 4);
39+
assert_eq(dict_get(p, "x"), 3, "x");
40+
assert_eq(dict_get(p, "y"), 4, "y");
41+
}
42+
43+
fn test_point_distance() {
44+
h p = Point(3, 4);
45+
h d = p.distance_from_origin();
46+
assert_true(approx_eq(d, 5.0, 0.001), "3-4-5 distance");
47+
}
48+
49+
fn test_point_translate() {
50+
h p = Point(1, 2);
51+
h q = p.translate(10, 20);
52+
assert_eq(dict_get(q, "x"), 11, "translated x");
53+
assert_eq(dict_get(q, "y"), 22, "translated y");
54+
}
55+
56+
fn test_point_equals() {
57+
h a = Point(1, 2);
58+
h b = Point(1, 2);
59+
h c = Point(3, 4);
60+
assert_eq(a.equals(b), 1, "a == b");
61+
assert_eq(a.equals(c), 0, "a != c");
62+
}
63+
64+
fn test_point_is_instance() {
65+
h p = Point(0, 0);
66+
assert_eq(is_instance(p, "Point"), 1, "Point");
67+
assert_eq(is_instance(p, "Vector"), 0, "not Vector");
68+
}
69+
70+
class Vector {
71+
dx;
72+
dy;
73+
fn magnitude(self) {
74+
h dx = dict_get(self, "dx");
75+
h dy = dict_get(self, "dy");
76+
return sqrt(dx * dx + dy * dy);
77+
}
78+
fn add(self, other) {
79+
return Vector(
80+
dict_get(self, "dx") + dict_get(other, "dx"),
81+
dict_get(self, "dy") + dict_get(other, "dy")
82+
);
83+
}
84+
}
85+
86+
fn test_vector_magnitude() {
87+
h v = Vector(3, 4);
88+
h m = v.magnitude();
89+
assert_true(approx_eq(m, 5.0, 0.001), "magnitude");
90+
}
91+
92+
fn test_vector_add() {
93+
h v1 = Vector(1, 2);
94+
h v2 = Vector(3, 4);
95+
h sum = v1.add(v2);
96+
assert_eq(dict_get(sum, "dx"), 4, "dx");
97+
assert_eq(dict_get(sum, "dy"), 6, "dy");
98+
}
99+
100+
class Counter {
101+
value;
102+
fn increment(self) {
103+
dict_set(self, "value", dict_get(self, "value") + 1);
104+
return self;
105+
}
106+
fn decrement(self) {
107+
dict_set(self, "value", dict_get(self, "value") - 1);
108+
return self;
109+
}
110+
fn get(self) { return dict_get(self, "value"); }
111+
}
112+
113+
fn test_counter_increment() {
114+
h c = Counter(0);
115+
c.increment();
116+
c.increment();
117+
c.increment();
118+
assert_eq(c.get(), 3, "incremented 3 times");
119+
}
120+
121+
fn test_counter_chaining_via_method_return() {
122+
h c = Counter(10);
123+
c.decrement();
124+
c.decrement();
125+
assert_eq(c.get(), 8, "decremented 2");
126+
}
127+
128+
# class composition
129+
class Stack {
130+
items;
131+
fn push(self, v) {
132+
h xs = dict_get(self, "items");
133+
arr_push(xs, v);
134+
return self;
135+
}
136+
fn pop(self) {
137+
h xs = dict_get(self, "items");
138+
h n = arr_len(xs);
139+
if n == 0 { return null; }
140+
h v = arr_get(xs, n - 1);
141+
# No arr_pop builtin; use arr_slice to drop last
142+
h new = arr_slice(xs, 0, n - 1);
143+
dict_set(self, "items", new);
144+
return v;
145+
}
146+
fn size(self) { return arr_len(dict_get(self, "items")); }
147+
}
148+
149+
fn test_stack_push_size() {
150+
h s = Stack([]);
151+
s.push(1);
152+
s.push(2);
153+
s.push(3);
154+
assert_eq(s.size(), 3, "3 items");
155+
}
156+
157+
fn test_stack_pop_returns_last() {
158+
h s = Stack([10, 20, 30]);
159+
h v = s.pop();
160+
assert_eq(v, 30, "popped 30");
161+
assert_eq(s.size(), 2, "2 left");
162+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# More generator tests.
2+
3+
fn assert_eq(actual, expected, msg) {
4+
if actual != expected {
5+
test_record_failure(msg + ": expected " + to_string(expected) + " got " + to_string(actual));
6+
}
7+
}
8+
9+
fn assert_true(cond, msg) { if !cond { test_record_failure(msg); } }
10+
11+
fn squares_to(n) {
12+
h i = 1;
13+
while i <= n {
14+
yield i * i;
15+
i = i + 1;
16+
}
17+
}
18+
19+
fn fib_gen(limit) {
20+
h a = 0;
21+
h b = 1;
22+
while a < limit {
23+
yield a;
24+
h t = a + b;
25+
a = b;
26+
b = t;
27+
}
28+
}
29+
30+
# Eager: squares
31+
fn test_eager_squares() {
32+
h xs = squares_to(5);
33+
assert_eq(arr_len(xs), 5, "5 squares");
34+
assert_eq(arr_get(xs, 0), 1, "1");
35+
assert_eq(arr_get(xs, 4), 25, "25");
36+
}
37+
38+
# Eager: fib
39+
fn test_eager_fib() {
40+
h xs = fib_gen(20);
41+
# Fibs < 20: 0,1,1,2,3,5,8,13
42+
assert_eq(arr_len(xs), 8, "8 fibs");
43+
assert_eq(arr_get(xs, 0), 0, "first");
44+
assert_eq(arr_get(xs, 7), 13, "last");
45+
}
46+
47+
# Lazy: count of squares
48+
fn test_lazy_squares_count() {
49+
h n = gen_count(fn() { return squares_to(50); });
50+
assert_eq(n, 50, "50 yields");
51+
}
52+
53+
# Lazy: sum of squares
54+
fn test_lazy_squares_sum() {
55+
h s = gen_sum(fn() { return squares_to(10); });
56+
# 1+4+9+16+25+36+49+64+81+100 = 385
57+
assert_eq(s, 385, "sum of first 10 squares");
58+
}
59+
60+
# Lazy: take first 3
61+
fn test_lazy_take_3() {
62+
h xs = gen_take(fn() { return squares_to(100); }, 3);
63+
assert_eq(arr_len(xs), 3, "3 items");
64+
assert_eq(arr_get(xs, 0), 1, "first square");
65+
assert_eq(arr_get(xs, 2), 9, "third square");
66+
}
67+
68+
# Substrate fib over a small limit
69+
fn test_substrate_fib_collect() {
70+
h xs = [];
71+
gen_substrate_fib(
72+
fn(v) { arr_push(xs, v); return 1; },
73+
100
74+
);
75+
# Fibs <= 100: 0,1,1,2,3,5,8,13,21,34,55,89 = 12
76+
assert_eq(arr_len(xs), 12, "12 fibs");
77+
}
78+
79+
# Substrate fib early stop
80+
fn test_substrate_fib_stop() {
81+
h count = [0];
82+
gen_substrate_fib(
83+
fn(v) {
84+
arr_set(count, 0, arr_get(count, 0) + 1);
85+
if arr_get(count, 0) >= 5 { return 0; }
86+
return 1;
87+
},
88+
1000
89+
);
90+
assert_eq(arr_get(count, 0), 5, "stopped at 5");
91+
}
92+
93+
# Compose: gen_sum after squares_to
94+
fn test_lazy_sum_50_squares() {
95+
h s = gen_sum(fn() { return squares_to(50); });
96+
# Formula: n(n+1)(2n+1)/6 for n=50 = 50*51*101/6 = 42925
97+
assert_eq(s, 42925, "sum of 1^2 to 50^2");
98+
}
99+
100+
# Empty generator
101+
fn empty() { return; }
102+
103+
fn test_empty_count() {
104+
assert_eq(gen_count(fn() { return empty(); }), 0, "empty");
105+
}
106+
107+
fn test_empty_sum() {
108+
assert_eq(gen_sum(fn() { return empty(); }), 0, "empty sum");
109+
}

0 commit comments

Comments
 (0)