159 lines
5.3 KiB
Go
159 lines
5.3 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestPrepareHierarchyLayoutRequestNormalizesEdges(t *testing.T) {
|
|
nodes := []Node{
|
|
{ID: 0, TermType: "uri", IRI: "http://example.com/root"},
|
|
{ID: 1, TermType: "uri", IRI: "http://example.com/child"},
|
|
{ID: 2, TermType: "uri", IRI: "http://example.com/leaf"},
|
|
}
|
|
preds := NewPredicateDict([]string{"http://www.w3.org/2000/01/rdf-schema#subClassOf"})
|
|
edges := []Edge{
|
|
{Source: 1, Target: 0, PredicateID: 0},
|
|
{Source: 1, Target: 0, PredicateID: 0},
|
|
{Source: 2, Target: 2, PredicateID: 0},
|
|
{Source: 2, Target: 1, PredicateID: 0},
|
|
}
|
|
|
|
prepared := prepareHierarchyLayoutRequest("http://example.com/root", nodes, edges, preds)
|
|
|
|
if got, want := len(prepared.Request.Nodes), 3; got != want {
|
|
t.Fatalf("len(request.nodes)=%d want %d", got, want)
|
|
}
|
|
if got, want := len(prepared.Request.Edges), 2; got != want {
|
|
t.Fatalf("len(request.edges)=%d want %d", got, want)
|
|
}
|
|
if prepared.Request.Edges[0].ParentID != 0 || prepared.Request.Edges[0].ChildID != 1 {
|
|
t.Fatalf("first normalized edge = %+v, want parent=0 child=1", prepared.Request.Edges[0])
|
|
}
|
|
if prepared.Request.Edges[1].ParentID != 1 || prepared.Request.Edges[1].ChildID != 2 {
|
|
t.Fatalf("second normalized edge = %+v, want parent=1 child=2", prepared.Request.Edges[1])
|
|
}
|
|
if prepared.Request.Edges[0].PredicateIRI == nil || *prepared.Request.Edges[0].PredicateIRI == "" {
|
|
t.Fatalf("expected predicate iri to be preserved")
|
|
}
|
|
}
|
|
|
|
func TestApplyHierarchyLayoutResponsePreservesIDsAndRemapsRoutes(t *testing.T) {
|
|
nodes := []Node{
|
|
{ID: 0, TermType: "uri", IRI: "http://example.com/root"},
|
|
{ID: 1, TermType: "uri", IRI: "http://example.com/child"},
|
|
{ID: 2, TermType: "uri", IRI: "http://example.com/leaf"},
|
|
}
|
|
normalizedEdges := []Edge{
|
|
{Source: 1, Target: 0, PredicateID: 0},
|
|
{Source: 2, Target: 0, PredicateID: 0},
|
|
}
|
|
response := hierarchyLayoutResponse{
|
|
Nodes: []hierarchyLayoutResponseNode{
|
|
{NodeID: 0, X: 10, Y: 20},
|
|
{NodeID: 2, X: 30, Y: 40},
|
|
},
|
|
RouteSegments: []hierarchyLayoutResponseRouteSegment{
|
|
{
|
|
EdgeIndex: 1,
|
|
Kind: "spiral",
|
|
Points: []hierarchyLayoutResponseRoutePoint{
|
|
{X: 10, Y: 20},
|
|
{X: 30, Y: 40},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
result, err := applyHierarchyLayoutResponse(nodes, normalizedEdges, response)
|
|
if err != nil {
|
|
t.Fatalf("applyHierarchyLayoutResponse returned error: %v", err)
|
|
}
|
|
|
|
if got, want := len(result.Nodes), 2; got != want {
|
|
t.Fatalf("len(nodes)=%d want %d", got, want)
|
|
}
|
|
if result.Nodes[0].ID != 0 || result.Nodes[1].ID != 2 {
|
|
t.Fatalf("filtered node ids = [%d %d], want [0 2]", result.Nodes[0].ID, result.Nodes[1].ID)
|
|
}
|
|
if result.Nodes[0].X != 10 || result.Nodes[0].Y != 20 || result.Nodes[1].X != 30 || result.Nodes[1].Y != 40 {
|
|
t.Fatalf("positions were not applied to filtered nodes: %+v", result.Nodes)
|
|
}
|
|
if got, want := len(result.Edges), 1; got != want {
|
|
t.Fatalf("len(edges)=%d want %d", got, want)
|
|
}
|
|
if result.Edges[0] != normalizedEdges[1] {
|
|
t.Fatalf("filtered edge = %+v, want %+v", result.Edges[0], normalizedEdges[1])
|
|
}
|
|
if got, want := len(result.RouteSegments), 1; got != want {
|
|
t.Fatalf("len(route_segments)=%d want %d", got, want)
|
|
}
|
|
if result.RouteSegments[0].EdgeIndex != 0 {
|
|
t.Fatalf("route edge index = %d want 0", result.RouteSegments[0].EdgeIndex)
|
|
}
|
|
}
|
|
|
|
func TestRunHierarchyLayoutBridgeUsesConfiguredWorkingDirectory(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
outputPath := filepath.Join(tmpDir, "pwd.txt")
|
|
scriptPath := filepath.Join(tmpDir, "bridge.sh")
|
|
script := "#!/bin/sh\npwd > \"" + outputPath + "\"\ncat >/dev/null\nprintf '{\"nodes\":[{\"node_id\":1,\"x\":10,\"y\":20,\"level\":0}],\"route_segments\":[]}'\n"
|
|
if err := os.WriteFile(scriptPath, []byte(script), 0o755); err != nil {
|
|
t.Fatalf("write script: %v", err)
|
|
}
|
|
|
|
cfg := Config{
|
|
HierarchyLayoutBridgeBin: scriptPath,
|
|
HierarchyLayoutBridgeWorkdir: tmpDir,
|
|
HierarchyLayoutTimeout: 2 * time.Second,
|
|
}
|
|
response, err := runHierarchyLayoutBridge(context.Background(), cfg, hierarchyLayoutRequest{
|
|
RootIRI: "root",
|
|
Nodes: []hierarchyLayoutRequestNode{
|
|
{NodeID: 1, IRI: "root"},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("runHierarchyLayoutBridge returned error: %v", err)
|
|
}
|
|
if got, want := len(response.Nodes), 1; got != want {
|
|
t.Fatalf("len(response.nodes)=%d want %d", got, want)
|
|
}
|
|
|
|
pwdBytes, err := os.ReadFile(outputPath)
|
|
if err != nil {
|
|
t.Fatalf("read pwd output: %v", err)
|
|
}
|
|
if got, want := strings.TrimSpace(string(pwdBytes)), tmpDir; got != want {
|
|
t.Fatalf("bridge working directory=%q want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestRunHierarchyLayoutBridgeReturnsSvgWriteFailure(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
scriptPath := filepath.Join(tmpDir, "bridge_fail.sh")
|
|
script := "#!/bin/sh\ncat >/dev/null\necho 'failed to write SVG output: permission denied' >&2\nexit 1\n"
|
|
if err := os.WriteFile(scriptPath, []byte(script), 0o755); err != nil {
|
|
t.Fatalf("write script: %v", err)
|
|
}
|
|
|
|
cfg := Config{
|
|
HierarchyLayoutBridgeBin: scriptPath,
|
|
HierarchyLayoutBridgeWorkdir: tmpDir,
|
|
HierarchyLayoutTimeout: 2 * time.Second,
|
|
}
|
|
_, err := runHierarchyLayoutBridge(context.Background(), cfg, hierarchyLayoutRequest{
|
|
RootIRI: "root",
|
|
})
|
|
if err == nil {
|
|
t.Fatalf("expected hierarchy layout bridge error")
|
|
}
|
|
if !strings.Contains(err.Error(), "failed to write SVG output") {
|
|
t.Fatalf("error=%q does not mention SVG write failure", err)
|
|
}
|
|
}
|