blocks_test.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // Copyright (C) 2014 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package scanner
  7. import (
  8. "bytes"
  9. "context"
  10. "crypto/rand"
  11. "fmt"
  12. origAdler32 "hash/adler32"
  13. "testing"
  14. "testing/quick"
  15. rollingAdler32 "github.com/chmduquesne/rollinghash/adler32"
  16. "github.com/syncthing/syncthing/lib/protocol"
  17. )
  18. var blocksTestData = []struct {
  19. data []byte
  20. blocksize int
  21. hash []string
  22. weakhash []uint32
  23. }{
  24. {[]byte(""), 1024, []string{
  25. "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
  26. []uint32{0},
  27. },
  28. {[]byte("contents"), 1024, []string{
  29. "d1b2a59fbea7e20077af9f91b27e95e865061b270be03ff539ab3b73587882e8"},
  30. []uint32{0x0f3a036f},
  31. },
  32. {[]byte("contents"), 9, []string{
  33. "d1b2a59fbea7e20077af9f91b27e95e865061b270be03ff539ab3b73587882e8"},
  34. []uint32{0x0f3a036f},
  35. },
  36. {[]byte("contents"), 8, []string{
  37. "d1b2a59fbea7e20077af9f91b27e95e865061b270be03ff539ab3b73587882e8"},
  38. []uint32{0x0f3a036f},
  39. },
  40. {[]byte("contents"), 7, []string{
  41. "ed7002b439e9ac845f22357d822bac1444730fbdb6016d3ec9432297b9ec9f73",
  42. "043a718774c572bd8a25adbeb1bfcd5c0256ae11cecf9f9c3f925d0e52beaf89"},
  43. []uint32{0x0bcb02fc, 0x00740074},
  44. },
  45. {[]byte("contents"), 3, []string{
  46. "1143da2bc54c495c4be31d3868785d39ffdfd56df5668f0645d8f14d47647952",
  47. "e4432baa90819aaef51d2a7f8e148bf7e679610f3173752fabb4dcb2d0f418d3",
  48. "44ad63f60af0f6db6fdde6d5186ef78176367df261fa06be3079b6c80c8adba4"},
  49. []uint32{0x02780141, 0x02970148, 0x015d00e8},
  50. },
  51. {[]byte("conconts"), 3, []string{
  52. "1143da2bc54c495c4be31d3868785d39ffdfd56df5668f0645d8f14d47647952",
  53. "1143da2bc54c495c4be31d3868785d39ffdfd56df5668f0645d8f14d47647952",
  54. "44ad63f60af0f6db6fdde6d5186ef78176367df261fa06be3079b6c80c8adba4"},
  55. []uint32{0x02780141, 0x02780141, 0x015d00e8},
  56. },
  57. {[]byte("contenten"), 3, []string{
  58. "1143da2bc54c495c4be31d3868785d39ffdfd56df5668f0645d8f14d47647952",
  59. "e4432baa90819aaef51d2a7f8e148bf7e679610f3173752fabb4dcb2d0f418d3",
  60. "e4432baa90819aaef51d2a7f8e148bf7e679610f3173752fabb4dcb2d0f418d3"},
  61. []uint32{0x02780141, 0x02970148, 0x02970148},
  62. },
  63. }
  64. func TestBlocks(t *testing.T) {
  65. for testNo, test := range blocksTestData {
  66. buf := bytes.NewBuffer(test.data)
  67. blocks, err := Blocks(context.TODO(), buf, test.blocksize, -1, nil, true)
  68. if err != nil {
  69. t.Fatal(err)
  70. }
  71. if l := len(blocks); l != len(test.hash) {
  72. t.Fatalf("%d: Incorrect number of blocks %d != %d", testNo, l, len(test.hash))
  73. } else {
  74. i := 0
  75. for off := int64(0); off < int64(len(test.data)); off += int64(test.blocksize) {
  76. if blocks[i].Offset != off {
  77. t.Errorf("%d/%d: Incorrect offset %d != %d", testNo, i, blocks[i].Offset, off)
  78. }
  79. bs := test.blocksize
  80. if rem := len(test.data) - int(off); bs > rem {
  81. bs = rem
  82. }
  83. if int(blocks[i].Size) != bs {
  84. t.Errorf("%d/%d: Incorrect length %d != %d", testNo, i, blocks[i].Size, bs)
  85. }
  86. if h := fmt.Sprintf("%x", blocks[i].Hash); h != test.hash[i] {
  87. t.Errorf("%d/%d: Incorrect block hash %q != %q", testNo, i, h, test.hash[i])
  88. }
  89. if h := blocks[i].WeakHash; h != test.weakhash[i] {
  90. t.Errorf("%d/%d: Incorrect block weakhash 0x%08x != 0x%08x", testNo, i, h, test.weakhash[i])
  91. }
  92. i++
  93. }
  94. }
  95. }
  96. }
  97. func TestAdler32Variants(t *testing.T) {
  98. // Verify that the two adler32 functions give matching results for a few
  99. // different blocks of data.
  100. hf1 := origAdler32.New()
  101. hf2 := rollingAdler32.New()
  102. checkFn := func(data []byte) bool {
  103. hf1.Write(data)
  104. sum1 := hf1.Sum32()
  105. hf2.Write(data)
  106. sum2 := hf2.Sum32()
  107. hf1.Reset()
  108. hf2.Reset()
  109. return sum1 == sum2
  110. }
  111. // protocol block sized data
  112. data := make([]byte, protocol.BlockSize)
  113. for i := 0; i < 5; i++ {
  114. rand.Read(data)
  115. if !checkFn(data) {
  116. t.Errorf("Hash mismatch on block sized data")
  117. }
  118. }
  119. // random small blocks
  120. if err := quick.Check(checkFn, nil); err != nil {
  121. t.Error(err)
  122. }
  123. // rolling should have the same result as the individual blocks
  124. // themselves. Which is not the same as the original non-rollind adler32
  125. // blocks.
  126. windowSize := 128
  127. hf2.Reset()
  128. hf3 := rollingAdler32.New()
  129. hf3.Write(data[:windowSize])
  130. for i := windowSize; i < len(data); i++ {
  131. if i%windowSize == 0 {
  132. // let the reference function catch up
  133. hf2.Write(data[i-windowSize : i])
  134. // verify that they are in sync with the rolling function
  135. sum2 := hf2.Sum32()
  136. sum3 := hf3.Sum32()
  137. t.Logf("At i=%d, sum2=%08x, sum3=%08x", i, sum2, sum3)
  138. if sum2 != sum3 {
  139. t.Errorf("Mismatch after roll; i=%d, sum2=%08x, sum3=%08x", i, sum2, sum3)
  140. break
  141. }
  142. }
  143. hf3.Roll(data[i])
  144. }
  145. }