diff options
Diffstat (limited to 'js/baba-yaga/tests/utilities.test.js')
-rw-r--r-- | js/baba-yaga/tests/utilities.test.js | 278 |
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'); + }); + }); +}); |