blob: b7d8f2d3034a216fd0586c8a806e11b6f4bbeaef [file] [log] [blame]
Nigel Taofb0b1722019-08-06 16:15:09 +10001// Copyright 2019 The Wuffs Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// +build ignore
16
17package main
18
19// rac-random-seek-test.go compresses stdin to the RAC file format, then checks
20// that repeatedly randomly accessing that RAC file recovers the original input.
21//
22// Usage: go run rac-random-seek-test.go < input
23
24import (
25 "bytes"
26 "fmt"
27 "io"
28 "io/ioutil"
29 "math/rand"
30 "os"
31
32 "github.com/google/wuffs/lib/rac"
33 "github.com/google/wuffs/lib/raczlib"
34)
35
36func main() {
37 if err := main1(); err != nil {
38 os.Stderr.WriteString(err.Error() + "\n")
39 os.Exit(1)
40 }
41}
42
43func main1() error {
44 input, err := ioutil.ReadAll(os.Stdin)
45 if err != nil {
46 return err
47 }
48 buf := &bytes.Buffer{}
49 const dChunkSize = 256
50 w := &raczlib.Writer{
51 Writer: buf,
52 DChunkSize: dChunkSize,
53 }
54 if _, err := w.Write(input); err != nil {
55 return err
56 }
57 if err := w.Close(); err != nil {
58 return err
59 }
60 compressed := buf.Bytes()
61 r := &raczlib.Reader{
62 ReadSeeker: bytes.NewReader(compressed),
63 CompressedSize: int64(len(compressed)),
64 }
65 numChunks, err := countRACChunks(compressed)
66 if err != nil {
67 return err
68 }
69 if want := (len(input) + dChunkSize - 1) / dChunkSize; numChunks != want {
70 return fmt.Errorf("numChunks: got %d, want %d", numChunks, want)
71 }
72
73 fmt.Printf("%8d uncompressed bytes\n", len(input))
74 fmt.Printf("%8d compressed bytes\n", len(compressed))
75 fmt.Printf("%8d RAC chunks\n", numChunks)
76
77 got := make([]byte, len(input))
78 if _, err := io.ReadFull(r, got); err != nil {
79 return fmt.Errorf("ReadFull: %v", err)
80 } else if !bytes.Equal(got, input) {
81 return fmt.Errorf("ReadFull: mismatch")
82 }
83
84 for i, rng := uint64(0), rand.New(rand.NewSource(1)); ; i++ {
85 m := rng.Intn(len(input) + 1)
86 n := rng.Intn(len(input) + 1)
87 if m > n {
88 m, n = n, m
89 }
90
91 got = got[:n-m]
92 if _, err := r.Seek(int64(m), io.SeekStart); err != nil {
93 return fmt.Errorf("i=%d, m=%d, n=%d: Seek: %v", i, m, n, err)
94 }
95 if _, err := io.ReadFull(r, got); err != nil {
96 return fmt.Errorf("i=%d, m=%d, n=%d: ReadFull: %v", i, m, n, err)
97 }
98
99 want := input[m:n]
100 if !bytes.Equal(got, want) {
101 return fmt.Errorf("i=%d, m=%d, n=%d: mismatch", i, m, n)
102 }
103
104 if i%1024 == 0 {
105 fmt.Printf("i=%d: ok\n", i)
106 }
107 }
108}
109
110func countRACChunks(compressed []byte) (int, error) {
111 p := &rac.Parser{
112 ReadSeeker: bytes.NewReader(compressed),
113 CompressedSize: int64(len(compressed)),
114 }
115 for n := 0; ; n++ {
116 if _, err := p.NextChunk(); err == io.EOF {
117 return n, nil
118 } else if err != nil {
119 return 0, err
120 }
121 }
122}