about summary refs log tree commit diff stats
path: root/js/baba-yaga/tests/utilities.test.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/baba-yaga/tests/utilities.test.js')
-rw-r--r--js/baba-yaga/tests/utilities.test.js278
1 files changed, 278 insertions, 0 deletions
diff --git a/js/baba-yaga/tests/utilities.test.js b/js/baba-yaga/tests/utilities.test.js
new file mode 100644
index 0000000..5303fea
--- /dev/null
+++ b/js/baba-yaga/tests/utilities.test.js
@@ -0,0 +1,278 @@
+import { createLexer } from '../src/core/lexer.js';
+import { createParser } from '../src/core/parser.js';
+import { createInterpreter } from '../src/core/interpreter.js';
+
+function runBabaYaga(code) {
+  const lexer = createLexer(code);
+  const tokens = lexer.allTokens();
+  const parser = createParser(tokens);
+  const ast = parser.parse();
+  
+  const outputs = [];
+  const debugOutputs = [];
+  
+  const host = {
+    io: {
+      out: (...args) => outputs.push(args.join(' ')),
+      debug: (...args) => debugOutputs.push(args.join(' ')),
+      in: () => '',
+    },
+  };
+  
+  const interpreter = createInterpreter(ast, host);
+  const result = interpreter.interpret();
+  
+  return { outputs, debugOutputs, result };
+}
+
+describe('Utility Functions', () => {
+  describe('validate namespace', () => {
+    test('validate.notEmpty', () => {
+      const code = `
+        io.out (validate.notEmpty "hello");
+        io.out (validate.notEmpty "");
+        io.out (validate.notEmpty [1, 2, 3]);
+        io.out (validate.notEmpty []);
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['true', 'false', 'true', 'false']);
+    });
+
+    test('validate.range', () => {
+      const code = `
+        io.out (validate.range 1 10 5);
+        io.out (validate.range 1 10 15);
+        io.out (validate.range 1 10 1);
+        io.out (validate.range 1 10 10);
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['true', 'false', 'true', 'true']);
+    });
+
+    test('validate.email', () => {
+      const code = `
+        io.out (validate.email "test@example.com");
+        io.out (validate.email "invalid-email");
+        io.out (validate.email "user@domain.co.uk");
+        io.out (validate.email "@domain.com");
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['true', 'false', 'true', 'false']);
+    });
+
+    test('validate.type', () => {
+      const code = `
+        io.out (validate.type "Int" 42);
+        io.out (validate.type "String" 42);
+        io.out (validate.type "String" "hello");
+        io.out (validate.type "Bool" true);
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['true', 'false', 'true', 'true']);
+    });
+  });
+
+  describe('text namespace', () => {
+    test('text.lines', () => {
+      const code = `
+        // Test with single line (since escape sequences aren't implemented yet)
+        lines : text.lines "hello world test";
+        io.out (length lines);
+        first : lines.0;
+        io.out first;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['1', 'hello world test']);
+    });
+
+    test('text.words', () => {
+      const code = `
+        words : text.words "hello   world  test";
+        io.out (length words);
+        io.out words.0;
+        io.out words.1;
+        io.out words.2;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['3', 'hello', 'world', 'test']);
+    });
+
+    test('text.padLeft and text.padRight', () => {
+      const code = `
+        io.out (text.padLeft 10 "hi");
+        io.out (text.padRight 10 "hi");
+        io.out (str.length (text.padLeft 5 "test"));
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('        hi');
+      expect(outputs[1]).toBe('hi        ');
+      expect(outputs[2]).toBe('5');
+    });
+  });
+
+  describe('utility functions', () => {
+    test('chunk', () => {
+      const code = `
+        numbers : [1, 2, 3, 4, 5, 6];
+        chunks : chunk numbers 2;
+        io.out (length chunks);
+        firstChunk : chunks.0;
+        io.out (length firstChunk);
+        io.out firstChunk.0;
+        io.out firstChunk.1;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['3', '2', '1', '2']);
+    });
+
+    test('range', () => {
+      const code = `
+        r1 : range 1 5;
+        r2 : range 5 1;
+        io.out (length r1);
+        io.out r1.0;
+        io.out r1.4;
+        io.out (length r2);
+        io.out r2.0;
+        io.out r2.4;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['5', '1', '5', '5', '5', '1']);
+    });
+
+    test('repeat', () => {
+      const code = `
+        repeated : repeat 3 "hello";
+        io.out (length repeated);
+        io.out repeated.0;
+        io.out repeated.1;
+        io.out repeated.2;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['3', 'hello', 'hello', 'hello']);
+    });
+  });
+
+  describe('sort namespace', () => {
+    test('sort.by with numbers', () => {
+      const code = `
+        numbers : [3, 1, 4, 1, 5, 9, 2, 6];
+        sorted : sort.by numbers (x -> x);
+        io.out sorted.0;
+        io.out sorted.1;
+        io.out sorted.7;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['1', '1', '9']);
+    });
+
+    test('sort.by with objects', () => {
+      const code = `
+        people : [
+          {name: "Alice", age: 30},
+          {name: "Bob", age: 25},
+          {name: "Charlie", age: 35}
+        ];
+        sortedByAge : sort.by people (p -> p.age);
+        first : sortedByAge.0;
+        second : sortedByAge.1;
+        third : sortedByAge.2;
+        io.out first.name;
+        io.out second.name;
+        io.out third.name;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['Bob', 'Alice', 'Charlie']);
+    });
+  });
+
+  describe('group namespace', () => {
+    test('group.by', () => {
+      const code = `
+        numbers : [1, 2, 3, 4, 5, 6];
+        grouped : group.by numbers (x -> x % 2 = 0);
+        evenGroup : grouped."true";
+        oddGroup : grouped."false";
+        io.out (length evenGroup);
+        io.out (length oddGroup);
+        io.out (evenGroup.0);
+        io.out (oddGroup.0);
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['3', '3', '2', '1']);
+    });
+  });
+
+  describe('random namespace', () => {
+    test('random.choice', () => {
+      const code = `
+        list : [1, 2, 3];
+        choice : random.choice list;
+        io.out (validate.range 1 3 choice);
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['true']);
+    });
+
+    test('random.shuffle', () => {
+      const code = `
+        list : [1, 2, 3, 4, 5];
+        shuffled : random.shuffle list;
+        io.out (length shuffled);
+        io.out (length list);
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['5', '5']);
+    });
+
+    test('random.range', () => {
+      const code = `
+        r : random.range 1 10;
+        io.out (validate.range 1 10 r);
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['true']);
+    });
+  });
+
+  describe('debug namespace', () => {
+    test('debug.print', () => {
+      const code = `
+        testFunc : x -> x * 2;
+        debug.print 42;
+        debug.print testFunc;
+      `;
+      const { debugOutputs } = runBabaYaga(code);
+      expect(debugOutputs.length).toBe(2);
+      expect(debugOutputs[0]).toContain('42');
+      expect(debugOutputs[1]).toContain('function');
+    });
+
+    test('debug.inspect', () => {
+      const code = `
+        testFunc : x -> x * 2;
+        inspection : debug.inspect testFunc;
+        len : str.length inspection;
+        io.out (len > 10);
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['true']);
+    });
+  });
+
+  describe('assert function', () => {
+    test('assert success', () => {
+      const code = `
+        assert (2 + 2 = 4) "Math works";
+        io.out "Success";
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['Success']);
+    });
+
+    test('assert failure', () => {
+      const code = `assert (2 + 2 = 5) "This should fail";`;
+      expect(() => runBabaYaga(code)).toThrow('Assertion failed: This should fail');
+    });
+  });
+});