github.com/pdfcpu/pdfcpu@v0.11.1/pkg/filter/filter_test.go (about) 1 /* 2 Copyright 2018 The pdfcpu Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package filter_test 18 19 import ( 20 "errors" 21 "io" 22 "os" 23 "strings" 24 "testing" 25 26 "github.com/pdfcpu/pdfcpu/pkg/filter" 27 ) 28 29 func TestFilterSupport(t *testing.T) { 30 var filtersTests = []struct { 31 filterName string 32 expected error 33 }{ 34 {filter.ASCII85, nil}, 35 {filter.ASCIIHex, nil}, 36 {filter.RunLength, nil}, 37 {filter.LZW, nil}, 38 {filter.Flate, nil}, 39 {filter.CCITTFax, nil}, 40 {filter.DCT, nil}, 41 {filter.JBIG2, filter.ErrUnsupportedFilter}, 42 {filter.JPX, filter.ErrUnsupportedFilter}, 43 {"INVALID_FILTER", errors.New("Invalid filter: <INVALID_FILTER>")}, 44 } 45 for _, tt := range filtersTests { 46 _, err := filter.NewFilter(tt.filterName, nil) 47 if (tt.expected != nil && err != nil && err.Error() != tt.expected.Error()) || 48 ((err == nil || tt.expected == nil) && err != tt.expected) { 49 t.Errorf("Problem: '%s' (expected '%s')\n", err.Error(), tt.expected.Error()) 50 } 51 } 52 } 53 54 // Encode a test string with filterName then decode and check if result matches original. 55 func encodeDecodeString(t *testing.T, filterName string) { 56 t.Helper() 57 58 filter, err := filter.NewFilter(filterName, nil) 59 if err != nil { 60 t.Fatalf("Problem: %v\n", err) 61 } 62 63 want := "Hello, Gopher!" 64 t.Logf("encoding using filter %s: len:%d % X <%s>\n", filterName, len(want), want, want) 65 66 b1, err := filter.Encode(strings.NewReader(want)) 67 if err != nil { 68 t.Fatalf("Problem encoding 1: %v\n", err) 69 } 70 //t.Logf("encoded 1: len:%d % X <%s>\n", b1.Len(), b1.Bytes(), b1.Bytes()) 71 72 b2, err := filter.Encode(b1) 73 if err != nil { 74 t.Fatalf("Problem encoding 2: %v\n", err) 75 } 76 //t.Logf("encoded 2: len:%d % X <%s>\n", b2.Len(), b2.Bytes(), b2.Bytes()) 77 78 c1, err := filter.Decode(b2) 79 if err != nil { 80 t.Fatalf("Problem decoding 2: %v\n", err) 81 } 82 //t.Logf("decoded 2: len:%d % X <%s>\n", c1.Len(), c1.Bytes(), c1.Bytes()) 83 84 c2, err := filter.Decode(c1) 85 if err != nil { 86 t.Fatalf("Problem decoding 1: %v\n", err) 87 } 88 //t.Logf("decoded 1: len:%d % X <%s>\n", c2.Len(), c2.Bytes(), c2.Bytes()) 89 90 bb, err := io.ReadAll(c2) 91 if err != nil { 92 t.Fatalf("%v\n", err) 93 } 94 got := string(bb) 95 if got != want { 96 t.Fatalf("got:%s want:%s\n", got, want) 97 } 98 } 99 100 func TestEncodeDecodeString(t *testing.T) { 101 for _, f := range filter.List() { 102 encodeDecodeString(t, f) 103 } 104 } 105 106 var filenames = []string{ 107 "testdata/gettysburg.txt", 108 "testdata/e.txt", 109 "testdata/pi.txt", 110 "testdata/Mark.Twain-Tom.Sawyer.txt", 111 } 112 113 // Encode fileName with filterName then decode and check if result matches original. 114 func encodeDecode(t *testing.T, fileName, filterName string) { 115 t.Helper() 116 117 t.Logf("testFile: %s with filter:%s\n", fileName, filterName) 118 119 f, err := filter.NewFilter(filterName, nil) 120 if err != nil { 121 t.Errorf("Problem: %v\n", err) 122 } 123 124 raw, err := os.Open(fileName) 125 if err != nil { 126 t.Errorf("%s: %v", fileName, err) 127 return 128 } 129 defer raw.Close() 130 131 enc, err := f.Encode(raw) 132 if err != nil { 133 t.Errorf("Problem encoding: %v\n", err) 134 } 135 136 dec, err := f.Decode(enc) 137 if err != nil { 138 t.Errorf("Problem decoding: %v\n", err) 139 } 140 141 // Compare decoded bytes with original bytes. 142 golden, err := os.Open(fileName) 143 if err != nil { 144 t.Errorf("%s: %v", fileName, err) 145 return 146 } 147 defer golden.Close() 148 149 g, err := io.ReadAll(golden) 150 if err != nil { 151 t.Errorf("%s: %v", fileName, err) 152 return 153 } 154 155 d, err := io.ReadAll(dec) 156 if err != nil { 157 t.Errorf("%s: %v", fileName, err) 158 return 159 } 160 161 if len(d) != len(g) { 162 t.Errorf("%s: length mismatch %d != %d", fileName, len(d), len(g)) 163 return 164 } 165 166 for i := 0; i < len(d); i++ { 167 if d[i] != g[i] { 168 t.Errorf("%s: mismatch at %d, 0x%02x != 0x%02x\n", fileName, i, d[i], g[i]) 169 return 170 } 171 } 172 173 } 174 175 func TestEncodeDecode(t *testing.T) { 176 for _, filterName := range filter.List() { 177 for _, filename := range filenames { 178 encodeDecode(t, filename, filterName) 179 } 180 } 181 } 182 183 func encode(t *testing.T, r io.Reader, filterName string) io.Reader { 184 t.Helper() 185 186 f, err := filter.NewFilter(filterName, nil) 187 if err != nil { 188 t.Errorf("Problem: %v\n", err) 189 } 190 191 r, err = f.Encode(r) 192 if err != nil { 193 t.Errorf("Problem encoding: %v\n", err) 194 } 195 196 return r 197 } 198 199 func decode(t *testing.T, r io.Reader, filterName string) io.Reader { 200 t.Helper() 201 202 f, err := filter.NewFilter(filterName, nil) 203 if err != nil { 204 t.Errorf("Problem: %v\n", err) 205 } 206 207 r, err = f.Decode(r) 208 if err != nil { 209 t.Errorf("Problem decoding: %v\n", err) 210 } 211 212 return r 213 } 214 215 // Encode fileName with filter pipeline then decode and check if result matches original. 216 func encodeDecodeFilterPipeline(t *testing.T, fileName string, fpl []string) { 217 t.Helper() 218 219 f0, err := os.Open(fileName) 220 if err != nil { 221 t.Errorf("%s: %v", fileName, err) 222 return 223 } 224 defer f0.Close() 225 226 r := io.Reader(f0) 227 228 for i := len(fpl) - 1; i >= 0; i-- { 229 r = encode(t, r, fpl[i]) 230 } 231 232 for _, f := range fpl { 233 r = decode(t, r, f) 234 } 235 236 // Compare decoded bytes with original bytes. 237 golden, err := os.Open(fileName) 238 if err != nil { 239 t.Errorf("%s: %v", fileName, err) 240 return 241 } 242 defer golden.Close() 243 244 g, err := io.ReadAll(golden) 245 if err != nil { 246 t.Errorf("%s: %v", fileName, err) 247 return 248 } 249 250 d, err := io.ReadAll(r) 251 if err != nil { 252 t.Errorf("%s: %v", fileName, err) 253 return 254 } 255 256 if len(d) != len(g) { 257 t.Errorf("%s: length mismatch %d != %d", fileName, len(d), len(g)) 258 return 259 } 260 261 for i := 0; i < len(d); i++ { 262 if d[i] != g[i] { 263 t.Errorf("%s: mismatch at %d, 0x%02x != 0x%02x\n", fileName, i, d[i], g[i]) 264 return 265 } 266 } 267 } 268 269 func TestEncodeDecodeFilterPipeline(t *testing.T) { 270 for _, filename := range filenames { 271 encodeDecodeFilterPipeline(t, filename, []string{filter.ASCII85, filter.Flate}) 272 } 273 } 274 275 // TestASCII85DecodeWithCRLF tests that ASCII85 decoding works correctly 276 // when the encoded data has CRLF line endings (issue #1112) 277 func TestASCII85DecodeWithCRLF(t *testing.T) { 278 f, err := filter.NewFilter(filter.ASCII85, nil) 279 if err != nil { 280 t.Fatalf("Failed to create ASCII85 filter: %v", err) 281 } 282 283 testCases := []struct { 284 name string 285 input string 286 ending string 287 expected string 288 }{ 289 {"LF ending", "Hello, Gopher!", "\n", "Hello, Gopher!"}, 290 {"CR ending", "Hello, Gopher!", "\r", "Hello, Gopher!"}, 291 {"CRLF ending", "Hello, Gopher!", "\r\n", "Hello, Gopher!"}, 292 {"No ending", "Hello, Gopher!", "", "Hello, Gopher!"}, 293 } 294 295 for _, tc := range testCases { 296 t.Run(tc.name, func(t *testing.T) { 297 // Encode the input 298 encoded, err := f.Encode(strings.NewReader(tc.input)) 299 if err != nil { 300 t.Fatalf("Encoding failed: %v", err) 301 } 302 303 // Read encoded data 304 encodedBytes, err := io.ReadAll(encoded) 305 if err != nil { 306 t.Fatalf("Reading encoded data failed: %v", err) 307 } 308 309 // Add the specified line ending 310 encodedWithEnding := append(encodedBytes, []byte(tc.ending)...) 311 312 // Decode 313 decoded, err := f.Decode(strings.NewReader(string(encodedWithEnding))) 314 if err != nil { 315 t.Fatalf("Decoding failed with %q ending: %v", tc.ending, err) 316 } 317 318 // Verify result 319 result, err := io.ReadAll(decoded) 320 if err != nil { 321 t.Fatalf("Reading decoded data failed: %v", err) 322 } 323 324 if string(result) != tc.expected { 325 t.Errorf("Mismatch: got %q, want %q", string(result), tc.expected) 326 } 327 }) 328 } 329 }