github.com/unidoc/unidoc@v2.2.0+incompatible/pdf/ps/parser_test.go (about) 1 /* 2 * This file is subject to the terms and conditions defined in 3 * file 'LICENSE.md', which is part of this source code package. 4 */ 5 6 package ps 7 8 import ( 9 "bufio" 10 "bytes" 11 "fmt" 12 "math" 13 "testing" 14 15 "github.com/unidoc/unidoc/common" 16 ) 17 18 func init() { 19 common.SetLogger(common.NewConsoleLogger(common.LogLevelDebug)) 20 //common.SetLogger(common.NewConsoleLogger(common.LogLevelTrace)) 21 } 22 23 func makeReaderForText(txt string) *bufio.Reader { 24 buf := []byte(txt) 25 bufReader := bytes.NewReader(buf) 26 bufferedReader := bufio.NewReader(bufReader) 27 return bufferedReader 28 } 29 30 func quickEval(progText string) (PSObject, error) { 31 parser := NewPSParser([]byte(progText)) 32 33 prog, err := parser.Parse() 34 if err != nil { 35 return nil, err 36 } 37 38 fmt.Printf("%s\n", progText) 39 fmt.Printf("-> Program: %s\n", prog.DebugString()) 40 41 exec := NewPSExecutor(prog) 42 43 outputs, err := exec.Execute(nil) 44 if err != nil { 45 return nil, err 46 } 47 48 if len(outputs) != 1 { 49 return nil, fmt.Errorf("Stack result has too many values (>1)") 50 } 51 52 stack := PSStack(outputs) 53 fmt.Printf("=> Result Stack: %s\n", stack.DebugString()) 54 55 return outputs[0], nil 56 } 57 58 func quickTest(progText string) (*PSStack, error) { 59 parser := NewPSParser([]byte(progText)) 60 61 prog, err := parser.Parse() 62 if err != nil { 63 return nil, err 64 } 65 fmt.Printf("%s\n", progText) 66 fmt.Printf("-> Program: %s\n", prog.DebugString()) 67 68 exec := NewPSExecutor(prog) 69 70 outputs, err := exec.Execute(nil) 71 if err != nil { 72 return nil, err 73 } 74 stack := PSStack(outputs) 75 76 return &stack, nil 77 } 78 79 func TestAdd1(t *testing.T) { 80 progText := "{ 1 1 add }" 81 82 obj, err := quickEval(progText) 83 if err != nil { 84 t.Errorf("Error: %v", err) 85 return 86 } 87 88 val, ok := obj.(*PSInteger) 89 if !ok { 90 t.Errorf("Wrong output type") 91 return 92 } 93 94 if val.Val != 2 { 95 t.Errorf("Wrong result") 96 return 97 } 98 } 99 100 func TestAdd2(t *testing.T) { 101 progText := "{ 1.1 1 add 3 4 add add }" 102 103 obj, err := quickEval(progText) 104 if err != nil { 105 t.Errorf("Error: %v", err) 106 return 107 } 108 109 val, ok := obj.(*PSReal) 110 if !ok { 111 t.Errorf("Wrong output type") 112 return 113 } 114 if math.Abs(val.Val-9.1) > TOLERANCE { 115 t.Errorf("Wrong result") 116 return 117 } 118 } 119 120 //// 8.3 6.6 sub -> 1.7 (real) 121 // 8 6.3 sub -> 1.7 (real) 122 // 8 6 sub -> 2 (int) 123 func TestSub1(t *testing.T) { 124 progText := "{ 8.3 6.6 sub }" 125 126 obj, err := quickEval(progText) 127 if err != nil { 128 t.Errorf("Error: %v", err) 129 return 130 } 131 132 val, ok := obj.(*PSReal) 133 if !ok { 134 t.Errorf("Wrong output type") 135 return 136 } 137 if math.Abs(val.Val-1.7) > TOLERANCE { 138 t.Errorf("Wrong result") 139 return 140 } 141 } 142 143 func TestSub2(t *testing.T) { 144 progText := "{ 8 6.3 sub }" 145 146 obj, err := quickEval(progText) 147 if err != nil { 148 t.Errorf("Error: %v", err) 149 return 150 } 151 152 val, ok := obj.(*PSReal) 153 if !ok { 154 t.Errorf("Wrong output type") 155 return 156 } 157 if math.Abs(val.Val-1.7) > TOLERANCE { 158 t.Errorf("Wrong result") 159 return 160 } 161 } 162 163 func TestSub3(t *testing.T) { 164 progText := "{ 8 6 sub }" 165 166 obj, err := quickEval(progText) 167 if err != nil { 168 t.Errorf("Error: %v", err) 169 return 170 } 171 172 val, ok := obj.(*PSInteger) 173 if !ok { 174 t.Errorf("Wrong output type") 175 return 176 } 177 if val.Val != 2 { 178 t.Errorf("Wrong result") 179 return 180 } 181 } 182 183 // 6 + (3/8) -> 6.375 184 // 3 8 div 6 add 185 // 6 3 8 div add 186 // 187 // 8 - (7*3) -> -13 188 // 8 7 3 mul sub 189 // 7 3 mul 8 exch sub 190 // Simple test entry with a single expected PSObject output. 191 type SimpleTestEntry struct { 192 progText string 193 expected PSObject 194 } 195 196 func TestArithmetics(t *testing.T) { 197 testcases := []SimpleTestEntry{ 198 {progText: "{ 3 8 div 6 add }", expected: MakeReal(6.375)}, 199 {progText: "{ 6 3 8 div add }", expected: MakeReal(6.375)}, 200 {progText: "{ 8 7 3 mul sub }", expected: MakeInteger(-13)}, 201 {progText: "{ 7 3 mul 8 exch sub }", expected: MakeInteger(-13)}, 202 } 203 204 for _, testcase := range testcases { 205 obj, err := quickEval(testcase.progText) 206 if err != nil { 207 t.Errorf("Error: %v", err) 208 return 209 } 210 211 // Maybe not the most robust test (comparing the strings), but should do. 212 if obj.DebugString() != testcase.expected.DebugString() { 213 t.Errorf("Wrong result: %s != %s", obj.DebugString(), testcase.expected.DebugString()) 214 return 215 } 216 } 217 } 218 219 // Complex test entry can have a more complex output. 220 type ComplexTestEntry struct { 221 progText string 222 expected string 223 } 224 225 func TestStackOperations(t *testing.T) { 226 testcases := []ComplexTestEntry{ 227 {progText: "{ 7 8 9 3 1 roll }", expected: "[ int:9 int:7 int:8 ]"}, 228 {progText: "{ 7 8 9 3 -1 roll }", expected: "[ int:8 int:9 int:7 ]"}, 229 {progText: "{ 9 7 8 3 -1 roll }", expected: "[ int:7 int:8 int:9 ]"}, 230 {progText: "{ 1 1 0.2 7 8 9 3 1 roll }", expected: "[ int:1 int:1 real:0.20000 int:9 int:7 int:8 ]"}, 231 } 232 233 for _, testcase := range testcases { 234 stack, err := quickTest(testcase.progText) 235 if err != nil { 236 t.Errorf("Error: %v", err) 237 return 238 } 239 240 // Maybe not the most robust test (comparing the strings), but should do. 241 if stack.DebugString() != testcase.expected { 242 t.Errorf("Wrong result: '%s' != '%s'", stack.DebugString(), testcase.expected) 243 return 244 } 245 } 246 } 247 248 func TestFunctionOperations(t *testing.T) { 249 testcases := []ComplexTestEntry{ 250 // atan 251 {progText: "{ 0 1 atan }", expected: "[ real:0.00000 ]"}, 252 {progText: "{ 1 0 atan }", expected: "[ real:90.00000 ]"}, 253 {progText: "{ -100 0 atan }", expected: "[ real:270.00000 ]"}, 254 {progText: "{ 4 4 atan }", expected: "[ real:45.00000 ]"}, 255 } 256 257 for _, testcase := range testcases { 258 stack, err := quickTest(testcase.progText) 259 if err != nil { 260 t.Errorf("Error: %v", err) 261 return 262 } 263 264 // Maybe not the most robust test (comparing the strings), but should do. 265 if stack.DebugString() != testcase.expected { 266 t.Errorf("Wrong result: '%s' != '%s'", stack.DebugString(), testcase.expected) 267 return 268 } 269 } 270 } 271 272 func TestVariousCases(t *testing.T) { 273 testcases := []ComplexTestEntry{ 274 // dup 275 {progText: "{ 99 dup }", expected: "[ int:99 int:99 ]"}, 276 // ceiling 277 {progText: "{ 3.2 ceiling }", expected: "[ real:4.00000 ]"}, 278 {progText: "{ -4.8 ceiling }", expected: "[ real:-4.00000 ]"}, 279 {progText: "{ 99 ceiling }", expected: "[ int:99 ]"}, 280 // floor 281 {progText: "{ 3.2 floor }", expected: "[ real:3.00000 ]"}, 282 {progText: "{ -4.8 floor }", expected: "[ real:-5.00000 ]"}, 283 {progText: "{ 99 floor }", expected: "[ int:99 ]"}, 284 // exp 285 {progText: "{ 9 0.5 exp }", expected: "[ real:3.00000 ]"}, 286 {progText: "{ -9 -1 exp }", expected: "[ real:-0.11111 ]"}, 287 // and 288 {progText: "{ true true and }", expected: "[ bool:true ]"}, 289 {progText: "{ true false and }", expected: "[ bool:false ]"}, 290 {progText: "{ false true and }", expected: "[ bool:false ]"}, 291 {progText: "{ false false and }", expected: "[ bool:false ]"}, 292 {progText: "{ 99 1 and }", expected: "[ int:1 ]"}, 293 {progText: "{ 52 7 and }", expected: "[ int:4 ]"}, 294 // bitshift 295 {progText: "{ 7 3 bitshift }", expected: "[ int:56 ]"}, 296 {progText: "{ 142 -3 bitshift }", expected: "[ int:17 ]"}, 297 // copy 298 {progText: "{ 7 3 2 copy }", expected: "[ int:7 int:3 int:7 int:3 ]"}, 299 {progText: "{ 7 3 0 copy }", expected: "[ int:7 int:3 ]"}, 300 // cos 301 {progText: "{ 0 cos }", expected: "[ real:1.00000 ]"}, 302 {progText: "{ 90 cos }", expected: "[ real:0.00000 ]"}, 303 // eq. 304 {progText: "{ 4.0 4 eq }", expected: "[ bool:true ]"}, 305 {progText: "{ 4 4.0 eq }", expected: "[ bool:true ]"}, 306 {progText: "{ 4.0 4.0 eq }", expected: "[ bool:true ]"}, 307 {progText: "{ 4 4 eq }", expected: "[ bool:true ]"}, 308 {progText: "{ -4 4 eq }", expected: "[ bool:false ]"}, 309 {progText: "{ false false eq }", expected: "[ bool:true ]"}, 310 {progText: "{ true false eq }", expected: "[ bool:false ]"}, 311 {progText: "{ true 4 eq }", expected: "[ bool:false ]"}, 312 // ge 313 {progText: "{ 4.2 4 ge }", expected: "[ bool:true ]"}, 314 {progText: "{ 4 4 ge }", expected: "[ bool:true ]"}, 315 {progText: "{ 3.9 4 ge }", expected: "[ bool:false ]"}, 316 // gt 317 {progText: "{ 4.2 4 gt }", expected: "[ bool:true ]"}, 318 {progText: "{ 4 4 gt }", expected: "[ bool:false ]"}, 319 {progText: "{ 3.9 4 gt }", expected: "[ bool:false ]"}, 320 // if 321 {progText: "{ 4.2 4 gt {5} if }", expected: "[ int:5 ]"}, 322 {progText: "{ 4.2 4 gt {4.0 4.0 ge {3} if} if}", expected: "[ int:3 ]"}, 323 {progText: "{ 4.0 4.0 gt {5} if }", expected: "[ ]"}, 324 // ifelse 325 {progText: "{ 4.2 4 gt {5} {4} ifelse }", expected: "[ int:5 ]"}, 326 {progText: "{ 3 4 gt {5} {4} ifelse }", expected: "[ int:4 ]"}, 327 // index 328 {progText: "{ 0 1 2 3 4 5 2 index }", expected: "[ int:0 int:1 int:2 int:3 int:4 int:5 int:3 ]"}, 329 {progText: "{ 9 8 7 2 index }", expected: "[ int:9 int:8 int:7 int:9 ]"}, 330 // le 331 {progText: "{ 4.2 4 le }", expected: "[ bool:false ]"}, 332 {progText: "{ 4 4 le }", expected: "[ bool:true ]"}, 333 {progText: "{ 3.9 4 le }", expected: "[ bool:true ]"}, 334 // ln 335 {progText: "{ 10 ln }", expected: "[ real:2.30259 ]"}, 336 {progText: "{ 100 ln }", expected: "[ real:4.60517 ]"}, 337 // log 338 {progText: "{ 10 log }", expected: "[ real:1.00000 ]"}, 339 {progText: "{ 100 log }", expected: "[ real:2.00000 ]"}, 340 // lt 341 {progText: "{ 4.2 4 lt }", expected: "[ bool:false ]"}, 342 {progText: "{ 4 4 lt }", expected: "[ bool:false ]"}, 343 {progText: "{ 3.9 4 lt }", expected: "[ bool:true ]"}, 344 // ne 345 {progText: "{ 4.0 4 ne }", expected: "[ bool:false ]"}, 346 {progText: "{ 4 4.0 ne }", expected: "[ bool:false ]"}, 347 {progText: "{ 4.0 4.0 ne }", expected: "[ bool:false ]"}, 348 {progText: "{ 4 4 ne }", expected: "[ bool:false ]"}, 349 {progText: "{ -4 4 ne }", expected: "[ bool:true ]"}, 350 {progText: "{ false false ne }", expected: "[ bool:false ]"}, 351 {progText: "{ true false ne }", expected: "[ bool:true ]"}, 352 {progText: "{ true 4 ne }", expected: "[ bool:true ]"}, 353 // neg 354 // not 355 {progText: "{ true not }", expected: "[ bool:false ]"}, 356 {progText: "{ false not }", expected: "[ bool:true ]"}, 357 {progText: "{ 52 not }", expected: "[ int:-53 ]"}, 358 // or 359 {progText: "{ true true or }", expected: "[ bool:true ]"}, 360 {progText: "{ true false or }", expected: "[ bool:true ]"}, 361 {progText: "{ false true or }", expected: "[ bool:true ]"}, 362 {progText: "{ false false or }", expected: "[ bool:false ]"}, 363 {progText: "{ 17 5 or }", expected: "[ int:21 ]"}, 364 // pop 365 {progText: "{ 1 2 3 pop }", expected: "[ int:1 int:2 ]"}, 366 {progText: "{ 1 2 pop }", expected: "[ int:1 ]"}, 367 {progText: "{ 1 pop }", expected: "[ ]"}, 368 // round 369 {progText: "{ 3.2 round }", expected: "[ real:3.00000 ]"}, 370 {progText: "{ 6.5 round }", expected: "[ real:7.00000 ]"}, 371 {progText: "{ -4.8 round }", expected: "[ real:-5.00000 ]"}, 372 {progText: "{ -6.5 round }", expected: "[ real:-6.00000 ]"}, 373 {progText: "{ 99 round }", expected: "[ int:99 ]"}, 374 // roll 375 {progText: "{ 1 2 3 3 -1 roll }", expected: "[ int:2 int:3 int:1 ]"}, 376 {progText: "{ 1 2 3 3 1 roll }", expected: "[ int:3 int:1 int:2 ]"}, 377 {progText: "{ 1 2 3 3 0 roll }", expected: "[ int:1 int:2 int:3 ]"}, 378 // sin 379 {progText: "{ 0 sin }", expected: "[ real:0.00000 ]"}, 380 {progText: "{ 90 sin }", expected: "[ real:1.00000 ]"}, 381 // sqrt 382 {progText: "{ 4 sqrt }", expected: "[ real:2.00000 ]"}, 383 {progText: "{ 2 sqrt }", expected: "[ real:1.41421 ]"}, 384 // truncate 385 {progText: "{ 3.2 truncate }", expected: "[ real:3.00000 ]"}, 386 {progText: "{ -4.8 truncate }", expected: "[ real:-4.00000 ]"}, 387 {progText: "{ 99 truncate }", expected: "[ int:99 ]"}, 388 // xor 389 {progText: "{ true true xor }", expected: "[ bool:false ]"}, 390 {progText: "{ true false xor }", expected: "[ bool:true ]"}, 391 {progText: "{ false true xor }", expected: "[ bool:true ]"}, 392 {progText: "{ false false xor }", expected: "[ bool:false ]"}, 393 {progText: "{ 7 3 xor }", expected: "[ int:4 ]"}, 394 {progText: "{ 12 3 xor }", expected: "[ int:15 ]"}, 395 } 396 397 for _, testcase := range testcases { 398 stack, err := quickTest(testcase.progText) 399 if err != nil { 400 t.Errorf("Error: %v", err) 401 return 402 } 403 404 // Maybe not the most robust test (comparing the strings), but should do. 405 if stack.DebugString() != testcase.expected { 406 t.Errorf("Wrong result: '%s' != '%s'", stack.DebugString(), testcase.expected) 407 return 408 } 409 } 410 } 411 412 func TestTintTransform1(t *testing.T) { 413 testcases := []ComplexTestEntry{ 414 // from corpus epson_pages3_color_pages1.pdf. 415 {progText: "{ 0.0000 dup 0 mul exch dup 0 mul exch dup 0 mul exch 1 mul }", expected: "[ real:0.00000 real:0.00000 real:0.00000 real:0.00000 ]"}, 416 } 417 418 for _, testcase := range testcases { 419 stack, err := quickTest(testcase.progText) 420 if err != nil { 421 t.Errorf("Error: %v", err) 422 return 423 } 424 425 // Maybe not the most robust test (comparing the strings), but should do. 426 if stack.DebugString() != testcase.expected { 427 t.Errorf("Wrong result: '%s' != '%s'", stack.DebugString(), testcase.expected) 428 return 429 } 430 } 431 }