writer_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. // Copyright 2012 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package flate
  5. import (
  6. "archive/zip"
  7. "bytes"
  8. "compress/flate"
  9. "fmt"
  10. "io"
  11. "math"
  12. "math/rand"
  13. "os"
  14. "runtime"
  15. "strconv"
  16. "strings"
  17. "testing"
  18. )
  19. func TestWriterMemUsage(t *testing.T) {
  20. testMem := func(t *testing.T, fn func()) {
  21. var before, after runtime.MemStats
  22. runtime.GC()
  23. runtime.ReadMemStats(&before)
  24. fn()
  25. runtime.GC()
  26. runtime.ReadMemStats(&after)
  27. t.Logf("%s: Memory Used: %dKB, %d allocs", t.Name(), (after.HeapInuse-before.HeapInuse)/1024, after.HeapObjects-before.HeapObjects)
  28. }
  29. data := make([]byte, 100000)
  30. t.Run(fmt.Sprint("stateless"), func(t *testing.T) {
  31. testMem(t, func() {
  32. StatelessDeflate(io.Discard, data, false, nil)
  33. })
  34. })
  35. for level := HuffmanOnly; level <= BestCompression; level++ {
  36. t.Run(fmt.Sprint("level-", level), func(t *testing.T) {
  37. var zr *Writer
  38. var err error
  39. testMem(t, func() {
  40. zr, err = NewWriter(io.Discard, level)
  41. if err != nil {
  42. t.Fatal(err)
  43. }
  44. zr.Write(data)
  45. })
  46. zr.Close()
  47. })
  48. }
  49. for level := HuffmanOnly; level <= BestCompression; level++ {
  50. t.Run(fmt.Sprint("stdlib-", level), func(t *testing.T) {
  51. var zr *flate.Writer
  52. var err error
  53. testMem(t, func() {
  54. zr, err = flate.NewWriter(io.Discard, level)
  55. if err != nil {
  56. t.Fatal(err)
  57. }
  58. zr.Write(data)
  59. })
  60. zr.Close()
  61. })
  62. }
  63. }
  64. func TestWriterRegression(t *testing.T) {
  65. data, err := os.ReadFile("testdata/regression.zip")
  66. if err != nil {
  67. t.Fatal(err)
  68. }
  69. for level := HuffmanOnly; level <= BestCompression; level++ {
  70. t.Run(fmt.Sprint("level_", level), func(t *testing.T) {
  71. zr, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
  72. if err != nil {
  73. t.Fatal(err)
  74. }
  75. for _, tt := range zr.File {
  76. if !strings.HasSuffix(t.Name(), "") {
  77. continue
  78. }
  79. t.Run(tt.Name, func(t *testing.T) {
  80. if testing.Short() && tt.FileInfo().Size() > 10000 {
  81. t.SkipNow()
  82. }
  83. r, err := tt.Open()
  84. if err != nil {
  85. t.Error(err)
  86. return
  87. }
  88. in, err := io.ReadAll(r)
  89. if err != nil {
  90. t.Error(err)
  91. }
  92. msg := "level " + strconv.Itoa(level) + ":"
  93. buf := new(bytes.Buffer)
  94. fw, err := NewWriter(buf, level)
  95. if err != nil {
  96. t.Fatal(msg + err.Error())
  97. }
  98. n, err := fw.Write(in)
  99. if n != len(in) {
  100. t.Fatal(msg + "short write")
  101. }
  102. if err != nil {
  103. t.Fatal(msg + err.Error())
  104. }
  105. err = fw.Close()
  106. if err != nil {
  107. t.Fatal(msg + err.Error())
  108. }
  109. fr1 := NewReader(buf)
  110. data2, err := io.ReadAll(fr1)
  111. if err != nil {
  112. t.Fatal(msg + err.Error())
  113. }
  114. if !bytes.Equal(in, data2) {
  115. t.Fatal(msg + "not equal")
  116. }
  117. // Do it again...
  118. msg = "level " + strconv.Itoa(level) + " (reset):"
  119. buf.Reset()
  120. fw.Reset(buf)
  121. n, err = fw.Write(in)
  122. if n != len(in) {
  123. t.Fatal(msg + "short write")
  124. }
  125. if err != nil {
  126. t.Fatal(msg + err.Error())
  127. }
  128. err = fw.Close()
  129. if err != nil {
  130. t.Fatal(msg + err.Error())
  131. }
  132. fr1 = NewReader(buf)
  133. data2, err = io.ReadAll(fr1)
  134. if err != nil {
  135. t.Fatal(msg + err.Error())
  136. }
  137. if !bytes.Equal(in, data2) {
  138. t.Fatal(msg + "not equal")
  139. }
  140. })
  141. }
  142. })
  143. }
  144. }
  145. func benchmarkEncoder(b *testing.B, testfile, level, n int) {
  146. b.SetBytes(int64(n))
  147. buf0, err := os.ReadFile(testfiles[testfile])
  148. if err != nil {
  149. b.Fatal(err)
  150. }
  151. if len(buf0) == 0 {
  152. b.Fatalf("test file %q has no data", testfiles[testfile])
  153. }
  154. buf1 := make([]byte, n)
  155. for i := 0; i < n; i += len(buf0) {
  156. if len(buf0) > n-i {
  157. buf0 = buf0[:n-i]
  158. }
  159. copy(buf1[i:], buf0)
  160. }
  161. buf0 = nil
  162. runtime.GC()
  163. w, err := NewWriter(io.Discard, level)
  164. if err != nil {
  165. b.Fatal(err)
  166. }
  167. b.ResetTimer()
  168. b.ReportAllocs()
  169. for i := 0; i < b.N; i++ {
  170. w.Reset(io.Discard)
  171. _, err = w.Write(buf1)
  172. if err != nil {
  173. b.Fatal(err)
  174. }
  175. err = w.Close()
  176. if err != nil {
  177. b.Fatal(err)
  178. }
  179. }
  180. }
  181. func BenchmarkEncodeDigitsConstant1e4(b *testing.B) { benchmarkEncoder(b, digits, constant, 1e4) }
  182. func BenchmarkEncodeDigitsConstant1e5(b *testing.B) { benchmarkEncoder(b, digits, constant, 1e5) }
  183. func BenchmarkEncodeDigitsConstant1e6(b *testing.B) { benchmarkEncoder(b, digits, constant, 1e6) }
  184. func BenchmarkEncodeDigitsSpeed1e4(b *testing.B) { benchmarkEncoder(b, digits, speed, 1e4) }
  185. func BenchmarkEncodeDigitsSpeed1e5(b *testing.B) { benchmarkEncoder(b, digits, speed, 1e5) }
  186. func BenchmarkEncodeDigitsSpeed1e6(b *testing.B) { benchmarkEncoder(b, digits, speed, 1e6) }
  187. func BenchmarkEncodeDigitsDefault1e4(b *testing.B) { benchmarkEncoder(b, digits, default_, 1e4) }
  188. func BenchmarkEncodeDigitsDefault1e5(b *testing.B) { benchmarkEncoder(b, digits, default_, 1e5) }
  189. func BenchmarkEncodeDigitsDefault1e6(b *testing.B) { benchmarkEncoder(b, digits, default_, 1e6) }
  190. func BenchmarkEncodeDigitsCompress1e4(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e4) }
  191. func BenchmarkEncodeDigitsCompress1e5(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e5) }
  192. func BenchmarkEncodeDigitsCompress1e6(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e6) }
  193. func BenchmarkEncodeDigitsSL1e4(b *testing.B) { benchmarkStatelessEncoder(b, digits, 1e4) }
  194. func BenchmarkEncodeDigitsSL1e5(b *testing.B) { benchmarkStatelessEncoder(b, digits, 1e5) }
  195. func BenchmarkEncodeDigitsSL1e6(b *testing.B) { benchmarkStatelessEncoder(b, digits, 1e6) }
  196. func BenchmarkEncodeTwainConstant1e4(b *testing.B) { benchmarkEncoder(b, twain, constant, 1e4) }
  197. func BenchmarkEncodeTwainConstant1e5(b *testing.B) { benchmarkEncoder(b, twain, constant, 1e5) }
  198. func BenchmarkEncodeTwainConstant1e6(b *testing.B) { benchmarkEncoder(b, twain, constant, 1e6) }
  199. func BenchmarkEncodeTwainSpeed1e4(b *testing.B) { benchmarkEncoder(b, twain, speed, 1e4) }
  200. func BenchmarkEncodeTwainSpeed1e5(b *testing.B) { benchmarkEncoder(b, twain, speed, 1e5) }
  201. func BenchmarkEncodeTwainSpeed1e6(b *testing.B) { benchmarkEncoder(b, twain, speed, 1e6) }
  202. func BenchmarkEncodeTwainDefault1e4(b *testing.B) { benchmarkEncoder(b, twain, default_, 1e4) }
  203. func BenchmarkEncodeTwainDefault1e5(b *testing.B) { benchmarkEncoder(b, twain, default_, 1e5) }
  204. func BenchmarkEncodeTwainDefault1e6(b *testing.B) { benchmarkEncoder(b, twain, default_, 1e6) }
  205. func BenchmarkEncodeTwainCompress1e4(b *testing.B) { benchmarkEncoder(b, twain, compress, 1e4) }
  206. func BenchmarkEncodeTwainCompress1e5(b *testing.B) { benchmarkEncoder(b, twain, compress, 1e5) }
  207. func BenchmarkEncodeTwainCompress1e6(b *testing.B) { benchmarkEncoder(b, twain, compress, 1e6) }
  208. func BenchmarkEncodeTwainSL1e4(b *testing.B) { benchmarkStatelessEncoder(b, twain, 1e4) }
  209. func BenchmarkEncodeTwainSL1e5(b *testing.B) { benchmarkStatelessEncoder(b, twain, 1e5) }
  210. func BenchmarkEncodeTwainSL1e6(b *testing.B) { benchmarkStatelessEncoder(b, twain, 1e6) }
  211. func benchmarkStatelessEncoder(b *testing.B, testfile, n int) {
  212. b.SetBytes(int64(n))
  213. buf0, err := os.ReadFile(testfiles[testfile])
  214. if err != nil {
  215. b.Fatal(err)
  216. }
  217. if len(buf0) == 0 {
  218. b.Fatalf("test file %q has no data", testfiles[testfile])
  219. }
  220. buf1 := make([]byte, n)
  221. for i := 0; i < n; i += len(buf0) {
  222. if len(buf0) > n-i {
  223. buf0 = buf0[:n-i]
  224. }
  225. copy(buf1[i:], buf0)
  226. }
  227. buf0 = nil
  228. runtime.GC()
  229. b.ResetTimer()
  230. b.ReportAllocs()
  231. for i := 0; i < b.N; i++ {
  232. w := NewStatelessWriter(io.Discard)
  233. _, err = w.Write(buf1)
  234. if err != nil {
  235. b.Fatal(err)
  236. }
  237. err = w.Close()
  238. if err != nil {
  239. b.Fatal(err)
  240. }
  241. }
  242. }
  243. // A writer that fails after N writes.
  244. type errorWriter struct {
  245. N int
  246. }
  247. func (e *errorWriter) Write(b []byte) (int, error) {
  248. if e.N <= 0 {
  249. return 0, io.ErrClosedPipe
  250. }
  251. e.N--
  252. return len(b), nil
  253. }
  254. // Test if errors from the underlying writer is passed upwards.
  255. func TestWriteError(t *testing.T) {
  256. buf := new(bytes.Buffer)
  257. n := 65536
  258. if !testing.Short() {
  259. n *= 4
  260. }
  261. for i := 0; i < n; i++ {
  262. fmt.Fprintf(buf, "asdasfasf%d%dfghfgujyut%dyutyu\n", i, i, i)
  263. }
  264. in := buf.Bytes()
  265. // We create our own buffer to control number of writes.
  266. copyBuf := make([]byte, 128)
  267. for l := 0; l < 10; l++ {
  268. for fail := 1; fail <= 256; fail *= 2 {
  269. // Fail after 'fail' writes
  270. ew := &errorWriter{N: fail}
  271. w, err := NewWriter(ew, l)
  272. if err != nil {
  273. t.Fatalf("NewWriter: level %d: %v", l, err)
  274. }
  275. n, err := copyBuffer(w, bytes.NewBuffer(in), copyBuf)
  276. if err == nil {
  277. t.Fatalf("Level %d: Expected an error, writer was %#v", l, ew)
  278. }
  279. n2, err := w.Write([]byte{1, 2, 2, 3, 4, 5})
  280. if n2 != 0 {
  281. t.Fatal("Level", l, "Expected 0 length write, got", n)
  282. }
  283. if err == nil {
  284. t.Fatal("Level", l, "Expected an error")
  285. }
  286. err = w.Flush()
  287. if err == nil {
  288. t.Fatal("Level", l, "Expected an error on flush")
  289. }
  290. err = w.Close()
  291. if err == nil {
  292. t.Fatal("Level", l, "Expected an error on close")
  293. }
  294. w.Reset(io.Discard)
  295. n2, err = w.Write([]byte{1, 2, 3, 4, 5, 6})
  296. if err != nil {
  297. t.Fatal("Level", l, "Got unexpected error after reset:", err)
  298. }
  299. if n2 == 0 {
  300. t.Fatal("Level", l, "Got 0 length write, expected > 0")
  301. }
  302. if testing.Short() {
  303. return
  304. }
  305. }
  306. }
  307. }
  308. // Test if errors from the underlying writer is passed upwards.
  309. func TestWriter_Reset(t *testing.T) {
  310. buf := new(bytes.Buffer)
  311. n := 65536
  312. if !testing.Short() {
  313. n *= 4
  314. }
  315. for i := 0; i < n; i++ {
  316. fmt.Fprintf(buf, "asdasfasf%d%dfghfgujyut%dyutyu\n", i, i, i)
  317. }
  318. in := buf.Bytes()
  319. for l := 0; l < 10; l++ {
  320. l := l
  321. if testing.Short() && l > 1 {
  322. continue
  323. }
  324. t.Run(fmt.Sprintf("level-%d", l), func(t *testing.T) {
  325. t.Parallel()
  326. offset := 1
  327. if testing.Short() {
  328. offset = 256
  329. }
  330. for ; offset <= 256; offset *= 2 {
  331. // Fail after 'fail' writes
  332. w, err := NewWriter(io.Discard, l)
  333. if err != nil {
  334. t.Fatalf("NewWriter: level %d: %v", l, err)
  335. }
  336. if w.d.fast == nil {
  337. t.Skip("Not Fast...")
  338. return
  339. }
  340. for i := 0; i < (bufferReset-len(in)-offset-maxMatchOffset)/maxMatchOffset; i++ {
  341. // skip ahead to where we are close to wrap around...
  342. w.d.fast.Reset()
  343. }
  344. w.d.fast.Reset()
  345. _, err = w.Write(in)
  346. if err != nil {
  347. t.Fatal(err)
  348. }
  349. for i := 0; i < 50; i++ {
  350. // skip ahead again... This should wrap around...
  351. w.d.fast.Reset()
  352. }
  353. w.d.fast.Reset()
  354. _, err = w.Write(in)
  355. if err != nil {
  356. t.Fatal(err)
  357. }
  358. for i := 0; i < (math.MaxUint32-bufferReset)/maxMatchOffset; i++ {
  359. // skip ahead to where we are close to wrap around...
  360. w.d.fast.Reset()
  361. }
  362. _, err = w.Write(in)
  363. if err != nil {
  364. t.Fatal(err)
  365. }
  366. err = w.Close()
  367. if err != nil {
  368. t.Fatal(err)
  369. }
  370. }
  371. })
  372. }
  373. }
  374. func TestDeterministicL1(t *testing.T) { testDeterministic(1, t) }
  375. func TestDeterministicL2(t *testing.T) { testDeterministic(2, t) }
  376. func TestDeterministicL3(t *testing.T) { testDeterministic(3, t) }
  377. func TestDeterministicL4(t *testing.T) { testDeterministic(4, t) }
  378. func TestDeterministicL5(t *testing.T) { testDeterministic(5, t) }
  379. func TestDeterministicL6(t *testing.T) { testDeterministic(6, t) }
  380. func TestDeterministicL7(t *testing.T) { testDeterministic(7, t) }
  381. func TestDeterministicL8(t *testing.T) { testDeterministic(8, t) }
  382. func TestDeterministicL9(t *testing.T) { testDeterministic(9, t) }
  383. func TestDeterministicL0(t *testing.T) { testDeterministic(0, t) }
  384. func TestDeterministicLM2(t *testing.T) { testDeterministic(-2, t) }
  385. func testDeterministic(i int, t *testing.T) {
  386. // Test so much we cross a good number of block boundaries.
  387. var length = maxStoreBlockSize*30 + 500
  388. if testing.Short() {
  389. length /= 10
  390. }
  391. // Create a random, but compressible stream.
  392. rng := rand.New(rand.NewSource(1))
  393. t1 := make([]byte, length)
  394. for i := range t1 {
  395. t1[i] = byte(rng.Int63() & 7)
  396. }
  397. // Do our first encode.
  398. var b1 bytes.Buffer
  399. br := bytes.NewBuffer(t1)
  400. w, err := NewWriter(&b1, i)
  401. if err != nil {
  402. t.Fatal(err)
  403. }
  404. // Use a very small prime sized buffer.
  405. cbuf := make([]byte, 787)
  406. _, err = copyBuffer(w, br, cbuf)
  407. if err != nil {
  408. t.Fatal(err)
  409. }
  410. w.Close()
  411. // We choose a different buffer size,
  412. // bigger than a maximum block, and also a prime.
  413. var b2 bytes.Buffer
  414. cbuf = make([]byte, 81761)
  415. br2 := bytes.NewBuffer(t1)
  416. w2, err := NewWriter(&b2, i)
  417. if err != nil {
  418. t.Fatal(err)
  419. }
  420. _, err = copyBuffer(w2, br2, cbuf)
  421. if err != nil {
  422. t.Fatal(err)
  423. }
  424. w2.Close()
  425. b1b := b1.Bytes()
  426. b2b := b2.Bytes()
  427. if !bytes.Equal(b1b, b2b) {
  428. t.Errorf("level %d did not produce deterministic result, result mismatch, len(a) = %d, len(b) = %d", i, len(b1b), len(b2b))
  429. }
  430. // Test using io.WriterTo interface.
  431. var b3 bytes.Buffer
  432. br = bytes.NewBuffer(t1)
  433. w, err = NewWriter(&b3, i)
  434. if err != nil {
  435. t.Fatal(err)
  436. }
  437. _, err = br.WriteTo(w)
  438. if err != nil {
  439. t.Fatal(err)
  440. }
  441. w.Close()
  442. b3b := b3.Bytes()
  443. if !bytes.Equal(b1b, b3b) {
  444. t.Errorf("level %d (io.WriterTo) did not produce deterministic result, result mismatch, len(a) = %d, len(b) = %d", i, len(b1b), len(b3b))
  445. }
  446. }
  447. // copyBuffer is a copy of io.CopyBuffer, since we want to support older go versions.
  448. // This is modified to never use io.WriterTo or io.ReaderFrom interfaces.
  449. func copyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err error) {
  450. if buf == nil {
  451. buf = make([]byte, 32*1024)
  452. }
  453. for {
  454. nr, er := src.Read(buf)
  455. if nr > 0 {
  456. nw, ew := dst.Write(buf[0:nr])
  457. if nw > 0 {
  458. written += int64(nw)
  459. }
  460. if ew != nil {
  461. err = ew
  462. break
  463. }
  464. if nr != nw {
  465. err = io.ErrShortWrite
  466. break
  467. }
  468. }
  469. if er == io.EOF {
  470. break
  471. }
  472. if er != nil {
  473. err = er
  474. break
  475. }
  476. }
  477. return written, err
  478. }
  479. func BenchmarkCompressAllocations(b *testing.B) {
  480. payload := []byte(strings.Repeat("Tiny payload", 20))
  481. for j := -2; j <= 9; j++ {
  482. b.Run("level("+strconv.Itoa(j)+")", func(b *testing.B) {
  483. b.Run("flate", func(b *testing.B) {
  484. b.ReportAllocs()
  485. for i := 0; i < b.N; i++ {
  486. w, err := NewWriter(io.Discard, j)
  487. if err != nil {
  488. b.Fatal(err)
  489. }
  490. w.Write(payload)
  491. w.Close()
  492. }
  493. })
  494. })
  495. }
  496. }
  497. func BenchmarkCompressAllocationsSingle(b *testing.B) {
  498. payload := []byte(strings.Repeat("Tiny payload", 20))
  499. const level = 2
  500. b.Run("flate", func(b *testing.B) {
  501. b.ReportAllocs()
  502. for i := 0; i < b.N; i++ {
  503. w, err := NewWriter(io.Discard, level)
  504. if err != nil {
  505. b.Fatal(err)
  506. }
  507. w.Write(payload)
  508. w.Close()
  509. }
  510. })
  511. }