git @ Cat's Eye Technologies Jaft / master test / jaftConcoctor.test.js
master

Tree @master (Download .tar.gz)

jaftConcoctor.test.js @masterraw · history · blame

// Copyright (c) 2026 Chris Pressey, Cat's Eye Technologies.
//
// SPDX-License-Identifier: LicenseRef-MIT-X-Jaft

import { describe, it, expect } from "vitest";
import { bless } from "concoctor";
import { concoctJaft as concoct } from "../src/jaftConcoctor.js";

describe("Concoct...", () => {
  describe("concoct with ternary", () => {
    it("should create function using ternary operator", () => {
      const gt = bless((a, b) => a > b);
      const neg = bless((a) => 0 - a);
      const abs = concoct({ gt, neg }, "(x) => gt(x, 0) ? x : neg(x)");

      expect(abs(5)).toBe(5);
      expect(abs(-5)).toBe(5);
    });

    it("should handle nested ternary", () => {
      const gt = bless((a, b) => a > b);
      const neg = bless((a) => 0 - a);
      const sign = concoct(
        { gt, neg },
        "(x) => gt(x, 0) ? 1 : (gt(0, x) ? neg(1) : 0)",
      );

      expect(sign(5)).toBe(1);
      expect(sign(0)).toBe(0);
      expect(sign(-5)).toBe(-1);
    });
  });

  describe("concoct with let", () => {
    it("should create function using let expression", () => {
      const add = bless((a, b) => a + b);
      const mul = bless((a, b) => a * b);
      const formula = concoct(
        { add, mul },
        "(a, b) => let x = add(a, b); mul(x, x)",
      );

      expect(formula(3, 4)).toBe(49); // (3 + 4)^2 = 49
    });

    it("should handle multiple bindings in let", () => {
      const add = bless((a, b) => a + b);
      const mul = bless((a, b) => a * b);
      const formula = concoct(
        { add, mul },
        "(a, b) => let x = add(a, b), y = mul(a, b); add(x, y)",
      );

      expect(formula(3, 4)).toBe(19); // (3 + 4) + (3 * 4) = 7 + 12 = 19
    });

    it("should handle nested let expressions", () => {
      const add = bless((a, b) => a + b);
      const nested = concoct(
        { add },
        "(a) => let x = add(a, 1); let y = add(x, 1); add(y, 1)",
      );

      expect(nested(5)).toBe(8); // 5 + 1 + 1 + 1 = 8
    });
  });

  describe("concoct with const", () => {
    it("should create function using const expression", () => {
      const add = bless((a, b) => a + b);
      const mul = bless((a, b) => a * b);
      const formula = concoct(
        { add, mul },
        "(a, b) => const x = add(a, b); mul(x, x)",
      );

      expect(formula(3, 4)).toBe(49); // (3 + 4)^2 = 49
    });
  });
});

describe("Binary operators", () => {
  describe("concoct with binops", () => {
    it("should create function using arithmetic operators", () => {
      const formula = concoct({}, "(a, b, c) => a + b * c");
      expect(formula(2, 3, 4)).toBe(14); // 2 + (3 * 4)
    });

    it("should create function using comparison and arithmetic", () => {
      const compare = concoct({}, "(x, y) => x * 2 >= y + 10");
      expect(compare(10, 5)).toBe(true); // 20 >= 15
      expect(compare(5, 10)).toBe(false); // 10 >= 20
    });

    it("should handle division, modulo, and subtraction", () => {
      const calc = concoct({}, "(a, b) => a / b + a % b - 1");
      expect(calc(10, 2)).toBe(4); // 5 + 0 - 1 = 4
    });

    it("should support member access", () => {
      const getLength = concoct({}, "(obj) => obj.length");
      expect(getLength({ length: 5 })).toBe(5);
      expect(getLength([1, 2, 3])).toBe(3);
    });

    it("should combine operators with ternary and let", () => {
      const complex = concoct(
        {},
        "(x) => let y = x * 2; y >= 10 ? y + 1 : y - 1",
      );
      expect(complex(6)).toBe(13); // y=12, 12>=10, so 12+1
      expect(complex(3)).toBe(5); // y=6, 6<10, so 6-1
    });

    it("should allow operators to replace blessed function calls", () => {
      // Previously needed: bless((a,b) => a+b) and bless((a,b) => a*b)
      const formula = concoct({}, "(a, b) => (a + 1) * (b + 1)");
      expect(formula(2, 3)).toBe(12); // (2+1) * (3+1) = 3 * 4
    });

    it("should handle strict equality", () => {
      const strictEq = concoct({}, "(a, b) => a === b");
      expect(strictEq(5, 5)).toBe(true);
      expect(strictEq(5, "5")).toBe(false);
    });
  });
});