package crypto import ( "testing" "git.mleku.dev/mleku/dendrite/pkg/axiom" "git.mleku.dev/mleku/dendrite/pkg/lattice" "git.mleku.dev/mleku/dendrite/pkg/ratio" ) type testElem struct { tag string val string } func (e testElem) Type() string { return e.tag } func (e testElem) Value() any { return e.val } func buildBondedLattice(n int) *lattice.Lattice { l := lattice.New() nodes := make([]*lattice.Node, n) for i := range nodes { nodes[i] = l.AddNode([]axiom.Constraint{tagConstraint{"word"}}) } // Ring topology. for i := range nodes { l.Connect(nodes[i], nodes[(i+1)%len(nodes)]) } // Bond half the nodes. for i := 0; i < n/2; i++ { nodes[i].Bond(testElem{"word", string(rune('a' + i))}) } return l } func TestNewSampler(t *testing.T) { l := buildBondedLattice(20) gs := NewSampler(l, ratio.New(4, 10)) if gs.Lattice != l { t.Error("sampler should reference the lattice") } if !gs.Threshold.Equal(ratio.New(4, 10)) { t.Errorf("threshold = %s, want 4/10", gs.Threshold) } } func TestSampleReturnsPattern(t *testing.T) { l := buildBondedLattice(20) gs := NewSampler(l, ratio.New(4, 10)) marks := gs.Sample() if len(marks) != l.Size() { t.Errorf("sample length = %d, want %d", len(marks), l.Size()) } // At least some should be occupied (high lock-in survivors). occupied := 0 for _, m := range marks { if m.Occupied { occupied++ } } // We bonded 10 of 20 nodes. With ring topology each bonded node // has ~1 bonded neighbor out of 2, giving contextual lock-in of // 0.3 + 0.7*(1/2) = 0.65 > 0.4 threshold. Most should survive. if occupied == 0 { t.Error("expected at least some occupied sites after sampling") } } func TestNoiseVectorLength(t *testing.T) { l := buildBondedLattice(16) gs := NewSampler(l, ratio.New(8, 10)) // high threshold = more dissolution vec, _ := gs.NoiseVector() if len(vec) != l.Size() { t.Errorf("noise vector length = %d, want %d", len(vec), l.Size()) } } func TestSnapshotConsistency(t *testing.T) { l := buildBondedLattice(10) s1 := snapshot(l) s2 := snapshot(l) if len(s1) != len(s2) { t.Fatal("snapshots should have same length") } for i := range s1 { if s1[i].Occupied != s2[i].Occupied { t.Errorf("site %d occupancy mismatch", i) } if s1[i].TypeTag != s2[i].TypeTag { t.Errorf("site %d type tag mismatch", i) } } }