about summary refs log tree commit diff stats
path: root/js/baba-yaga/tests/math_namespace.test.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/baba-yaga/tests/math_namespace.test.js')
-rw-r--r--js/baba-yaga/tests/math_namespace.test.js112
1 files changed, 112 insertions, 0 deletions
diff --git a/js/baba-yaga/tests/math_namespace.test.js b/js/baba-yaga/tests/math_namespace.test.js
new file mode 100644
index 0000000..c892bbb
--- /dev/null
+++ b/js/baba-yaga/tests/math_namespace.test.js
@@ -0,0 +1,112 @@
+const assert = require('assert');
+const { createLexer } = require('../src/core/lexer');
+const { createParser } = require('../src/core/parser');
+const { createInterpreter } = require('../src/core/interpreter');
+
+function interpret(code) {
+  const lexer = createLexer(code);
+  const tokens = lexer.allTokens();
+  const parser = createParser(tokens);
+  const ast = parser.parse();
+  const interpreter = createInterpreter(ast);
+  interpreter.interpret();
+  return interpreter;
+}
+
+describe('Math Namespace', () => {
+  it('should support basic numeric ops: abs/floor/ceil/round/trunc', () => {
+    const code = `
+      a : math.abs -3;
+      b : math.floor 2.9;
+      c : math.ceil 2.1;
+      d : math.round 2.5;
+      e : math.trunc -2.9;
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('a').value, 3);
+    assert.strictEqual(itp.scope.get('b').value, 2);
+    assert.strictEqual(itp.scope.get('c').value, 3);
+    assert.strictEqual(itp.scope.get('d').value, 3);
+    assert.strictEqual(itp.scope.get('e').value, -2);
+  });
+
+  it('should support min/max/clamp', () => {
+    const code = `
+      a : math.min 10 3;
+      b : math.max 10 3;
+      c : math.clamp 15 0 10;
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('a').value, 3);
+    assert.strictEqual(itp.scope.get('b').value, 10);
+    assert.strictEqual(itp.scope.get('c').value, 10);
+  });
+
+  it('should support pow/sqrt/exp/log (with domain checks)', () => {
+    const code = `
+      p : math.pow 2 8;
+      s : math.sqrt 9;
+      e : math.exp 1;
+      l : math.log 2.718281828;
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('p').value, 256);
+    assert.strictEqual(itp.scope.get('s').value, 3);
+    assert.ok(Math.abs(itp.scope.get('e').value - Math.E) < 1e-9);
+    assert.ok(Math.abs(itp.scope.get('l').value - 1) < 1e-6);
+
+    assert.throws(() => interpret('x : math.sqrt -1;'));
+    assert.throws(() => interpret('x : math.log 0;'));
+  });
+
+  it('should support trig and conversions', () => {
+    const code = `
+      c : math.cos 0;
+      s : math.sin 0;
+      a : math.atan2 1 1;
+      d : math.deg PI;
+      r : math.rad 180;
+    `;
+    const itp = interpret(code);
+    assert.ok(Math.abs(itp.scope.get('c').value - 1) < 1e-12);
+    assert.ok(Math.abs(itp.scope.get('s').value - 0) < 1e-12);
+    assert.ok(Math.abs(itp.scope.get('a').value - Math.PI/4) < 1e-6);
+    assert.ok(Math.abs(itp.scope.get('d').value - 180) < 1e-12);
+    assert.ok(Math.abs(itp.scope.get('r').value - Math.PI) < 1e-6);
+  });
+
+  it('should support random and randomInt', () => {
+    const code = `
+      one : math.randomInt 1 1;
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('one').value, 1);
+  });
+
+  it('should accept Int where Float is expected, and Number as supertype', () => {
+    const code = `
+      // Float-typed parameter accepts Int (widening)
+      f : (x: Float) -> Float -> x;
+      r1 : f 2;
+
+      // Number supertype accepts Int or Float
+      idN : (x: Number) -> Number -> x;
+      n1 : idN 2;
+      n2 : idN 2.5;
+
+      // Return type Number accepts either Int or Float (use dummy arg since zero-arg call syntax is not supported)
+      retN1 : (z: Int) -> Number -> 3;
+      retN2 : (z: Int) -> Number -> 3.5;
+      v1 : retN1 0;
+      v2 : retN2 0;
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('r1').value, 2);
+    assert.strictEqual(itp.scope.get('n1').value, 2);
+    assert.ok(Math.abs(itp.scope.get('n2').value - 2.5) < 1e-12);
+    assert.strictEqual(itp.scope.get('v1').value, 3);
+    assert.ok(Math.abs(itp.scope.get('v2').value - 3.5) < 1e-12);
+  });
+});
+
+