# test.build/core/converters/graph.converter.test.ts

> 91 lines of code and 0 definitions.

Tree: Codebase Testing
Language: typescript
Canonical: https://banes-lab.com/anatomy/testing#file-testing-test-build-core-converters-graph-converter-test-ts
Source text: https://banes-lab.com/source/testing/test.build/core/converters/graph.converter.test.ts.txt

Listed in [test.build/core/converters](https://banes-lab.com/api/source/testing/test.build/core/converters.md), after [test.build/core/converters/graph.concern.converter.test.ts](https://banes-lab.com/source/testing/test.build/core/converters/graph.concern.converter.test.ts.md) and before [test.build/core/converters/graph.fixture.ts](https://banes-lab.com/source/testing/test.build/core/converters/graph.fixture.ts.md).

## Contained in

- [test.build/core/converters](https://banes-lab.com/anatomy/testing/folder-testing-test-build-core-converters.md)

## Source

```typescript
import { CONTAINS_RELATION, EVIDENCE_RELATION_ID } from "@banes-lab/web/constants/graph.constants";
import { REFERENCED_BY, VOCABULARY, graphNode } from "./graph.fixture.ts";
import {
    danglingEdges,
    edgeIndexOf,
    groundingSources,
    inboundRelations,
    mergeGraphs,
    outboundRelations,
} from "@banes-lab/build-scripts/core/converters/graph.converter.ts";
import { describe, expect, it } from "vitest";

const A = "architecture:a";
const B = "architecture:b";
const GRAPH = { edges: [{ from: A, relation: "requires", to: B }], nodes: [graphNode(A, null), graphNode(B, null)] };

describe("inboundRelations", () => {
    it("groups each node's inbound edges under the declared reverse, titled by the source", () => {
        expect(inboundRelations(GRAPH, VOCABULARY.pairs).get(B)).toStrictEqual([
            { edges: [{ label: A, ref: A }], relation: REFERENCED_BY },
        ]);
        expect(() =>
            inboundRelations({ edges: [{ from: "a", relation: "invented", to: "b" }], nodes: [] }, VOCABULARY.pairs),
        ).toThrow('the relation "invented" from a has no reverse');
    });
});

describe("outboundRelations", () => {
    it("groups each node's outgoing edges under their own relation, titled by the target, once per target", () => {
        const twice = { edges: [...GRAPH.edges, ...GRAPH.edges], nodes: GRAPH.nodes };
        expect(outboundRelations(twice).get(A)).toStrictEqual([
            { edges: [{ label: B, ref: B }], relation: "requires" },
        ]);
        expect(outboundRelations(GRAPH).get(B)).toBeUndefined();
    });
});

describe("edgeIndexOf", () => {
    it("answers each node's outgoing and incoming edges by relation", () => {
        const index = edgeIndexOf(GRAPH);
        expect(index.outgoing(A, "requires")).toStrictEqual([{ label: B, ref: B }]);
        expect(index.incoming(B, "requires")).toStrictEqual([{ label: A, ref: A }]);
        expect(index.incoming(A, "requires")).toStrictEqual([]);
    });
});

describe("groundingSources", () => {
    const SECTION = "chapter:/anatomy#f";
    const FOLDER = "anatomy:f";
    const FILE = "anatomy:f/x.ts";
    const TEACHER = "chapter:/p#s";
    const OTHER = "chapter:/p#t";
    const graph = {
        edges: [
            { from: TEACHER, relation: EVIDENCE_RELATION_ID, to: FOLDER },
            { from: FOLDER, relation: CONTAINS_RELATION, to: FILE },
            { from: OTHER, relation: EVIDENCE_RELATION_ID, to: FILE },
        ],
        nodes: [
            graphNode(SECTION, "/anatomy#f"),
            graphNode(FOLDER, "/anatomy#f"),
            graphNode(FILE, null),
            graphNode(TEACHER, null),
            graphNode(OTHER, null),
        ],
    };

    it("reads evidence into every node that shares the ref's page address, so a folder cited as evidence grounds its section", () => {
        const sources = groundingSources(graph, edgeIndexOf(graph), (ref) => (ref === SECTION ? "/anatomy#f" : null));
        expect(sources(SECTION)).toStrictEqual([{ label: TEACHER, ref: TEACHER }]);
    });

    it("reads evidence into the parts a node contains, and lists each source once", () => {
        const sources = groundingSources(graph, edgeIndexOf(graph), () => null);
        expect(sources(FOLDER)).toStrictEqual([
            { label: TEACHER, ref: TEACHER },
            { label: OTHER, ref: OTHER },
        ]);
        expect(sources(TEACHER)).toStrictEqual([]);
    });
});

describe("mergeGraphs", () => {
    it("keeps the first node per ref, stores each edge once and reports a ref claimed by two kinds", () => {
        const clash = { ...graphNode(B, null), kind: "other" };
        const merged = mergeGraphs([GRAPH, { edges: GRAPH.edges, nodes: [clash] }]);
        expect(merged.nodes).toHaveLength(2);
        expect(merged.edges).toHaveLength(1);
        expect(merged.duplicates).toHaveLength(1);
    });
});

describe("danglingEdges", () => {
    it("names an edge whose end no node carries", () => {
        expect(danglingEdges(GRAPH)).toStrictEqual([]);
        expect(
            danglingEdges({ edges: [{ from: A, relation: "requires", to: "gone" }], nodes: GRAPH.nodes }),
        ).toHaveLength(1);
    });
});
```
