import { test, expect, mock } from "bun:test"; import { docCreate, sparqlUpdate, sparqlQuery } from "../src/docs"; import * as ngProxy from "../src/ng-proxy"; // NOTE ORDER: the "not configured → throw" case MUST run before any configure() // call, because configure() sets a module-level singleton with no public reset. test("throws a clear error when configure() was not called", async () => { await expect(docCreate("sid", "Graph", "data:graph", "store")).rejects.toThrow( /configure\(\) must be called before use/, ); await expect(sparqlUpdate("sid", "INSERT DATA {}")).rejects.toThrow( /configure\(\) must be called before use/, ); await expect(sparqlQuery("sid", "SELECT * {}")).rejects.toThrow( /configure\(\) must be called before use/, ); }); // From here on, a fake real `ng` is injected via configure(). import { configure } from "../src/polyfill"; function fakeNg() { return { doc_create: mock(async (..._a: unknown[]) => "did:ng:o:new-doc"), sparql_update: mock(async (..._a: unknown[]) => undefined), sparql_query: mock(async (..._a: unknown[]) => ({ results: { bindings: [] } })), // A sentinel: makeNg(), if ever used, would `.bind` and call THIS through // the JS Proxy. We assert the primitives call the raw fns above directly. }; } function inject() { const ng = fakeNg(); configure({ ng: ng as any, useShape: (() => {}) as any }); return ng; } test("docCreate calls the real injected ng.doc_create with the exact args", async () => { const ng = inject(); const nuri = await docCreate("sid-1", "Graph", "data:graph", "store", undefined); expect(nuri).toBe("did:ng:o:new-doc"); expect(ng.doc_create).toHaveBeenCalledTimes(1); expect(ng.doc_create.mock.calls[0]).toEqual(["sid-1", "Graph", "data:graph", "store", undefined]); }); test("sparqlUpdate forwards (sessionId, query, anchor) to the real ng.sparql_update", async () => { const ng = inject(); await sparqlUpdate("sid-2", "INSERT DATA { GRAPH {

} }", "did:ng:o:a"); expect(ng.sparql_update).toHaveBeenCalledTimes(1); expect(ng.sparql_update.mock.calls[0]).toEqual([ "sid-2", "INSERT DATA { GRAPH {

} }", "did:ng:o:a", ]); }); test("sparqlUpdate passes anchor=undefined when omitted", async () => { const ng = inject(); await sparqlUpdate("sid-3", "INSERT DATA {}"); expect(ng.sparql_update.mock.calls[0]).toEqual(["sid-3", "INSERT DATA {}", undefined]); }); test("sparqlQuery forwards (sessionId, query, base, anchor) and returns the raw result", async () => { const ng = inject(); const res = await sparqlQuery("sid-4", "SELECT ?e { GRAPH { ?s ?p ?e } }", undefined, "did:ng:o:g"); expect(res).toEqual({ results: { bindings: [] } }); expect(ng.sparql_query).toHaveBeenCalledTimes(1); expect(ng.sparql_query.mock.calls[0]).toEqual([ "sid-4", "SELECT ?e { GRAPH { ?s ?p ?e } }", undefined, "did:ng:o:g", ]); }); test("the primitives do NOT route through the public ng proxy (makeNg)", async () => { // makeNg builds a JS Proxy over the injected ng. If a primitive went through // it, calls would land on the proxy's `get` trap, not on our raw mock fns. // Spy on makeNg: it must never be invoked by the docs primitives. const spy = mock(ngProxy.makeNg); const ng = inject(); await docCreate("sid", "Graph", "data:graph", "store"); await sparqlUpdate("sid", "INSERT DATA {}"); await sparqlQuery("sid", "SELECT * {}"); expect(spy).toHaveBeenCalledTimes(0); // And the raw injected fns were reached directly: expect(ng.doc_create).toHaveBeenCalledTimes(1); expect(ng.sparql_update).toHaveBeenCalledTimes(1); expect(ng.sparql_query).toHaveBeenCalledTimes(1); });