hexapdf 0.17.1 → 0.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1024 -0
- data/LICENSE +29 -0
- data/README.md +129 -0
- data/Rakefile +109 -0
- data/agpl-3.0.txt +661 -0
- data/examples/001-hello_world.rb +16 -0
- data/examples/002-graphics.rb +275 -0
- data/examples/003-arcs.rb +50 -0
- data/examples/004-optimizing.rb +23 -0
- data/examples/005-merging.rb +27 -0
- data/examples/006-standard_pdf_fonts.rb +73 -0
- data/examples/007-truetype.rb +42 -0
- data/examples/008-show_char_bboxes.rb +55 -0
- data/examples/009-text_layouter_alignment.rb +47 -0
- data/examples/010-text_layouter_inline_boxes.rb +64 -0
- data/examples/011-text_layouter_line_wrapping.rb +57 -0
- data/examples/012-text_layouter_styling.rb +122 -0
- data/examples/013-text_layouter_shapes.rb +176 -0
- data/examples/014-text_in_polygon.rb +60 -0
- data/examples/015-boxes.rb +76 -0
- data/examples/016-frame_automatic_box_placement.rb +90 -0
- data/examples/017-frame_text_flow.rb +60 -0
- data/examples/018-composer.rb +44 -0
- data/examples/019-acro_form.rb +88 -0
- data/examples/emoji-smile.png +0 -0
- data/examples/emoji-wink.png +0 -0
- data/examples/machupicchu.jpg +0 -0
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -0
- data/lib/hexapdf/content/graphic_object/geom2d.rb +13 -0
- data/lib/hexapdf/version.rb +1 -1
- data/test/data/aes-test-vectors/CBCGFSbox-128-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCGFSbox-128-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCGFSbox-192-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCGFSbox-192-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCGFSbox-256-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCGFSbox-256-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-128-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-128-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-192-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-192-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-256-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-256-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-128-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-128-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-192-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-192-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-256-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-256-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-128-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-128-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-192-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-192-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-256-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-256-encrypt.data.gz +0 -0
- data/test/data/fonts/Ubuntu-Title.ttf +0 -0
- data/test/data/images/cmyk.jpg +0 -0
- data/test/data/images/fillbytes.jpg +0 -0
- data/test/data/images/gray.jpg +0 -0
- data/test/data/images/greyscale-1bit.png +0 -0
- data/test/data/images/greyscale-2bit.png +0 -0
- data/test/data/images/greyscale-4bit.png +0 -0
- data/test/data/images/greyscale-8bit.png +0 -0
- data/test/data/images/greyscale-alpha-8bit.png +0 -0
- data/test/data/images/greyscale-trns-8bit.png +0 -0
- data/test/data/images/greyscale-with-gamma1.0.png +0 -0
- data/test/data/images/greyscale-with-gamma1.5.png +0 -0
- data/test/data/images/indexed-1bit.png +0 -0
- data/test/data/images/indexed-2bit.png +0 -0
- data/test/data/images/indexed-4bit.png +0 -0
- data/test/data/images/indexed-8bit.png +0 -0
- data/test/data/images/indexed-alpha-4bit.png +0 -0
- data/test/data/images/indexed-alpha-8bit.png +0 -0
- data/test/data/images/rgb.jpg +0 -0
- data/test/data/images/truecolour-8bit.png +0 -0
- data/test/data/images/truecolour-alpha-8bit.png +0 -0
- data/test/data/images/truecolour-gama-chrm-8bit.png +0 -0
- data/test/data/images/truecolour-srgb-8bit.png +0 -0
- data/test/data/images/ycck.jpg +0 -0
- data/test/data/minimal.pdf +44 -0
- data/test/data/standard-security-handler/README +9 -0
- data/test/data/standard-security-handler/bothpwd-aes-128bit-V4.pdf +44 -0
- data/test/data/standard-security-handler/bothpwd-aes-256bit-V5.pdf +0 -0
- data/test/data/standard-security-handler/bothpwd-arc4-128bit-V2.pdf +43 -0
- data/test/data/standard-security-handler/bothpwd-arc4-128bit-V4.pdf +43 -0
- data/test/data/standard-security-handler/bothpwd-arc4-40bit-V1.pdf +0 -0
- data/test/data/standard-security-handler/nopwd-aes-128bit-V4.pdf +43 -0
- data/test/data/standard-security-handler/nopwd-aes-256bit-V5.pdf +0 -0
- data/test/data/standard-security-handler/nopwd-arc4-128bit-V2.pdf +43 -0
- data/test/data/standard-security-handler/nopwd-arc4-128bit-V4.pdf +43 -0
- data/test/data/standard-security-handler/nopwd-arc4-40bit-V1.pdf +43 -0
- data/test/data/standard-security-handler/ownerpwd-aes-128bit-V4.pdf +0 -0
- data/test/data/standard-security-handler/ownerpwd-aes-256bit-V5.pdf +43 -0
- data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V2.pdf +43 -0
- data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V4.pdf +43 -0
- data/test/data/standard-security-handler/ownerpwd-arc4-40bit-V1.pdf +43 -0
- data/test/data/standard-security-handler/userpwd-aes-128bit-V4.pdf +43 -0
- data/test/data/standard-security-handler/userpwd-aes-256bit-V5.pdf +43 -0
- data/test/data/standard-security-handler/userpwd-arc4-128bit-V2.pdf +0 -0
- data/test/data/standard-security-handler/userpwd-arc4-128bit-V4.pdf +0 -0
- data/test/data/standard-security-handler/userpwd-arc4-40bit-V1.pdf +43 -0
- data/test/hexapdf/common_tokenizer_tests.rb +236 -0
- data/test/hexapdf/content/common.rb +39 -0
- data/test/hexapdf/content/graphic_object/test_arc.rb +102 -0
- data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +90 -0
- data/test/hexapdf/content/graphic_object/test_geom2d.rb +79 -0
- data/test/hexapdf/content/graphic_object/test_solid_arc.rb +86 -0
- data/test/hexapdf/content/test_canvas.rb +1279 -0
- data/test/hexapdf/content/test_color_space.rb +176 -0
- data/test/hexapdf/content/test_graphics_state.rb +151 -0
- data/test/hexapdf/content/test_operator.rb +619 -0
- data/test/hexapdf/content/test_parser.rb +99 -0
- data/test/hexapdf/content/test_processor.rb +163 -0
- data/test/hexapdf/content/test_transformation_matrix.rb +64 -0
- data/test/hexapdf/document/test_files.rb +72 -0
- data/test/hexapdf/document/test_fonts.rb +60 -0
- data/test/hexapdf/document/test_images.rb +72 -0
- data/test/hexapdf/document/test_pages.rb +130 -0
- data/test/hexapdf/encryption/common.rb +87 -0
- data/test/hexapdf/encryption/test_aes.rb +129 -0
- data/test/hexapdf/encryption/test_arc4.rb +39 -0
- data/test/hexapdf/encryption/test_fast_aes.rb +17 -0
- data/test/hexapdf/encryption/test_fast_arc4.rb +12 -0
- data/test/hexapdf/encryption/test_identity.rb +21 -0
- data/test/hexapdf/encryption/test_ruby_aes.rb +23 -0
- data/test/hexapdf/encryption/test_ruby_arc4.rb +20 -0
- data/test/hexapdf/encryption/test_security_handler.rb +380 -0
- data/test/hexapdf/encryption/test_standard_security_handler.rb +322 -0
- data/test/hexapdf/filter/common.rb +53 -0
- data/test/hexapdf/filter/test_ascii85_decode.rb +59 -0
- data/test/hexapdf/filter/test_ascii_hex_decode.rb +38 -0
- data/test/hexapdf/filter/test_crypt.rb +21 -0
- data/test/hexapdf/filter/test_encryption.rb +24 -0
- data/test/hexapdf/filter/test_flate_decode.rb +44 -0
- data/test/hexapdf/filter/test_lzw_decode.rb +52 -0
- data/test/hexapdf/filter/test_predictor.rb +219 -0
- data/test/hexapdf/filter/test_run_length_decode.rb +32 -0
- data/test/hexapdf/font/cmap/test_parser.rb +102 -0
- data/test/hexapdf/font/cmap/test_writer.rb +66 -0
- data/test/hexapdf/font/encoding/test_base.rb +45 -0
- data/test/hexapdf/font/encoding/test_difference_encoding.rb +29 -0
- data/test/hexapdf/font/encoding/test_glyph_list.rb +59 -0
- data/test/hexapdf/font/encoding/test_zapf_dingbats_encoding.rb +16 -0
- data/test/hexapdf/font/test_cmap.rb +104 -0
- data/test/hexapdf/font/test_encoding.rb +27 -0
- data/test/hexapdf/font/test_invalid_glyph.rb +34 -0
- data/test/hexapdf/font/test_true_type_wrapper.rb +186 -0
- data/test/hexapdf/font/test_type1_wrapper.rb +107 -0
- data/test/hexapdf/font/true_type/common.rb +17 -0
- data/test/hexapdf/font/true_type/table/common.rb +27 -0
- data/test/hexapdf/font/true_type/table/test_cmap.rb +47 -0
- data/test/hexapdf/font/true_type/table/test_cmap_subtable.rb +141 -0
- data/test/hexapdf/font/true_type/table/test_directory.rb +30 -0
- data/test/hexapdf/font/true_type/table/test_glyf.rb +58 -0
- data/test/hexapdf/font/true_type/table/test_head.rb +56 -0
- data/test/hexapdf/font/true_type/table/test_hhea.rb +26 -0
- data/test/hexapdf/font/true_type/table/test_hmtx.rb +30 -0
- data/test/hexapdf/font/true_type/table/test_kern.rb +61 -0
- data/test/hexapdf/font/true_type/table/test_loca.rb +33 -0
- data/test/hexapdf/font/true_type/table/test_maxp.rb +50 -0
- data/test/hexapdf/font/true_type/table/test_name.rb +76 -0
- data/test/hexapdf/font/true_type/table/test_os2.rb +55 -0
- data/test/hexapdf/font/true_type/table/test_post.rb +78 -0
- data/test/hexapdf/font/true_type/test_builder.rb +42 -0
- data/test/hexapdf/font/true_type/test_font.rb +116 -0
- data/test/hexapdf/font/true_type/test_optimizer.rb +26 -0
- data/test/hexapdf/font/true_type/test_subsetter.rb +73 -0
- data/test/hexapdf/font/true_type/test_table.rb +48 -0
- data/test/hexapdf/font/type1/common.rb +6 -0
- data/test/hexapdf/font/type1/test_afm_parser.rb +65 -0
- data/test/hexapdf/font/type1/test_font.rb +104 -0
- data/test/hexapdf/font/type1/test_font_metrics.rb +22 -0
- data/test/hexapdf/font/type1/test_pfb_parser.rb +37 -0
- data/test/hexapdf/font_loader/test_from_configuration.rb +43 -0
- data/test/hexapdf/font_loader/test_from_file.rb +36 -0
- data/test/hexapdf/font_loader/test_standard14.rb +33 -0
- data/test/hexapdf/image_loader/test_jpeg.rb +93 -0
- data/test/hexapdf/image_loader/test_pdf.rb +47 -0
- data/test/hexapdf/image_loader/test_png.rb +259 -0
- data/test/hexapdf/layout/test_box.rb +154 -0
- data/test/hexapdf/layout/test_frame.rb +350 -0
- data/test/hexapdf/layout/test_image_box.rb +73 -0
- data/test/hexapdf/layout/test_inline_box.rb +71 -0
- data/test/hexapdf/layout/test_line.rb +206 -0
- data/test/hexapdf/layout/test_style.rb +790 -0
- data/test/hexapdf/layout/test_text_box.rb +140 -0
- data/test/hexapdf/layout/test_text_fragment.rb +375 -0
- data/test/hexapdf/layout/test_text_layouter.rb +758 -0
- data/test/hexapdf/layout/test_text_shaper.rb +62 -0
- data/test/hexapdf/layout/test_width_from_polygon.rb +109 -0
- data/test/hexapdf/task/test_dereference.rb +51 -0
- data/test/hexapdf/task/test_optimize.rb +162 -0
- data/test/hexapdf/test_composer.rb +258 -0
- data/test/hexapdf/test_configuration.rb +93 -0
- data/test/hexapdf/test_data_dir.rb +32 -0
- data/test/hexapdf/test_dictionary.rb +340 -0
- data/test/hexapdf/test_dictionary_fields.rb +269 -0
- data/test/hexapdf/test_document.rb +641 -0
- data/test/hexapdf/test_filter.rb +100 -0
- data/test/hexapdf/test_importer.rb +106 -0
- data/test/hexapdf/test_object.rb +258 -0
- data/test/hexapdf/test_parser.rb +645 -0
- data/test/hexapdf/test_pdf_array.rb +169 -0
- data/test/hexapdf/test_rectangle.rb +73 -0
- data/test/hexapdf/test_reference.rb +50 -0
- data/test/hexapdf/test_revision.rb +188 -0
- data/test/hexapdf/test_revisions.rb +196 -0
- data/test/hexapdf/test_serializer.rb +195 -0
- data/test/hexapdf/test_stream.rb +274 -0
- data/test/hexapdf/test_tokenizer.rb +80 -0
- data/test/hexapdf/test_type.rb +18 -0
- data/test/hexapdf/test_writer.rb +140 -0
- data/test/hexapdf/test_xref_section.rb +61 -0
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +795 -0
- data/test/hexapdf/type/acro_form/test_button_field.rb +308 -0
- data/test/hexapdf/type/acro_form/test_choice_field.rb +220 -0
- data/test/hexapdf/type/acro_form/test_field.rb +259 -0
- data/test/hexapdf/type/acro_form/test_form.rb +357 -0
- data/test/hexapdf/type/acro_form/test_signature_field.rb +38 -0
- data/test/hexapdf/type/acro_form/test_text_field.rb +201 -0
- data/test/hexapdf/type/acro_form/test_variable_text_field.rb +88 -0
- data/test/hexapdf/type/actions/test_launch.rb +24 -0
- data/test/hexapdf/type/actions/test_uri.rb +23 -0
- data/test/hexapdf/type/annotations/test_markup_annotation.rb +22 -0
- data/test/hexapdf/type/annotations/test_text.rb +34 -0
- data/test/hexapdf/type/annotations/test_widget.rb +225 -0
- data/test/hexapdf/type/test_annotation.rb +97 -0
- data/test/hexapdf/type/test_catalog.rb +48 -0
- data/test/hexapdf/type/test_cid_font.rb +61 -0
- data/test/hexapdf/type/test_file_specification.rb +141 -0
- data/test/hexapdf/type/test_font.rb +67 -0
- data/test/hexapdf/type/test_font_descriptor.rb +61 -0
- data/test/hexapdf/type/test_font_simple.rb +176 -0
- data/test/hexapdf/type/test_font_true_type.rb +31 -0
- data/test/hexapdf/type/test_font_type0.rb +120 -0
- data/test/hexapdf/type/test_font_type1.rb +142 -0
- data/test/hexapdf/type/test_font_type3.rb +26 -0
- data/test/hexapdf/type/test_form.rb +120 -0
- data/test/hexapdf/type/test_image.rb +261 -0
- data/test/hexapdf/type/test_info.rb +9 -0
- data/test/hexapdf/type/test_object_stream.rb +117 -0
- data/test/hexapdf/type/test_page.rb +598 -0
- data/test/hexapdf/type/test_page_tree_node.rb +315 -0
- data/test/hexapdf/type/test_resources.rb +209 -0
- data/test/hexapdf/type/test_trailer.rb +116 -0
- data/test/hexapdf/type/test_xref_stream.rb +143 -0
- data/test/hexapdf/utils/test_bit_field.rb +63 -0
- data/test/hexapdf/utils/test_bit_stream.rb +69 -0
- data/test/hexapdf/utils/test_graphics_helpers.rb +37 -0
- data/test/hexapdf/utils/test_lru_cache.rb +22 -0
- data/test/hexapdf/utils/test_object_hash.rb +120 -0
- data/test/hexapdf/utils/test_pdf_doc_encoding.rb +18 -0
- data/test/hexapdf/utils/test_sorted_tree_node.rb +239 -0
- data/test/test_helper.rb +58 -0
- metadata +263 -3
|
@@ -0,0 +1,641 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'tempfile'
|
|
4
|
+
require 'test_helper'
|
|
5
|
+
require 'hexapdf/document'
|
|
6
|
+
require 'stringio'
|
|
7
|
+
|
|
8
|
+
describe HexaPDF::Document do
|
|
9
|
+
before do
|
|
10
|
+
@io = StringIO.new(<<~EOF)
|
|
11
|
+
%PDF-1.7
|
|
12
|
+
1 0 obj
|
|
13
|
+
10
|
|
14
|
+
endobj
|
|
15
|
+
|
|
16
|
+
2 0 obj
|
|
17
|
+
20
|
|
18
|
+
endobj
|
|
19
|
+
|
|
20
|
+
3 0 obj
|
|
21
|
+
30
|
|
22
|
+
endobj
|
|
23
|
+
|
|
24
|
+
xref
|
|
25
|
+
0 4
|
|
26
|
+
0000000000 65535 f
|
|
27
|
+
0000000009 00000 n
|
|
28
|
+
0000000028 00000 n
|
|
29
|
+
0000000047 00000 n
|
|
30
|
+
trailer
|
|
31
|
+
<< /Size 4 >>
|
|
32
|
+
startxref
|
|
33
|
+
66
|
|
34
|
+
%%EOF
|
|
35
|
+
|
|
36
|
+
2 0 obj
|
|
37
|
+
200
|
|
38
|
+
endobj
|
|
39
|
+
|
|
40
|
+
xref
|
|
41
|
+
2 2
|
|
42
|
+
0000000197 00000 n
|
|
43
|
+
0000000000 00001 f
|
|
44
|
+
trailer
|
|
45
|
+
<< /Size 4 /Prev 66 >>
|
|
46
|
+
startxref
|
|
47
|
+
217
|
|
48
|
+
%%EOF
|
|
49
|
+
EOF
|
|
50
|
+
@io_doc = HexaPDF::Document.new(io: @io)
|
|
51
|
+
@doc = HexaPDF::Document.new
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe "::open" do
|
|
55
|
+
before do
|
|
56
|
+
@file = Tempfile.new('hexapdf-document')
|
|
57
|
+
@io_doc.write(@file)
|
|
58
|
+
@file.close
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
after do
|
|
62
|
+
@file.unlink
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "works without block" do
|
|
66
|
+
doc = HexaPDF::Document.open(@file.path)
|
|
67
|
+
assert_equal(200, doc.object(2).value)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "works with a block" do
|
|
71
|
+
HexaPDF::Document.open(@file.path) do |doc|
|
|
72
|
+
assert_equal(200, doc.object(2).value)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
describe "initialize" do
|
|
78
|
+
it "doesn't need any arguments" do
|
|
79
|
+
doc = HexaPDF::Document.new
|
|
80
|
+
assert_equal(:A4, doc.config['page.default_media_box'])
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "takes a configuration hash as option" do
|
|
84
|
+
doc = HexaPDF::Document.new(config: {'page.default_media_box' => :A5})
|
|
85
|
+
assert_equal(:A5, doc.config['page.default_media_box'])
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "takes an IO object as option" do
|
|
89
|
+
doc = HexaPDF::Document.new(io: @io)
|
|
90
|
+
assert_equal(10, doc.object(1).value)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
describe "object" do
|
|
95
|
+
it "accepts a Reference object as argument" do
|
|
96
|
+
assert_equal(10, @io_doc.object(HexaPDF::Reference.new(1, 0)).value)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "accepts an object number as arguments" do
|
|
100
|
+
assert_equal(10, @io_doc.object(1).value)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "returns added objects" do
|
|
104
|
+
obj = @io_doc.add(@io_doc.wrap({Type: :Test}, oid: 100))
|
|
105
|
+
assert_equal(obj, @io_doc.object(100))
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it "returns nil for unknown object references" do
|
|
109
|
+
assert_nil(@io_doc.object(100))
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it "returns only the newest version of an object" do
|
|
113
|
+
assert_equal(200, @io_doc.object(2).value)
|
|
114
|
+
assert_equal(200, @io_doc.object(HexaPDF::Reference.new(2, 0)).value)
|
|
115
|
+
assert_nil(@io_doc.object(3).value)
|
|
116
|
+
assert_nil(@io_doc.object(HexaPDF::Reference.new(3, 1)).value)
|
|
117
|
+
assert_equal(30, @io_doc.object(HexaPDF::Reference.new(3, 0)).value)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
describe "object?" do
|
|
122
|
+
it "works with a Reference object as argument" do
|
|
123
|
+
assert(@io_doc.object?(HexaPDF::Reference.new(1, 0)))
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it "works with an object number as arguments" do
|
|
127
|
+
assert(@io_doc.object?(1))
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
describe "deref" do
|
|
132
|
+
it "returns a dereferenced object when given a Reference object" do
|
|
133
|
+
assert_equal(@io_doc.object(1), @io_doc.deref(HexaPDF::Reference.new(1, 0)))
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "returns the given object when it is not a Reference object" do
|
|
137
|
+
assert_equal(5, @io_doc.deref(5))
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
describe "add" do
|
|
142
|
+
it "automatically assigns free object numbers" do
|
|
143
|
+
assert_equal(1, @doc.add(5).oid)
|
|
144
|
+
assert_equal(2, @doc.add(5).oid)
|
|
145
|
+
@doc.revisions.add
|
|
146
|
+
assert_equal(3, @doc.add(5).oid)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it "assigns the object's document" do
|
|
150
|
+
obj = @doc.add(5)
|
|
151
|
+
assert_equal(@doc, obj.document)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
it "allows adding a native ruby object" do
|
|
155
|
+
obj = @doc.add(5)
|
|
156
|
+
assert_equal(5, obj.value)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it "allows passing arguments to the wrap call" do
|
|
160
|
+
obj = @doc.add({}, type: HexaPDF::Dictionary)
|
|
161
|
+
assert_equal(HexaPDF::Dictionary, obj.class)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
it "allows adding a HexaPDF::Object" do
|
|
165
|
+
obj = @doc.add(HexaPDF::Object.new(5))
|
|
166
|
+
assert_equal(5, obj.value)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
it "returns the given object if it is already stored in the document" do
|
|
170
|
+
obj = @doc.add(5)
|
|
171
|
+
assert_same(obj, @doc.add(obj))
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it "allows specifying a revision to which the object should be added" do
|
|
175
|
+
@doc.revisions.add
|
|
176
|
+
@doc.revisions.add
|
|
177
|
+
|
|
178
|
+
@doc.add(@doc.wrap(5, oid: 1), revision: 0)
|
|
179
|
+
assert_equal(5, @doc.object(1).value)
|
|
180
|
+
|
|
181
|
+
@doc.add(@doc.wrap(10, oid: 1), revision: 2)
|
|
182
|
+
assert_equal(10, @doc.object(1).value)
|
|
183
|
+
|
|
184
|
+
@doc.add(@doc.wrap(7.5, oid: 1), revision: 1)
|
|
185
|
+
assert_equal(10, @doc.object(1).value)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
it "fails if the specified revision index is invalid" do
|
|
189
|
+
assert_raises(ArgumentError) { @doc.add(5, revision: 5) }
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
it "fails if the object to be added is associated with another document" do
|
|
193
|
+
doc = HexaPDF::Document.new
|
|
194
|
+
obj = doc.add(5)
|
|
195
|
+
assert_raises(HexaPDF::Error) { @doc.add(obj) }
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it "fails if the object number is already associated with another object" do
|
|
199
|
+
obj = @doc.add(5)
|
|
200
|
+
assert_raises(HexaPDF::Error) { @doc.add(@doc.wrap(5, oid: obj.oid, gen: 1)) }
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
describe "delete" do
|
|
205
|
+
it "works with a Reference object as argument" do
|
|
206
|
+
obj = @doc.add(5)
|
|
207
|
+
@doc.delete(obj, mark_as_free: false)
|
|
208
|
+
refute(@doc.object?(obj))
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
it "works with an object number as arguments" do
|
|
212
|
+
@doc.add(5)
|
|
213
|
+
@doc.delete(1, mark_as_free: false)
|
|
214
|
+
refute(@doc.object?(1))
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
describe "with an object in multiple revisions" do
|
|
218
|
+
before do
|
|
219
|
+
@ref = HexaPDF::Reference.new(2, 3)
|
|
220
|
+
obj = @doc.wrap(5, oid: @ref.oid, gen: @ref.gen)
|
|
221
|
+
@doc.revisions.add
|
|
222
|
+
@doc.add(obj, revision: 0)
|
|
223
|
+
@doc.add(obj, revision: 1)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
it "deletes an object for all revisions when revision = :all" do
|
|
227
|
+
@doc.delete(@ref, revision: :all, mark_as_free: false)
|
|
228
|
+
refute(@doc.object?(@ref))
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
it "deletes an object only in the current revision when revision = :current" do
|
|
232
|
+
@doc.delete(@ref, revision: :current, mark_as_free: false)
|
|
233
|
+
assert(@doc.object?(@ref))
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
it "marks the object as PDF null object when using mark_as_free=true" do
|
|
237
|
+
@doc.delete(@ref, revision: :current)
|
|
238
|
+
assert(@doc.object(@ref).null?)
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
it "fails if the revision argument is invalid" do
|
|
243
|
+
assert_raises(ArgumentError) { @doc.delete(1, revision: :invalid) }
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
describe "import" do
|
|
248
|
+
it "allows importing objects from another document" do
|
|
249
|
+
obj = @doc.import(@io_doc.object(2))
|
|
250
|
+
assert_equal(200, obj.value)
|
|
251
|
+
refute_equal(0, obj.oid)
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
it "fails if the given object is not a PDF object" do
|
|
255
|
+
assert_raises(ArgumentError) { @doc.import(5) }
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
it "fails if the given object is associated with no or the destination document" do
|
|
259
|
+
assert_raises(ArgumentError) { @doc.import(HexaPDF::Object.new(5)) }
|
|
260
|
+
obj = @doc.add(5)
|
|
261
|
+
assert_raises(ArgumentError) { @doc.import(obj) }
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
describe "wrap" do
|
|
266
|
+
before do
|
|
267
|
+
@myclass = Class.new(HexaPDF::Dictionary)
|
|
268
|
+
@myclass.define_type(:MyClass)
|
|
269
|
+
@myclass2 = Class.new(HexaPDF::Dictionary)
|
|
270
|
+
@myclass2.define_field(:Test, type: String, required: true)
|
|
271
|
+
HexaPDF::GlobalConfiguration['object.type_map'][:MyClass] = @myclass
|
|
272
|
+
HexaPDF::GlobalConfiguration['object.subtype_map'][nil][:Global] = @myclass2
|
|
273
|
+
HexaPDF::GlobalConfiguration['object.subtype_map'][:MyClass] = {TheSecond: @myclass2}
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
after do
|
|
277
|
+
HexaPDF::GlobalConfiguration['object.type_map'].delete(:MyClass)
|
|
278
|
+
HexaPDF::GlobalConfiguration['object.subtype_map'][nil].delete(:Global)
|
|
279
|
+
HexaPDF::GlobalConfiguration['object.subtype_map'][:MyClass].delete(:TheSecond)
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
it "uses a suitable default type if no special type is specified" do
|
|
283
|
+
assert_instance_of(HexaPDF::Object, @doc.wrap(5))
|
|
284
|
+
assert_instance_of(HexaPDF::Stream, @doc.wrap({a: 5}, stream: ''))
|
|
285
|
+
assert_instance_of(HexaPDF::Dictionary, @doc.wrap({a: 5}))
|
|
286
|
+
assert_instance_of(HexaPDF::PDFArray, @doc.wrap([1, 2]))
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
it "returns an object of type HexaPDF::Object" do
|
|
290
|
+
assert_kind_of(HexaPDF::Object, @doc.wrap(5))
|
|
291
|
+
assert_kind_of(HexaPDF::Object, @doc.wrap({}, stream: ''))
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
it "associates the returned object with the document" do
|
|
295
|
+
assert_equal(@doc, @doc.wrap(5).document)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
it "sets the given object (not === HexaPDF::Object) as value for the PDF object" do
|
|
299
|
+
assert_equal(5, @doc.wrap(5).value)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
it "uses the data of the given PDF object for re-wrapping" do
|
|
303
|
+
obj = @doc.wrap({a: :b}, oid: 10, gen: 20, stream: 'hallo')
|
|
304
|
+
new_obj = @doc.wrap(obj)
|
|
305
|
+
assert_equal({a: :b}, new_obj.value)
|
|
306
|
+
assert_equal('hallo', new_obj.raw_stream)
|
|
307
|
+
assert_equal(10, new_obj.oid)
|
|
308
|
+
assert_equal(20, new_obj.gen)
|
|
309
|
+
refute_same(obj, new_obj)
|
|
310
|
+
|
|
311
|
+
obj = @doc.wrap({a: :b}, oid: 10, gen: 20)
|
|
312
|
+
new_obj = @doc.wrap(obj)
|
|
313
|
+
refute_same(obj, new_obj)
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
it "allows overrding the data of the given PDF object" do
|
|
317
|
+
obj = @doc.wrap({a: :b}, oid: 10, gen: 20, stream: 'hallo')
|
|
318
|
+
new_obj = @doc.wrap(obj, oid: 15, gen: 25, stream: 'not')
|
|
319
|
+
assert_equal('not', new_obj.raw_stream)
|
|
320
|
+
assert_equal(15, new_obj.oid)
|
|
321
|
+
assert_equal(25, new_obj.gen)
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
it "sets the given oid/gen values on the returned object" do
|
|
325
|
+
obj = @doc.wrap(5, oid: 10, gen: 20)
|
|
326
|
+
assert_equal(10, obj.oid)
|
|
327
|
+
assert_equal(20, obj.gen)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
it "uses the type/subtype information in the hash that should be wrapped" do
|
|
331
|
+
assert_kind_of(@myclass, @doc.wrap({Type: :MyClass}))
|
|
332
|
+
refute_kind_of(@myclass2, @doc.wrap({Subtype: :TheSecond}))
|
|
333
|
+
refute_kind_of(@myclass2, @doc.wrap({Subtype: :Global}))
|
|
334
|
+
assert_kind_of(@myclass2, @doc.wrap({Subtype: :Global, Test: "true"}))
|
|
335
|
+
assert_kind_of(@myclass2, @doc.wrap({Type: :MyClass, S: :TheSecond}))
|
|
336
|
+
assert_kind_of(@myclass, @doc.wrap({Type: :MyClass, Subtype: :TheThird}))
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
it "respects the given type/subtype arguments" do
|
|
340
|
+
assert_kind_of(@myclass, @doc.wrap({Type: :Other}, type: :MyClass))
|
|
341
|
+
refute_kind_of(@myclass2, @doc.wrap({Subtype: :Other}, subtype: :Global))
|
|
342
|
+
assert_kind_of(@myclass2, @doc.wrap({Subtype: :Other, Test: "true"}, subtype: :Global))
|
|
343
|
+
assert_kind_of(@myclass2, @doc.wrap({Type: :Other, Subtype: :Other},
|
|
344
|
+
type: :MyClass, subtype: :TheSecond))
|
|
345
|
+
assert_kind_of(@myclass2, @doc.wrap({Subtype: :TheSecond}, type: @myclass))
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
it "directly uses a class given via the type argument" do
|
|
349
|
+
obj = @doc.wrap({a: :b}, type: @myclass, oid: 5)
|
|
350
|
+
assert_kind_of(@myclass, obj)
|
|
351
|
+
obj = @doc.wrap(obj, type: @myclass2)
|
|
352
|
+
assert_kind_of(@myclass2, obj)
|
|
353
|
+
assert_equal(:b, obj.value[:a])
|
|
354
|
+
assert_equal(5, obj.oid)
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
describe "unwrap" do
|
|
359
|
+
it "returns a simple native ruby type" do
|
|
360
|
+
assert_equal(5, @doc.unwrap(5))
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
it "recursively unwraps arrays" do
|
|
364
|
+
assert_equal([5, 10, [200], [200]],
|
|
365
|
+
@io_doc.unwrap([5, HexaPDF::Reference.new(1, 0), [HexaPDF::Reference.new(2, 0)],
|
|
366
|
+
[HexaPDF::Reference.new(2, 0)]]))
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
it "recursively unwraps hashes" do
|
|
370
|
+
assert_equal({a: 5, b: 10, c: [200], d: [200]},
|
|
371
|
+
@io_doc.unwrap({a: 5, b: HexaPDF::Reference.new(1, 0),
|
|
372
|
+
c: [HexaPDF::Reference.new(2, 0)],
|
|
373
|
+
d: [HexaPDF::Reference.new(2, 0)]}))
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
it "recursively unwraps PDF objects" do
|
|
377
|
+
assert_equal({a: 10}, @io_doc.unwrap(@io_doc.wrap({a: HexaPDF::Reference.new(1, 0)})))
|
|
378
|
+
value = {a: HexaPDF::Object.new({b: HexaPDF::Object.new(10)})}
|
|
379
|
+
assert_equal({a: {b: 10}}, @doc.unwrap(value))
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
it "fails to unwrap recursive structures" do
|
|
383
|
+
obj1 = @doc.add({})
|
|
384
|
+
obj2 = @doc.add({})
|
|
385
|
+
obj1.value[2] = obj2
|
|
386
|
+
obj2.value[1] = obj1
|
|
387
|
+
assert_raises(HexaPDF::Error) { @doc.unwrap({a: obj1}) }
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
describe "each" do
|
|
392
|
+
it "iterates over the current objects" do
|
|
393
|
+
assert_equal([10, 200, nil], @io_doc.each(only_current: true).sort.map(&:value))
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
it "iterates over all objects" do
|
|
397
|
+
assert_equal([10, 200, 20, 30, nil], @io_doc.each(only_current: false).sort.map(&:value))
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
it "iterates over all loaded objects" do
|
|
401
|
+
assert_equal(200, @io_doc.object(2).value)
|
|
402
|
+
assert_equal([200], @io_doc.each(only_loaded: true).sort.map(&:value))
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
it "yields the revision as second argument if the block accepts exactly two arguments" do
|
|
406
|
+
objs = [[10, 20, 30], [200, nil]]
|
|
407
|
+
data = @io_doc.revisions.map.with_index {|rev, i| objs[i].map {|o| [o, rev] } }.reverse.flatten
|
|
408
|
+
@io_doc.each(only_current: false) do |obj, rev|
|
|
409
|
+
assert(data.shift == obj.value)
|
|
410
|
+
assert_equal(data.shift, rev)
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
describe "encryption" do
|
|
416
|
+
it "checks for encryption based on the existence of the trailer's /Encrypt dictionary" do
|
|
417
|
+
refute(@doc.encrypted?)
|
|
418
|
+
@doc.trailer[:Encrypt] = {Filter: :Standard}
|
|
419
|
+
assert(@doc.encrypted?)
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
it "can set or delete a security handler via #encrypt" do
|
|
423
|
+
@doc.encrypt
|
|
424
|
+
refute_nil(@doc.security_handler)
|
|
425
|
+
assert(@doc.encrypted?)
|
|
426
|
+
|
|
427
|
+
@doc.encrypt(name: nil)
|
|
428
|
+
assert_nil(@doc.security_handler)
|
|
429
|
+
refute(@doc.encrypted?)
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
it "doesn't decrypt the document if document.auto_encrypt=false" do
|
|
433
|
+
test_file = File.join(TEST_DATA_DIR, 'standard-security-handler', 'nopwd-arc4-40bit-V1.pdf')
|
|
434
|
+
doc = HexaPDF::Document.new(io: StringIO.new(File.read(test_file)),
|
|
435
|
+
config: {'document.auto_decrypt' => false})
|
|
436
|
+
assert_kind_of(String, doc.trailer[:Info][:ModDate])
|
|
437
|
+
handler = HexaPDF::Encryption::SecurityHandler.set_up_decryption(doc)
|
|
438
|
+
assert_kind_of(Time, handler.decrypt(doc.trailer[:Info])[:ModDate])
|
|
439
|
+
end
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
describe "validate" do
|
|
443
|
+
before do
|
|
444
|
+
@doc.validate # to create a valid document
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
it "validates indirect objects" do
|
|
448
|
+
obj = @doc.add({Type: :Page, MediaBox: [1, 1, 1, 1], Parent: @doc.pages.root})
|
|
449
|
+
refute(@doc.validate(auto_correct: false))
|
|
450
|
+
|
|
451
|
+
called = false
|
|
452
|
+
assert(@doc.validate {|_, _, o| assert_same(obj, o); called = true })
|
|
453
|
+
assert(called)
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
it "validates the trailer object" do
|
|
457
|
+
@doc.trailer[:ID] = :Symbol
|
|
458
|
+
refute(@doc.validate {|_, _, obj| assert_same(@doc.trailer, obj) })
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
it "validates only loaded objects" do
|
|
462
|
+
io = StringIO.new
|
|
463
|
+
doc = HexaPDF::Document.new
|
|
464
|
+
doc.pages.add.delete(:Resources)
|
|
465
|
+
page = doc.pages.add
|
|
466
|
+
page[:Annots] = [doc.add({Type: :Annot, Subtype: :Link, Rect: [0, 0, 1, 1], H: :Z})]
|
|
467
|
+
doc.write(io, validate: false)
|
|
468
|
+
doc = HexaPDF::Document.new(io: io)
|
|
469
|
+
doc.pages[0] # force loading of the first page
|
|
470
|
+
|
|
471
|
+
refute(doc.validate(auto_correct: false, only_loaded: true)) # bc of Resources
|
|
472
|
+
assert(doc.validate(only_loaded: true))
|
|
473
|
+
refute(doc.validate(auto_correct: false)) # bc of annot key H
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
describe "write" do
|
|
478
|
+
it "writes the document to a file" do
|
|
479
|
+
begin
|
|
480
|
+
file = Tempfile.new('hexapdf-write')
|
|
481
|
+
file.close
|
|
482
|
+
@io_doc.write(file.path)
|
|
483
|
+
HexaPDF::Document.open(file.path) do |doc|
|
|
484
|
+
assert_equal(200, doc.object(2).value)
|
|
485
|
+
end
|
|
486
|
+
ensure
|
|
487
|
+
file.unlink
|
|
488
|
+
end
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
it "writes the document to an IO object" do
|
|
492
|
+
io = StringIO.new(''.b)
|
|
493
|
+
@doc.write(io)
|
|
494
|
+
refute(io.string.empty?)
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
it "writes the document incrementally" do
|
|
498
|
+
io = StringIO.new
|
|
499
|
+
@io_doc.write(io, incremental: true)
|
|
500
|
+
assert_equal(@io.string, io.string[0, @io.string.length])
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
it "fails if the document is not valid" do
|
|
504
|
+
@doc.trailer[:Size] = :Symbol
|
|
505
|
+
assert_raises(HexaPDF::Error) { @doc.write(StringIO.new(''.b)) }
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
it "update the ID and the Info's ModDate field" do
|
|
509
|
+
_, id1 = @doc.trailer.set_random_id
|
|
510
|
+
|
|
511
|
+
@doc.write(StringIO.new(''.b), update_fields: false)
|
|
512
|
+
assert_same(id1, @doc.trailer[:ID][1])
|
|
513
|
+
refute(@doc.trailer.info.key?(:ModDate))
|
|
514
|
+
|
|
515
|
+
@doc.write(StringIO.new(''.b))
|
|
516
|
+
refute_same(id1, (id2 = @doc.trailer[:ID][1]))
|
|
517
|
+
assert(@doc.trailer.info.key?(:ModDate))
|
|
518
|
+
|
|
519
|
+
@doc.trailer.info[:Author] = 'Me'
|
|
520
|
+
@doc.write(StringIO.new(''.b))
|
|
521
|
+
refute_same(id2, @doc.trailer[:ID][1])
|
|
522
|
+
assert(@doc.trailer.info.key?(:ModDate))
|
|
523
|
+
assert(@doc.trailer.info.key?(:Author))
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
it "it doesn't optimize the file by default" do
|
|
527
|
+
io = StringIO.new(''.b)
|
|
528
|
+
@io_doc.write(io)
|
|
529
|
+
doc = HexaPDF::Document.new(io: io)
|
|
530
|
+
assert_equal(0, doc.each.count {|o| o.type == :ObjStm })
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
it "allows optimizing the file by using object streams" do
|
|
534
|
+
io = StringIO.new(''.b)
|
|
535
|
+
@io_doc.write(io, optimize: true)
|
|
536
|
+
doc = HexaPDF::Document.new(io: io)
|
|
537
|
+
assert_equal(2, doc.each.count {|o| o.type == :ObjStm })
|
|
538
|
+
end
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
describe "version" do
|
|
542
|
+
it "uses the file header version of a loaded document" do
|
|
543
|
+
assert_equal('1.7', @io_doc.version)
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
it "uses the default version for a new document" do
|
|
547
|
+
assert_equal('1.2', @doc.version)
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
it "uses the catalog's /Version entry if it points to a later version" do
|
|
551
|
+
(@doc.trailer[:Root] ||= {})[:Version] = '1.4'
|
|
552
|
+
assert_equal('1.4', @doc.version)
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
it "allows setting the version" do
|
|
556
|
+
@doc.version = '1.4'
|
|
557
|
+
assert_equal('1.4', @doc.version)
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
it "fails setting a version with an invalid format" do
|
|
561
|
+
assert_raises(ArgumentError) { @doc.version = 'bla' }
|
|
562
|
+
end
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
describe "task" do
|
|
566
|
+
it "executes the given task with options" do
|
|
567
|
+
@doc.config['task.map'][:test] = lambda do |doc, arg1:|
|
|
568
|
+
assert_equal(doc, @doc)
|
|
569
|
+
assert_equal(:arg1, arg1)
|
|
570
|
+
end
|
|
571
|
+
@doc.task(:test, arg1: :arg1)
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
it "executes the given task with a block" do
|
|
575
|
+
@doc.config['task.map'][:test] = lambda do |doc, **, &block|
|
|
576
|
+
assert_equal(doc, @doc)
|
|
577
|
+
block.call('inside')
|
|
578
|
+
end
|
|
579
|
+
assert_equal(:done, @doc.task(:test) {|msg| assert_equal('inside', msg); :done })
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
it "fails if the given task is not available" do
|
|
583
|
+
assert_raises(HexaPDF::Error) { @doc.task(:unknown) }
|
|
584
|
+
end
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
describe "acro_form" do
|
|
588
|
+
it "returns the main AcroForm object" do
|
|
589
|
+
assert_nil(@doc.acro_form)
|
|
590
|
+
@doc.catalog[:AcroForm] = 5
|
|
591
|
+
assert_equal(5, @doc.acro_form)
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
it "create the AcroForm object if instructed" do
|
|
595
|
+
assert_equal(:XXAcroForm, @doc.acro_form(create: true).type)
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
describe "listener interface" do
|
|
600
|
+
it "allows registering and dispatching messages" do
|
|
601
|
+
args = []
|
|
602
|
+
callable = lambda {|*a| args << [:callable, a] }
|
|
603
|
+
@doc.register_listener(:something, callable)
|
|
604
|
+
@doc.register_listener(:something) {|*a| args << [:block, a] }
|
|
605
|
+
@doc.dispatch_message(:something, :arg)
|
|
606
|
+
assert_equal([[:callable, [:arg]], [:block, [:arg]]], args)
|
|
607
|
+
end
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
describe "caching interface" do
|
|
611
|
+
it "allows setting and retrieving values" do
|
|
612
|
+
assert_equal(:test, @doc.cache(:a, :b, :test) { :notused })
|
|
613
|
+
assert_equal(:test, @doc.cache(:a, :b) { :other })
|
|
614
|
+
assert_equal(:test, @doc.cache(:a, :b))
|
|
615
|
+
assert_nil(@doc.cache(:a, :c, nil))
|
|
616
|
+
assert_nil(@doc.cache(:a, :c) { :other })
|
|
617
|
+
assert_nil(@doc.cache(:a, :c))
|
|
618
|
+
assert(@doc.cached?(:a, :b))
|
|
619
|
+
assert(@doc.cached?(:a, :c))
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
it "allows updating a value" do
|
|
623
|
+
@doc.cache(:a, :b) { :test }
|
|
624
|
+
assert_equal(:new, @doc.cache(:a, :b, update: true) { :new })
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
it "allows clearing cached values" do
|
|
628
|
+
@doc.cache(:a, :b) { :c }
|
|
629
|
+
@doc.cache(:b, :c) { :d }
|
|
630
|
+
@doc.clear_cache(:a)
|
|
631
|
+
refute(@doc.cached?(:a, :b))
|
|
632
|
+
assert(@doc.cached?(:b, :c))
|
|
633
|
+
@doc.clear_cache
|
|
634
|
+
refute(@doc.cached?(:a, :c))
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
it "fails if no cached value exists and no block is given" do
|
|
638
|
+
assert_raises(LocalJumpError) { @doc.cache(:a, :b) }
|
|
639
|
+
end
|
|
640
|
+
end
|
|
641
|
+
end
|