package murmur import ( "encoding/hex" "fmt" "strconv" "testing" ) func TestRotl(t *testing.T) { tests := []struct { in, rotate, exp int64 }{ {123456789, 33, 1060485742448345088}, {-123456789, 33, -1060485733858410497}, {-12345678987654, 33, 1756681988166642059}, {7210216203459776512, 31, -4287945813905642825}, {2453826951392495049, 27, -2013042863942636044}, {270400184080946339, 33, -3553153987756601583}, {2060965185473694757, 31, 6290866853133484661}, {3075794793055692309, 33, -3158909918919076318}, {-6486402271863858009, 31, 405973038345868736}, } for _, test := range tests { t.Run(fmt.Sprintf("%d >> %d", test.in, test.rotate), func(t *testing.T) { if v := rotl(test.in, uint8(test.rotate)); v != test.exp { t.Fatalf("expected %d got %d", test.exp, v) } }) } } func TestFmix(t *testing.T) { tests := []struct { in, exp int64 }{ {123456789, -8107560010088384378}, {-123456789, -5252787026298255965}, {-12345678987654, -1122383578793231303}, {-1241537367799374202, 3388197556095096266}, {-7566534940689533355, 4729783097411765989}, } for _, test := range tests { t.Run(strconv.Itoa(int(test.in)), func(t *testing.T) { if v := fmix(test.in); v != test.exp { t.Fatalf("expected %d got %d", test.exp, v) } }) } } func TestMurmur3H1_CassandraSign(t *testing.T) { key, err := hex.DecodeString("00104327529fb645dd00b883ec39ae448bb800000400066a6b00") if err != nil { t.Fatal(err) } h := Murmur3H1(key) const exp int64 = -9223371632693506265 if h != exp { t.Fatalf("expected %d got %d", exp, h) } } // Test the implementation of murmur3 func TestMurmur3H1(t *testing.T) { // these examples are based on adding a index number to a sample string in // a loop. The expected values were generated by the java datastax murmur3 // implementation. The number of examples here of increasing lengths ensure // test coverage of all tail-length branches in the murmur3 algorithm seriesExpected := [...]uint64{ 0x0000000000000000, // "" 0x2ac9debed546a380, // "0" 0x649e4eaa7fc1708e, // "01" 0xce68f60d7c353bdb, // "012" 0x0f95757ce7f38254, // "0123" 0x0f04e459497f3fc1, // "01234" 0x88c0a92586be0a27, // "012345" 0x13eb9fb82606f7a6, // "0123456" 0x8236039b7387354d, // "01234567" 0x4c1e87519fe738ba, // "012345678" 0x3f9652ac3effeb24, // "0123456789" 0x3f33760ded9006c6, // "01234567890" 0xaed70a6631854cb1, // "012345678901" 0x8a299a8f8e0e2da7, // "0123456789012" 0x624b675c779249a6, // "01234567890123" 0xa4b203bb1d90b9a3, // "012345678901234" 0xa3293ad698ecb99a, // "0123456789012345" 0xbc740023dbd50048, // "01234567890123456" 0x3fe5ab9837d25cdd, // "012345678901234567" 0x2d0338c1ca87d132, // "0123456789012345678" } sample := "" for i, expected := range seriesExpected { assertMurmur3H1(t, []byte(sample), expected) sample = sample + strconv.Itoa(i%10) } // Here are some test examples from other driver implementations assertMurmur3H1(t, []byte("hello"), 0xcbd8a7b341bd9b02) assertMurmur3H1(t, []byte("hello, world"), 0x342fac623a5ebc8e) assertMurmur3H1(t, []byte("19 Jan 2038 at 3:14:07 AM"), 0xb89e5988b737affc) assertMurmur3H1(t, []byte("The quick brown fox jumps over the lazy dog."), 0xcd99481f9ee902c9) } // helper function for testing the murmur3 implementation func assertMurmur3H1(t *testing.T, data []byte, expected uint64) { actual := Murmur3H1(data) if actual != int64(expected) { t.Errorf("Expected h1 = %x for data = %x, but was %x", int64(expected), data, actual) } } // Benchmark of the performance of the murmur3 implementation func BenchmarkMurmur3H1(b *testing.B) { data := make([]byte, 1024) for i := 0; i < 1024; i++ { data[i] = byte(i) } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { h1 := Murmur3H1(data) if h1 != int64(7627370222079200297) { b.Fatalf("expected %d got %d", int64(7627370222079200297), h1) } } }) }