package pdf import "core:testing" // Every Device hook is optional: the text device leaves all the path and image // hooks nil, the display-list device leaves the mask hooks nil. The interpreter // goes through the dev_* wrappers precisely so that costs one predictable // branch instead of a crash, so an all-nil device is the case to pin. @(test) test_device_wrappers_tolerate_nil_hooks :: proc(t: ^testing.T) { p := path_make() defer path_destroy(&p) path_rect(&p, 0, 0, 10, 10) txt := text_make() defer text_destroy(&txt) stroke := STROKE_STATE_DEFAULT paint: Paint call_everything :: proc(dev: ^Device, p: ^Path, txt: ^Text, stroke: ^Stroke_State, paint: Paint) { dev_fill_path(dev, p, false, MATRIX_IDENTITY, paint) dev_stroke_path(dev, p, stroke, MATRIX_IDENTITY, paint) dev_clip_path(dev, p, true, MATRIX_IDENTITY) dev_clip_stroke_path(dev, p, stroke, MATRIX_IDENTITY) dev_clip_text(dev, txt, MATRIX_IDENTITY) dev_clip_image_mask(dev, nil, MATRIX_IDENTITY) dev_pop_clip(dev) dev_fill_text(dev, txt, MATRIX_IDENTITY, paint) dev_stroke_text(dev, txt, stroke, MATRIX_IDENTITY, paint) dev_ignore_text(dev, txt, MATRIX_IDENTITY) dev_fill_image(dev, nil, MATRIX_IDENTITY, paint) dev_fill_image_mask(dev, nil, MATRIX_IDENTITY, paint) dev_fill_shade(dev, nil, MATRIX_IDENTITY, paint) dev_begin_mask(dev, RECT_EMPTY, true, paint) dev_end_mask(dev, nil, nil) dev_begin_group(dev, RECT_EMPTY, false, false, .Normal, 1, nil) dev_end_group(dev) _ = dev_begin_tile(dev, RECT_EMPTY, RECT_EMPTY, 1, 1, MATRIX_IDENTITY) dev_end_tile(dev) dev_begin_layer(dev, "layer") dev_end_layer(dev) dev_close(dev) } // A device with no hooks at all. empty: Device call_everything(&empty, &p, &txt, &stroke, paint) // And no device at all, which is what an interpreter run with a nil sink // must survive. call_everything(nil, &p, &txt, &stroke, paint) // begin_tile must report "run the content once" when unimplemented, not a // negative or unbounded count. testing.expect_value(t, dev_begin_tile(&empty, RECT_EMPTY, RECT_EMPTY, 1, 1, MATRIX_IDENTITY), 0) testing.expect_value(t, dev_begin_tile(nil, RECT_EMPTY, RECT_EMPTY, 1, 1, MATRIX_IDENTITY), 0) } // The hints let a device tell the interpreter what it can skip -- decoding a // 4000x4000 JPEG to extract text off the page it sits on is pure waste. @(test) test_device_hints :: proc(t: ^testing.T) { dev: Device testing.expect(t, dev_wants_images(&dev), "a device with no hints wants everything") testing.expect(t, dev_wants_shades(&dev), "") dev.hints = {.Ignore_Image} testing.expect(t, !dev_wants_images(&dev), "") testing.expect(t, dev_wants_shades(&dev), "one hint must not imply another") dev.hints = {.Ignore_Image, .Ignore_Shade} testing.expect(t, !dev_wants_images(&dev), "") testing.expect(t, !dev_wants_shades(&dev), "") // A nil device wants nothing, so the interpreter skips the work entirely. testing.expect(t, !dev_wants_images(nil), "") testing.expect(t, !dev_wants_shades(nil), "") } @(test) test_text_make_and_destroy :: proc(t: ^testing.T) { txt := text_make() append(&txt.items, Text_Item{gid = 5, unicode = 'A', advance = 500}) testing.expect_value(t, len(txt.items), 1) text_destroy(&txt) testing.expect_value(t, len(txt.items), 0) text_destroy(&txt) // idempotent text_destroy(nil) }