package clock import ( "math" "reflect" "testing" ) func assertClocksEqual[T Uint](t testing.TB, got, want []T) { t.Helper() if !reflect.DeepEqual(got, want) { t.Errorf("Error: got %v want %v", got, want) } } func TestVectorClock(t *testing.T) { t.Run("test cases for uint32 type", func(t *testing.T) { testCases := []struct { a []uint32 b []uint32 expected []uint32 }{ {[]uint32{0, 0}, []uint32{0, 0}, []uint32{0, 0}}, {[]uint32{2, 0}, []uint32{0, 2}, []uint32{2, 2}}, {[]uint32{4, 11}, []uint32{3, 10}, []uint32{4, 11}}, {[]uint32{5, 9}, []uint32{8, 12}, []uint32{8, 12}}, {[]uint32{1, 1}, []uint32{1, 1}, []uint32{1, 1}}, {[]uint32{math.MaxUint32, 1}, []uint32{2, 1}, []uint32{4294967295, 1}}, } for _, tc := range testCases { vc := VectorClock[uint32]{clock: tc.a} clock, err := vc.Sync(VectorClock[uint32]{clock: tc.b}) if err != nil { t.Errorf("Sync should not have errored") } assertClocksEqual(t, clock, tc.expected) } }) t.Run("test cases for uint64 type", func(t *testing.T) { testCases := []struct { a []uint64 b []uint64 expected []uint64 }{ {[]uint64{0, 0}, []uint64{0, 0}, []uint64{0, 0}}, {[]uint64{2, 0}, []uint64{0, 2}, []uint64{2, 2}}, {[]uint64{4, 11}, []uint64{3, 10}, []uint64{4, 11}}, {[]uint64{5, 9}, []uint64{8, 12}, []uint64{8, 12}}, {[]uint64{1, 1}, []uint64{1, 1}, []uint64{1, 1}}, {[]uint64{math.MaxUint64, 1}, []uint64{2, 1}, []uint64{18446744073709551615, 1}}, } for _, tc := range testCases { vc := VectorClock[uint64]{clock: tc.a} clock, err := vc.Sync(VectorClock[uint64]{clock: tc.b}) if err != nil { t.Errorf("Sync should not have errored") } assertClocksEqual(t, clock, tc.expected) } }) t.Run("test empty new", func(t *testing.T) { got := NewVectorClock[uint32](2) want := VectorClock[uint32]{clock: []uint32{0, 0}} assertClocksEqual(t, got.GetClock(), want.GetClock()) }) t.Run("test new vc for uint32", func(t *testing.T) { vc := VectorClock[uint32]{clock: []uint32{4, 11}} clock, err := vc.Increment(0) if err != nil { t.Errorf("Increment should not have errored") } assertClocksEqual(t, clock, []uint32{5, 11}) clock, err = vc.Increment(1) if err != nil { t.Errorf("Increment should not have errored") } assertClocksEqual(t, clock, []uint32{5, 12}) }) t.Run("test overflow condition", func(t *testing.T) { vc := VectorClock[uint32]{clock: []uint32{math.MaxUint32, 11}} clock, err := vc.Increment(0) if err != nil { t.Errorf("Increment should not have errored") } assertClocksEqual(t, clock, []uint32{0, 11}) }) t.Run("test index cannot be incremented", func(t *testing.T) { vc := VectorClock[uint64]{} clock, err := vc.Increment(0) if clock != nil { t.Errorf("Clock should be nil") } if err == nil { t.Errorf("There should have been an error") } }) } func TestNewVectorClock(t *testing.T) { t.Run("test new vc for uint32", func(t *testing.T) { got := NewVectorClock[uint32](2) want := VectorClock[uint32]{clock: []uint32{0, 0}} assertClocksEqual(t, got.GetClock(), want.GetClock()) }) t.Run("test new vc for uint64", func(t *testing.T) { got := NewVectorClock[uint64](2) want := VectorClock[uint64]{clock: []uint64{0, 0}} assertClocksEqual(t, got.GetClock(), want.GetClock()) }) } func TestArrayToVectorClock(t *testing.T) { t.Run("from empty slice", func(t *testing.T) { got := ArrayToVectorClock([]uint32{}) want := VectorClock[uint32]{ clock: []uint32{}, } if len(got.GetClock()) != 0 { t.Errorf("Expected VectorClock.clock to be of length zero.") } if !reflect.DeepEqual(got.GetClock(), want.GetClock()) { t.Errorf("Error: got %v want %v", got.GetClock(), want.GetClock()) } }) t.Run("from zero slice", func(t *testing.T) { got := ArrayToVectorClock(make([]uint64, 6)) want := VectorClock[uint64]{ clock: []uint64{0, 0, 0, 0, 0, 0}, } assertClocksEqual(t, got.GetClock(), want.GetClock()) }) t.Run("from start clock", func(t *testing.T) { want := NewVectorClock[uint64](3) got := ArrayToVectorClock(want.GetClock()) assertClocksEqual(t, got.GetClock(), want.GetClock()) }) t.Run("from a populated clock", func(t *testing.T) { want := VectorClock[uint32]{ clock: []uint32{2, 3}, } got := ArrayToVectorClock(want.GetClock()) assertClocksEqual(t, got.GetClock(), want.GetClock()) }) t.Run("from a slice that is then modified", func(t *testing.T) { initial_a := []uint64{1, 2, 3, 4} got := ArrayToVectorClock(initial_a) want := make([]uint64, len(initial_a)) copy(want, initial_a) initial_a[0] = 12 initial_a[2] = 4 assertClocksEqual(t, got.GetClock(), want) if reflect.DeepEqual(initial_a, got.GetClock()) { t.Errorf("Initial array %v should not be equal to clock %v", initial_a, got.GetClock()) } }) }