package projection import ( "testing" "git.mleku.dev/mleku/dendrite/pkg/permutation" "git.mleku.dev/mleku/dendrite/pkg/state" ) func TestVertexTrigramRoundTrip(t *testing.T) { for v := Vertex(0); v < VertexCount; v++ { tri := v.Trigram() if uint8(tri) != uint8(v) { t.Errorf("vertex %d: trigram = %d, want %d", v, tri, v) } } } func TestPackUnpack(t *testing.T) { for v := Vertex(0); v < VertexCount; v++ { for k := Key(0); k < KeyCount; k++ { p := Pack(v, k) if p.Vertex() != v { t.Errorf("Pack(%d,%d).Vertex() = %d", v, k, p.Vertex()) } if p.Key() != k { t.Errorf("Pack(%d,%d).Key() = %d", v, k, p.Key()) } } } } func TestProjectionCount(t *testing.T) { // 8 vertices × 8 keys = 64 projections. seen := make(map[Projection]bool) for v := Vertex(0); v < VertexCount; v++ { for k := Key(0); k < KeyCount; k++ { seen[Pack(v, k)] = true } } if len(seen) != ProjectionCount { t.Errorf("unique projections = %d, want %d", len(seen), ProjectionCount) } } func TestKeyPermutation(t *testing.T) { cases := []struct { key Key perm permutation.Perm }{ {KeyFaceXY, permutation.Identity}, {KeyFaceXZ, permutation.Swap12}, {KeyFaceYZ, permutation.Swap02}, {KeyEdgeBias, permutation.Swap01}, {KeyVertexA, permutation.Cycle012}, {KeyVertexB, permutation.Cycle021}, // Collapse keys alias to existing permutations. {KeyCollapseA, permutation.Identity}, {KeyCollapseB, permutation.Swap12}, } for _, tc := range cases { got := tc.key.Permutation() if got != tc.perm { t.Errorf("Key(%d).Permutation() = %v, want %v", tc.key, got, tc.perm) } } } func TestKeyOrder(t *testing.T) { cases := []struct { key Key order int }{ {KeyFaceXY, 2}, {KeyFaceXZ, 2}, {KeyFaceYZ, 2}, {KeyEdgeBias, 2}, {KeyVertexA, 3}, {KeyVertexB, 3}, {KeyCollapseA, 1}, {KeyCollapseB, 1}, } for _, tc := range cases { got := tc.key.Order() if got != tc.order { t.Errorf("Key(%d).Order() = %d, want %d", tc.key, got, tc.order) } } } func TestCollapseKeys(t *testing.T) { for k := Key(0); k < KeyCount; k++ { isCollapse := k.IsCollapse() wantCollapse := k >= KeyCollapseA if isCollapse != wantCollapse { t.Errorf("Key(%d).IsCollapse() = %v, want %v", k, isCollapse, wantCollapse) } } } func TestVisibleEdgesOrder3(t *testing.T) { // Vertex-on projection (order 3) should show all 12 edges. edges := VisibleEdges(KeyVertexA) if len(edges) != 12 { t.Errorf("VertexA visible edges = %d, want 12", len(edges)) } edges = VisibleEdges(KeyVertexB) if len(edges) != 12 { t.Errorf("VertexB visible edges = %d, want 12", len(edges)) } } func TestVisibleEdgesCollapse(t *testing.T) { // Collapse projections should show fewer edges. edgesA := VisibleEdges(KeyCollapseA) edgesB := VisibleEdges(KeyCollapseB) if len(edgesA) >= 12 { t.Errorf("CollapseA should show fewer than 12 edges, got %d", len(edgesA)) } if len(edgesB) >= 12 { t.Errorf("CollapseB should show fewer than 12 edges, got %d", len(edgesB)) } } func TestPathCountPositive(t *testing.T) { // Every non-collapse key should have positive path count. for k := Key(0); k < KeyCount; k++ { pc := PathCount(k) edges := VisibleEdges(k) if len(edges) > 0 && pc == 0 { t.Errorf("Key(%d) has %d edges but PathCount = 0", k, len(edges)) } } } func TestProjectionPermutationApplied(t *testing.T) { // Verify that applying a projection key's permutation to a trigram // produces a valid (different or same) trigram. for k := Key(0); k < KeyCount; k++ { p := k.Permutation() for tri := state.Trigram(0); tri < 8; tri++ { result := p.ApplyTrigram(tri) if result > 7 { t.Errorf("Key(%d) perm applied to trigram %d gave invalid %d", k, tri, result) } } } } func TestEncodeFullEncoding(t *testing.T) { enc := Encode(V101, KeyVertexA, 42) if enc.Proj.Vertex() != V101 { t.Errorf("vertex = %d, want %d", enc.Proj.Vertex(), V101) } if enc.Proj.Key() != KeyVertexA { t.Errorf("key = %d, want %d", enc.Proj.Key(), KeyVertexA) } if enc.Path != 42 { t.Errorf("path = %d, want 42", enc.Path) } } func TestVertexString(t *testing.T) { if V000.String() != "Earth(000)" { t.Errorf("V000.String() = %q", V000.String()) } if V111.String() != "Mountain(111)" { t.Errorf("V111.String() = %q", V111.String()) } } func TestKeyString(t *testing.T) { if KeyFaceXY.String() != "FaceXY" { t.Errorf("KeyFaceXY.String() = %q", KeyFaceXY.String()) } if KeyCollapseA.String() != "CollapseA" { t.Errorf("KeyCollapseA.String() = %q", KeyCollapseA.String()) } }