1import { assertEquals, assertRejects, assertThrows } from "@std/assert";2import { type ImportResolver, JrsonnetError, State, ValKind } from "./mod.ts";34Deno.test("evaluateSnippet returns numbers", () => {5 const state = new State();6 const v = state.evaluateSnippet("test.jsonnet", "1 + 2");7 assertEquals(v.kind, ValKind.Num);8 assertEquals(v.asNum(), 3);9});1011Deno.test("evaluateSnippet returns booleans", () => {12 const state = new State();13 const v = state.evaluateSnippet("test.jsonnet", "true && !false");14 assertEquals(v.kind, ValKind.Bool);15 assertEquals(v.asBool(), true);16});1718Deno.test("evaluateSnippet returns strings", () => {19 const state = new State();20 const v = state.evaluateSnippet("test.jsonnet", "'hello ' + 'world'");21 assertEquals(v.kind, ValKind.Str);22 assertEquals(v.asString(), "hello world");23});2425Deno.test("evaluateSnippet returns null", () => {26 const state = new State();27 const v = state.evaluateSnippet("test.jsonnet", "null");28 assertEquals(v.kind, ValKind.Null);29 assertEquals(v.asNum(), undefined);30});3132Deno.test("Val.asArr exposes ArrValue", () => {33 const state = new State();34 const arr = state.evaluateSnippet("test.jsonnet", "[10, 20, 30]").asArr();35 if (!arr) throw new Error("expected array");36 assertEquals(arr.length, 3);37 assertEquals(arr.at(1)?.asNum(), 20);38 assertEquals(arr.at(99), undefined);39});4041Deno.test("Val.asObj exposes ObjValue", () => {42 const state = new State();43 const obj = state.evaluateSnippet("test.jsonnet", "{a: 1, b: 'two'}").asObj();44 if (!obj) throw new Error("expected object");45 assertEquals(obj.keys().sort(), ["a", "b"]);46 assertEquals(obj.get("a")?.asNum(), 1);47 assertEquals(obj.get("b")?.asString(), "two");48 assertEquals(obj.get("missing"), undefined);49});5051Deno.test("evaluateSnippet manifests JSON", () => {52 const state = new State();53 const v = state.evaluateSnippet("test.jsonnet", "{a: 1, b: [2, 3]}");54 assertEquals(v.manifestJson(0), '{"a":1,"b":[2,3]}');55});5657Deno.test("evaluateSnippet propagates jsonnet errors", () => {58 const state = new State();59 assertThrows(() => state.evaluateSnippet("test.jsonnet", "error 'boom'"));60});6162Deno.test("evaluateFile without resolver rejects", async () => {63 const state = new State();64 await assertRejects(() => state.evaluateFile("anything.jsonnet"));65});6667Deno.test("resolver errors become JrsonnetError with cause", async () => {68 const original = new Error("disk on fire");69 const resolver: ImportResolver = {70 resolveFrom(_from, path) {71 return Promise.resolve(`memory:///${path}`);72 },73 loadFileContents(_resolved) {74 throw original;75 },76 };77 const state = new State(resolver);78 const err = await assertRejects(79 () => state.evaluateFile("anything.jsonnet"),80 JrsonnetError,81 "loadFileContents",82 );83 assertEquals(err.cause, original);84 assertEquals(err.frames[0]?.desc, "loadFileContents");85 86 assertEquals((err.stack ?? "").includes(".wasm"), false);87});8889Deno.test("Val.applyTla calls function with named args", () => {90 const state = new State();91 const fn = state.evaluateSnippet(92 "test.jsonnet",93 "function(x, y) x + y",94 );95 const result = fn.applyTla({96 x: state.evaluateSnippet("x.jsonnet", "10"),97 y: state.evaluateSnippet("y.jsonnet", "32"),98 });99 assertEquals(result.asNum(), 42);100});101102Deno.test("Val.applyTla borrows args without consuming them", () => {103 const state = new State();104 const fn = state.evaluateSnippet("test.jsonnet", "function(x) x * 2");105 const x = state.evaluateSnippet("x.jsonnet", "21");106 assertEquals(fn.applyTla({ x }).asNum(), 42);107 assertEquals(x.asNum(), 21);108 assertEquals(fn.applyTla({ x }).asNum(), 42);109});110111Deno.test("Val.applyTla on non-function returns the value unchanged", () => {112 const state = new State();113 const v = state.evaluateSnippet("test.jsonnet", "123");114 assertEquals(v.applyTla({}).asNum(), 123);115});116117Deno.test("evaluateFileFrom resolves relative paths", async () => {118 const files: Record<string, string> = {119 "memory:///root/main.jsonnet": "import 'lib.jsonnet'",120 "memory:///root/lib.jsonnet": "{ answer: 42 }",121 };122 const resolver: ImportResolver = {123 resolveFrom(from, path) {124 const base = from ?? "memory:///root/";125 return Promise.resolve(new URL(path, base).toString());126 },127 loadFileContents(resolved) {128 const code = files[resolved];129 if (code === undefined) throw new Error(`missing ${resolved}`);130 return Promise.resolve(new TextEncoder().encode(code));131 },132 };133 const state = new State(resolver);134 const v = await state.evaluateFileFrom(135 "memory:///root/main.jsonnet",136 "./lib.jsonnet",137 );138 assertEquals(v.asObj()?.get("answer")?.asNum(), 42);139});