projection_test.go raw

   1  package projection
   2  
   3  import (
   4  	"testing"
   5  
   6  	"git.mleku.dev/mleku/dendrite/pkg/permutation"
   7  	"git.mleku.dev/mleku/dendrite/pkg/state"
   8  )
   9  
  10  func TestVertexTrigramRoundTrip(t *testing.T) {
  11  	for v := Vertex(0); v < VertexCount; v++ {
  12  		tri := v.Trigram()
  13  		if uint8(tri) != uint8(v) {
  14  			t.Errorf("vertex %d: trigram = %d, want %d", v, tri, v)
  15  		}
  16  	}
  17  }
  18  
  19  func TestPackUnpack(t *testing.T) {
  20  	for v := Vertex(0); v < VertexCount; v++ {
  21  		for k := Key(0); k < KeyCount; k++ {
  22  			p := Pack(v, k)
  23  			if p.Vertex() != v {
  24  				t.Errorf("Pack(%d,%d).Vertex() = %d", v, k, p.Vertex())
  25  			}
  26  			if p.Key() != k {
  27  				t.Errorf("Pack(%d,%d).Key() = %d", v, k, p.Key())
  28  			}
  29  		}
  30  	}
  31  }
  32  
  33  func TestProjectionCount(t *testing.T) {
  34  	// 8 vertices × 8 keys = 64 projections.
  35  	seen := make(map[Projection]bool)
  36  	for v := Vertex(0); v < VertexCount; v++ {
  37  		for k := Key(0); k < KeyCount; k++ {
  38  			seen[Pack(v, k)] = true
  39  		}
  40  	}
  41  	if len(seen) != ProjectionCount {
  42  		t.Errorf("unique projections = %d, want %d", len(seen), ProjectionCount)
  43  	}
  44  }
  45  
  46  func TestKeyPermutation(t *testing.T) {
  47  	cases := []struct {
  48  		key  Key
  49  		perm permutation.Perm
  50  	}{
  51  		{KeyFaceXY, permutation.Identity},
  52  		{KeyFaceXZ, permutation.Swap12},
  53  		{KeyFaceYZ, permutation.Swap02},
  54  		{KeyEdgeBias, permutation.Swap01},
  55  		{KeyVertexA, permutation.Cycle012},
  56  		{KeyVertexB, permutation.Cycle021},
  57  		// Collapse keys alias to existing permutations.
  58  		{KeyCollapseA, permutation.Identity},
  59  		{KeyCollapseB, permutation.Swap12},
  60  	}
  61  	for _, tc := range cases {
  62  		got := tc.key.Permutation()
  63  		if got != tc.perm {
  64  			t.Errorf("Key(%d).Permutation() = %v, want %v", tc.key, got, tc.perm)
  65  		}
  66  	}
  67  }
  68  
  69  func TestKeyOrder(t *testing.T) {
  70  	cases := []struct {
  71  		key   Key
  72  		order int
  73  	}{
  74  		{KeyFaceXY, 2},
  75  		{KeyFaceXZ, 2},
  76  		{KeyFaceYZ, 2},
  77  		{KeyEdgeBias, 2},
  78  		{KeyVertexA, 3},
  79  		{KeyVertexB, 3},
  80  		{KeyCollapseA, 1},
  81  		{KeyCollapseB, 1},
  82  	}
  83  	for _, tc := range cases {
  84  		got := tc.key.Order()
  85  		if got != tc.order {
  86  			t.Errorf("Key(%d).Order() = %d, want %d", tc.key, got, tc.order)
  87  		}
  88  	}
  89  }
  90  
  91  func TestCollapseKeys(t *testing.T) {
  92  	for k := Key(0); k < KeyCount; k++ {
  93  		isCollapse := k.IsCollapse()
  94  		wantCollapse := k >= KeyCollapseA
  95  		if isCollapse != wantCollapse {
  96  			t.Errorf("Key(%d).IsCollapse() = %v, want %v", k, isCollapse, wantCollapse)
  97  		}
  98  	}
  99  }
 100  
 101  func TestVisibleEdgesOrder3(t *testing.T) {
 102  	// Vertex-on projection (order 3) should show all 12 edges.
 103  	edges := VisibleEdges(KeyVertexA)
 104  	if len(edges) != 12 {
 105  		t.Errorf("VertexA visible edges = %d, want 12", len(edges))
 106  	}
 107  	edges = VisibleEdges(KeyVertexB)
 108  	if len(edges) != 12 {
 109  		t.Errorf("VertexB visible edges = %d, want 12", len(edges))
 110  	}
 111  }
 112  
 113  func TestVisibleEdgesCollapse(t *testing.T) {
 114  	// Collapse projections should show fewer edges.
 115  	edgesA := VisibleEdges(KeyCollapseA)
 116  	edgesB := VisibleEdges(KeyCollapseB)
 117  	if len(edgesA) >= 12 {
 118  		t.Errorf("CollapseA should show fewer than 12 edges, got %d", len(edgesA))
 119  	}
 120  	if len(edgesB) >= 12 {
 121  		t.Errorf("CollapseB should show fewer than 12 edges, got %d", len(edgesB))
 122  	}
 123  }
 124  
 125  func TestPathCountPositive(t *testing.T) {
 126  	// Every non-collapse key should have positive path count.
 127  	for k := Key(0); k < KeyCount; k++ {
 128  		pc := PathCount(k)
 129  		edges := VisibleEdges(k)
 130  		if len(edges) > 0 && pc == 0 {
 131  			t.Errorf("Key(%d) has %d edges but PathCount = 0", k, len(edges))
 132  		}
 133  	}
 134  }
 135  
 136  func TestProjectionPermutationApplied(t *testing.T) {
 137  	// Verify that applying a projection key's permutation to a trigram
 138  	// produces a valid (different or same) trigram.
 139  	for k := Key(0); k < KeyCount; k++ {
 140  		p := k.Permutation()
 141  		for tri := state.Trigram(0); tri < 8; tri++ {
 142  			result := p.ApplyTrigram(tri)
 143  			if result > 7 {
 144  				t.Errorf("Key(%d) perm applied to trigram %d gave invalid %d", k, tri, result)
 145  			}
 146  		}
 147  	}
 148  }
 149  
 150  func TestEncodeFullEncoding(t *testing.T) {
 151  	enc := Encode(V101, KeyVertexA, 42)
 152  	if enc.Proj.Vertex() != V101 {
 153  		t.Errorf("vertex = %d, want %d", enc.Proj.Vertex(), V101)
 154  	}
 155  	if enc.Proj.Key() != KeyVertexA {
 156  		t.Errorf("key = %d, want %d", enc.Proj.Key(), KeyVertexA)
 157  	}
 158  	if enc.Path != 42 {
 159  		t.Errorf("path = %d, want 42", enc.Path)
 160  	}
 161  }
 162  
 163  func TestVertexString(t *testing.T) {
 164  	if V000.String() != "Earth(000)" {
 165  		t.Errorf("V000.String() = %q", V000.String())
 166  	}
 167  	if V111.String() != "Mountain(111)" {
 168  		t.Errorf("V111.String() = %q", V111.String())
 169  	}
 170  }
 171  
 172  func TestKeyString(t *testing.T) {
 173  	if KeyFaceXY.String() != "FaceXY" {
 174  		t.Errorf("KeyFaceXY.String() = %q", KeyFaceXY.String())
 175  	}
 176  	if KeyCollapseA.String() != "CollapseA" {
 177  		t.Errorf("KeyCollapseA.String() = %q", KeyCollapseA.String())
 178  	}
 179  }
 180