github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/uio/archivereader_test.go (about) 1 // Copyright 2021 the u-root 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 5 package uio 6 7 import ( 8 "bytes" 9 "io" 10 "math/rand" 11 "strings" 12 "testing" 13 "time" 14 15 "github.com/pierrec/lz4/v4" 16 ) 17 18 const choices = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 19 20 func TestArchiveReaderRegular(t *testing.T) { 21 dataStr := strings.Repeat("This is an important data!@#$%^^&&*&**(()())", 1000) 22 23 ar, err := NewArchiveReader(bytes.NewReader([]byte(dataStr))) 24 if err != nil { 25 t.Fatalf("newArchiveReader(bytes.NewReader(%v)) returned error: %v", []byte(dataStr), err) 26 } 27 28 buf := new(strings.Builder) 29 if _, err := io.Copy(buf, ar); err != nil { 30 t.Errorf("io.Copy(%v, %v) returned error: %v, want nil.", buf, ar, err) 31 } 32 if buf.String() != dataStr { 33 t.Errorf("got %s, want %s", buf.String(), dataStr) 34 } 35 } 36 37 func TestArchiveReaderPreReadShort(t *testing.T) { 38 dataStr := "short data" 39 ar, err := NewArchiveReader(bytes.NewReader([]byte(dataStr))) 40 if err != nil { 41 t.Errorf("newArchiveReader(bytes.NewReader([]byte(%s))) returned err: %v, want nil", dataStr, err) 42 } 43 got, err := io.ReadAll(ar) 44 if err != nil { 45 t.Errorf("got error reading archive reader: %v, want nil", err) 46 } 47 if string(got) != dataStr { 48 t.Errorf("got %s, want %s", string(got), dataStr) 49 } 50 // Pre-read nothing. 51 dataStr = "" 52 ar, err = NewArchiveReader(bytes.NewReader([]byte(dataStr))) 53 if err != ErrPreReadError { 54 t.Errorf("newArchiveReader(bytes.NewReader([]byte(%s))) returned err: %v, want %v", dataStr, err, ErrPreReadError) 55 } 56 got, err = io.ReadAll(ar) 57 if err != nil { 58 t.Errorf("got error reading archive reader: %v, want nil", err) 59 } 60 if string(got) != dataStr { 61 t.Errorf("got %s, want %s", string(got), dataStr) 62 } 63 } 64 65 // randomString generates random string of fixed length in a fast and simple way. 66 func randomString(l int) string { 67 rand.Seed(time.Now().UnixNano()) 68 r := make([]byte, l) 69 for i := 0; i < l; i++ { 70 r[i] = byte(choices[rand.Intn(len(choices))]) 71 } 72 return string(r) 73 } 74 75 func checkArchiveReaderLZ4(t *testing.T, tt archiveReaderLZ4Case) { 76 t.Helper() 77 78 srcR := bytes.NewReader([]byte(tt.dataStr)) 79 80 srcBuf := new(bytes.Buffer) 81 lz4w := tt.setup(srcBuf) 82 83 n, err := io.Copy(lz4w, srcR) 84 if err != nil { 85 t.Fatalf("io.Copy(%v, %v) returned error: %v, want nil", lz4w, srcR, err) 86 } 87 if n != int64(len([]byte(tt.dataStr))) { 88 t.Fatalf("got %d bytes compressed, want %d", n, len([]byte(tt.dataStr))) 89 } 90 if err = lz4w.Close(); err != nil { 91 t.Fatalf("Failed to close lz4 writer: %v", err) 92 } 93 94 // Test ArchiveReader reading it. 95 ar, err := NewArchiveReader(bytes.NewReader(srcBuf.Bytes())) 96 if err != nil { 97 t.Fatalf("newArchiveReader(bytes.NewReader(%v)) returned error: %v", srcBuf.Bytes(), err) 98 } 99 buf := new(strings.Builder) 100 if _, err := io.Copy(buf, ar); err != nil { 101 t.Errorf("io.Copy(%v, %v) returned error: %v, want nil.", buf, ar, err) 102 } 103 if buf.String() != tt.dataStr { 104 t.Errorf("got %s, want %s", buf.String(), tt.dataStr) 105 } 106 } 107 108 type archiveReaderLZ4Case struct { 109 name string 110 setup func(w io.Writer) *lz4.Writer 111 dataStr string 112 } 113 114 func TestArchiveReaderLZ4(t *testing.T) { 115 for _, tt := range []archiveReaderLZ4Case{ 116 { 117 name: "non-legacy regular", 118 setup: func(w io.Writer) *lz4.Writer { 119 return lz4.NewWriter(w) 120 }, 121 dataStr: randomString(1024), 122 }, 123 { 124 name: "non-legacy larger data", 125 setup: func(w io.Writer) *lz4.Writer { 126 return lz4.NewWriter(w) 127 }, 128 dataStr: randomString(5 * 1024), 129 }, 130 { 131 name: "non-legacy short data", // Likley not realistic for most cases in the real world. 132 setup: func(w io.Writer) *lz4.Writer { 133 return lz4.NewWriter(w) 134 }, 135 dataStr: randomString(100), // Smaller than pre-read size, 1024 bytes. 136 }, 137 { 138 name: "legacy regular", 139 setup: func(w io.Writer) *lz4.Writer { 140 lz4w := lz4.NewWriter(w) 141 lz4w.Apply(lz4.LegacyOption(true)) 142 return lz4w 143 }, 144 dataStr: randomString(1024), 145 }, 146 { 147 name: "legacy larger data", 148 setup: func(w io.Writer) *lz4.Writer { 149 lz4w := lz4.NewWriter(w) 150 lz4w.Apply(lz4.LegacyOption(true)) 151 return lz4w 152 }, 153 dataStr: randomString(5 * 1024), 154 }, 155 { 156 name: "legacy small data", 157 setup: func(w io.Writer) *lz4.Writer { 158 lz4w := lz4.NewWriter(w) 159 lz4w.Apply(lz4.LegacyOption(true)) 160 return lz4w 161 }, 162 dataStr: randomString(100), // Smaller than pre-read size, 1024 bytes.. 163 }, 164 { 165 name: "legacy small data", 166 setup: func(w io.Writer) *lz4.Writer { 167 lz4w := lz4.NewWriter(w) 168 lz4w.Apply(lz4.LegacyOption(true)) 169 return lz4w 170 }, 171 dataStr: randomString(100), // Smaller than pre-read size, 1024 bytes.. 172 }, 173 { 174 name: "regular larger data with fast compression", 175 setup: func(w io.Writer) *lz4.Writer { 176 lz4w := lz4.NewWriter(w) 177 lz4w.Apply(lz4.CompressionLevelOption(lz4.Fast)) 178 return lz4w 179 }, 180 dataStr: randomString(5 * 1024), 181 }, 182 { 183 name: "legacy larger data with fast compression", 184 setup: func(w io.Writer) *lz4.Writer { 185 lz4w := lz4.NewWriter(w) 186 lz4w.Apply(lz4.LegacyOption(true)) 187 lz4w.Apply(lz4.CompressionLevelOption(lz4.Fast)) 188 return lz4w 189 }, 190 dataStr: randomString(5 * 1024), 191 }, 192 } { 193 t.Run(tt.name, func(t *testing.T) { 194 checkArchiveReaderLZ4(t, tt) 195 }) 196 } 197 } 198 199 func TestArchiveReaderLZ4SlowCompressed(t *testing.T) { 200 for _, tt := range []archiveReaderLZ4Case{ 201 { 202 name: "regular larger data with medium compression", 203 setup: func(w io.Writer) *lz4.Writer { 204 lz4w := lz4.NewWriter(w) 205 lz4w.Apply(lz4.CompressionLevelOption(lz4.Level5)) 206 return lz4w 207 }, 208 dataStr: randomString(5 * 1024), 209 }, 210 { 211 name: "regular larger data with slow compression", 212 setup: func(w io.Writer) *lz4.Writer { 213 lz4w := lz4.NewWriter(w) 214 lz4w.Apply(lz4.CompressionLevelOption(lz4.Level9)) 215 return lz4w 216 }, 217 dataStr: randomString(5 * 1024), 218 }, 219 { 220 name: "legacy larger data with medium compression", 221 setup: func(w io.Writer) *lz4.Writer { 222 lz4w := lz4.NewWriter(w) 223 lz4w.Apply(lz4.LegacyOption(true)) 224 lz4w.Apply(lz4.CompressionLevelOption(lz4.Level5)) 225 return lz4w 226 }, 227 dataStr: randomString(5 * 1024), 228 }, 229 { 230 name: "legacy larger data with slow compression", 231 setup: func(w io.Writer) *lz4.Writer { 232 lz4w := lz4.NewWriter(w) 233 lz4w.Apply(lz4.LegacyOption(true)) 234 lz4w.Apply(lz4.CompressionLevelOption(lz4.Level9)) 235 return lz4w 236 }, 237 dataStr: randomString(5 * 1024), 238 }, 239 } { 240 t.Run(tt.name, func(t *testing.T) { 241 checkArchiveReaderLZ4(t, tt) 242 }) 243 } 244 }