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.
Files changed (255) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1024 -0
  3. data/LICENSE +29 -0
  4. data/README.md +129 -0
  5. data/Rakefile +109 -0
  6. data/agpl-3.0.txt +661 -0
  7. data/examples/001-hello_world.rb +16 -0
  8. data/examples/002-graphics.rb +275 -0
  9. data/examples/003-arcs.rb +50 -0
  10. data/examples/004-optimizing.rb +23 -0
  11. data/examples/005-merging.rb +27 -0
  12. data/examples/006-standard_pdf_fonts.rb +73 -0
  13. data/examples/007-truetype.rb +42 -0
  14. data/examples/008-show_char_bboxes.rb +55 -0
  15. data/examples/009-text_layouter_alignment.rb +47 -0
  16. data/examples/010-text_layouter_inline_boxes.rb +64 -0
  17. data/examples/011-text_layouter_line_wrapping.rb +57 -0
  18. data/examples/012-text_layouter_styling.rb +122 -0
  19. data/examples/013-text_layouter_shapes.rb +176 -0
  20. data/examples/014-text_in_polygon.rb +60 -0
  21. data/examples/015-boxes.rb +76 -0
  22. data/examples/016-frame_automatic_box_placement.rb +90 -0
  23. data/examples/017-frame_text_flow.rb +60 -0
  24. data/examples/018-composer.rb +44 -0
  25. data/examples/019-acro_form.rb +88 -0
  26. data/examples/emoji-smile.png +0 -0
  27. data/examples/emoji-wink.png +0 -0
  28. data/examples/machupicchu.jpg +0 -0
  29. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -0
  30. data/lib/hexapdf/content/graphic_object/geom2d.rb +13 -0
  31. data/lib/hexapdf/version.rb +1 -1
  32. data/test/data/aes-test-vectors/CBCGFSbox-128-decrypt.data.gz +0 -0
  33. data/test/data/aes-test-vectors/CBCGFSbox-128-encrypt.data.gz +0 -0
  34. data/test/data/aes-test-vectors/CBCGFSbox-192-decrypt.data.gz +0 -0
  35. data/test/data/aes-test-vectors/CBCGFSbox-192-encrypt.data.gz +0 -0
  36. data/test/data/aes-test-vectors/CBCGFSbox-256-decrypt.data.gz +0 -0
  37. data/test/data/aes-test-vectors/CBCGFSbox-256-encrypt.data.gz +0 -0
  38. data/test/data/aes-test-vectors/CBCKeySbox-128-decrypt.data.gz +0 -0
  39. data/test/data/aes-test-vectors/CBCKeySbox-128-encrypt.data.gz +0 -0
  40. data/test/data/aes-test-vectors/CBCKeySbox-192-decrypt.data.gz +0 -0
  41. data/test/data/aes-test-vectors/CBCKeySbox-192-encrypt.data.gz +0 -0
  42. data/test/data/aes-test-vectors/CBCKeySbox-256-decrypt.data.gz +0 -0
  43. data/test/data/aes-test-vectors/CBCKeySbox-256-encrypt.data.gz +0 -0
  44. data/test/data/aes-test-vectors/CBCVarKey-128-decrypt.data.gz +0 -0
  45. data/test/data/aes-test-vectors/CBCVarKey-128-encrypt.data.gz +0 -0
  46. data/test/data/aes-test-vectors/CBCVarKey-192-decrypt.data.gz +0 -0
  47. data/test/data/aes-test-vectors/CBCVarKey-192-encrypt.data.gz +0 -0
  48. data/test/data/aes-test-vectors/CBCVarKey-256-decrypt.data.gz +0 -0
  49. data/test/data/aes-test-vectors/CBCVarKey-256-encrypt.data.gz +0 -0
  50. data/test/data/aes-test-vectors/CBCVarTxt-128-decrypt.data.gz +0 -0
  51. data/test/data/aes-test-vectors/CBCVarTxt-128-encrypt.data.gz +0 -0
  52. data/test/data/aes-test-vectors/CBCVarTxt-192-decrypt.data.gz +0 -0
  53. data/test/data/aes-test-vectors/CBCVarTxt-192-encrypt.data.gz +0 -0
  54. data/test/data/aes-test-vectors/CBCVarTxt-256-decrypt.data.gz +0 -0
  55. data/test/data/aes-test-vectors/CBCVarTxt-256-encrypt.data.gz +0 -0
  56. data/test/data/fonts/Ubuntu-Title.ttf +0 -0
  57. data/test/data/images/cmyk.jpg +0 -0
  58. data/test/data/images/fillbytes.jpg +0 -0
  59. data/test/data/images/gray.jpg +0 -0
  60. data/test/data/images/greyscale-1bit.png +0 -0
  61. data/test/data/images/greyscale-2bit.png +0 -0
  62. data/test/data/images/greyscale-4bit.png +0 -0
  63. data/test/data/images/greyscale-8bit.png +0 -0
  64. data/test/data/images/greyscale-alpha-8bit.png +0 -0
  65. data/test/data/images/greyscale-trns-8bit.png +0 -0
  66. data/test/data/images/greyscale-with-gamma1.0.png +0 -0
  67. data/test/data/images/greyscale-with-gamma1.5.png +0 -0
  68. data/test/data/images/indexed-1bit.png +0 -0
  69. data/test/data/images/indexed-2bit.png +0 -0
  70. data/test/data/images/indexed-4bit.png +0 -0
  71. data/test/data/images/indexed-8bit.png +0 -0
  72. data/test/data/images/indexed-alpha-4bit.png +0 -0
  73. data/test/data/images/indexed-alpha-8bit.png +0 -0
  74. data/test/data/images/rgb.jpg +0 -0
  75. data/test/data/images/truecolour-8bit.png +0 -0
  76. data/test/data/images/truecolour-alpha-8bit.png +0 -0
  77. data/test/data/images/truecolour-gama-chrm-8bit.png +0 -0
  78. data/test/data/images/truecolour-srgb-8bit.png +0 -0
  79. data/test/data/images/ycck.jpg +0 -0
  80. data/test/data/minimal.pdf +44 -0
  81. data/test/data/standard-security-handler/README +9 -0
  82. data/test/data/standard-security-handler/bothpwd-aes-128bit-V4.pdf +44 -0
  83. data/test/data/standard-security-handler/bothpwd-aes-256bit-V5.pdf +0 -0
  84. data/test/data/standard-security-handler/bothpwd-arc4-128bit-V2.pdf +43 -0
  85. data/test/data/standard-security-handler/bothpwd-arc4-128bit-V4.pdf +43 -0
  86. data/test/data/standard-security-handler/bothpwd-arc4-40bit-V1.pdf +0 -0
  87. data/test/data/standard-security-handler/nopwd-aes-128bit-V4.pdf +43 -0
  88. data/test/data/standard-security-handler/nopwd-aes-256bit-V5.pdf +0 -0
  89. data/test/data/standard-security-handler/nopwd-arc4-128bit-V2.pdf +43 -0
  90. data/test/data/standard-security-handler/nopwd-arc4-128bit-V4.pdf +43 -0
  91. data/test/data/standard-security-handler/nopwd-arc4-40bit-V1.pdf +43 -0
  92. data/test/data/standard-security-handler/ownerpwd-aes-128bit-V4.pdf +0 -0
  93. data/test/data/standard-security-handler/ownerpwd-aes-256bit-V5.pdf +43 -0
  94. data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V2.pdf +43 -0
  95. data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V4.pdf +43 -0
  96. data/test/data/standard-security-handler/ownerpwd-arc4-40bit-V1.pdf +43 -0
  97. data/test/data/standard-security-handler/userpwd-aes-128bit-V4.pdf +43 -0
  98. data/test/data/standard-security-handler/userpwd-aes-256bit-V5.pdf +43 -0
  99. data/test/data/standard-security-handler/userpwd-arc4-128bit-V2.pdf +0 -0
  100. data/test/data/standard-security-handler/userpwd-arc4-128bit-V4.pdf +0 -0
  101. data/test/data/standard-security-handler/userpwd-arc4-40bit-V1.pdf +43 -0
  102. data/test/hexapdf/common_tokenizer_tests.rb +236 -0
  103. data/test/hexapdf/content/common.rb +39 -0
  104. data/test/hexapdf/content/graphic_object/test_arc.rb +102 -0
  105. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +90 -0
  106. data/test/hexapdf/content/graphic_object/test_geom2d.rb +79 -0
  107. data/test/hexapdf/content/graphic_object/test_solid_arc.rb +86 -0
  108. data/test/hexapdf/content/test_canvas.rb +1279 -0
  109. data/test/hexapdf/content/test_color_space.rb +176 -0
  110. data/test/hexapdf/content/test_graphics_state.rb +151 -0
  111. data/test/hexapdf/content/test_operator.rb +619 -0
  112. data/test/hexapdf/content/test_parser.rb +99 -0
  113. data/test/hexapdf/content/test_processor.rb +163 -0
  114. data/test/hexapdf/content/test_transformation_matrix.rb +64 -0
  115. data/test/hexapdf/document/test_files.rb +72 -0
  116. data/test/hexapdf/document/test_fonts.rb +60 -0
  117. data/test/hexapdf/document/test_images.rb +72 -0
  118. data/test/hexapdf/document/test_pages.rb +130 -0
  119. data/test/hexapdf/encryption/common.rb +87 -0
  120. data/test/hexapdf/encryption/test_aes.rb +129 -0
  121. data/test/hexapdf/encryption/test_arc4.rb +39 -0
  122. data/test/hexapdf/encryption/test_fast_aes.rb +17 -0
  123. data/test/hexapdf/encryption/test_fast_arc4.rb +12 -0
  124. data/test/hexapdf/encryption/test_identity.rb +21 -0
  125. data/test/hexapdf/encryption/test_ruby_aes.rb +23 -0
  126. data/test/hexapdf/encryption/test_ruby_arc4.rb +20 -0
  127. data/test/hexapdf/encryption/test_security_handler.rb +380 -0
  128. data/test/hexapdf/encryption/test_standard_security_handler.rb +322 -0
  129. data/test/hexapdf/filter/common.rb +53 -0
  130. data/test/hexapdf/filter/test_ascii85_decode.rb +59 -0
  131. data/test/hexapdf/filter/test_ascii_hex_decode.rb +38 -0
  132. data/test/hexapdf/filter/test_crypt.rb +21 -0
  133. data/test/hexapdf/filter/test_encryption.rb +24 -0
  134. data/test/hexapdf/filter/test_flate_decode.rb +44 -0
  135. data/test/hexapdf/filter/test_lzw_decode.rb +52 -0
  136. data/test/hexapdf/filter/test_predictor.rb +219 -0
  137. data/test/hexapdf/filter/test_run_length_decode.rb +32 -0
  138. data/test/hexapdf/font/cmap/test_parser.rb +102 -0
  139. data/test/hexapdf/font/cmap/test_writer.rb +66 -0
  140. data/test/hexapdf/font/encoding/test_base.rb +45 -0
  141. data/test/hexapdf/font/encoding/test_difference_encoding.rb +29 -0
  142. data/test/hexapdf/font/encoding/test_glyph_list.rb +59 -0
  143. data/test/hexapdf/font/encoding/test_zapf_dingbats_encoding.rb +16 -0
  144. data/test/hexapdf/font/test_cmap.rb +104 -0
  145. data/test/hexapdf/font/test_encoding.rb +27 -0
  146. data/test/hexapdf/font/test_invalid_glyph.rb +34 -0
  147. data/test/hexapdf/font/test_true_type_wrapper.rb +186 -0
  148. data/test/hexapdf/font/test_type1_wrapper.rb +107 -0
  149. data/test/hexapdf/font/true_type/common.rb +17 -0
  150. data/test/hexapdf/font/true_type/table/common.rb +27 -0
  151. data/test/hexapdf/font/true_type/table/test_cmap.rb +47 -0
  152. data/test/hexapdf/font/true_type/table/test_cmap_subtable.rb +141 -0
  153. data/test/hexapdf/font/true_type/table/test_directory.rb +30 -0
  154. data/test/hexapdf/font/true_type/table/test_glyf.rb +58 -0
  155. data/test/hexapdf/font/true_type/table/test_head.rb +56 -0
  156. data/test/hexapdf/font/true_type/table/test_hhea.rb +26 -0
  157. data/test/hexapdf/font/true_type/table/test_hmtx.rb +30 -0
  158. data/test/hexapdf/font/true_type/table/test_kern.rb +61 -0
  159. data/test/hexapdf/font/true_type/table/test_loca.rb +33 -0
  160. data/test/hexapdf/font/true_type/table/test_maxp.rb +50 -0
  161. data/test/hexapdf/font/true_type/table/test_name.rb +76 -0
  162. data/test/hexapdf/font/true_type/table/test_os2.rb +55 -0
  163. data/test/hexapdf/font/true_type/table/test_post.rb +78 -0
  164. data/test/hexapdf/font/true_type/test_builder.rb +42 -0
  165. data/test/hexapdf/font/true_type/test_font.rb +116 -0
  166. data/test/hexapdf/font/true_type/test_optimizer.rb +26 -0
  167. data/test/hexapdf/font/true_type/test_subsetter.rb +73 -0
  168. data/test/hexapdf/font/true_type/test_table.rb +48 -0
  169. data/test/hexapdf/font/type1/common.rb +6 -0
  170. data/test/hexapdf/font/type1/test_afm_parser.rb +65 -0
  171. data/test/hexapdf/font/type1/test_font.rb +104 -0
  172. data/test/hexapdf/font/type1/test_font_metrics.rb +22 -0
  173. data/test/hexapdf/font/type1/test_pfb_parser.rb +37 -0
  174. data/test/hexapdf/font_loader/test_from_configuration.rb +43 -0
  175. data/test/hexapdf/font_loader/test_from_file.rb +36 -0
  176. data/test/hexapdf/font_loader/test_standard14.rb +33 -0
  177. data/test/hexapdf/image_loader/test_jpeg.rb +93 -0
  178. data/test/hexapdf/image_loader/test_pdf.rb +47 -0
  179. data/test/hexapdf/image_loader/test_png.rb +259 -0
  180. data/test/hexapdf/layout/test_box.rb +154 -0
  181. data/test/hexapdf/layout/test_frame.rb +350 -0
  182. data/test/hexapdf/layout/test_image_box.rb +73 -0
  183. data/test/hexapdf/layout/test_inline_box.rb +71 -0
  184. data/test/hexapdf/layout/test_line.rb +206 -0
  185. data/test/hexapdf/layout/test_style.rb +790 -0
  186. data/test/hexapdf/layout/test_text_box.rb +140 -0
  187. data/test/hexapdf/layout/test_text_fragment.rb +375 -0
  188. data/test/hexapdf/layout/test_text_layouter.rb +758 -0
  189. data/test/hexapdf/layout/test_text_shaper.rb +62 -0
  190. data/test/hexapdf/layout/test_width_from_polygon.rb +109 -0
  191. data/test/hexapdf/task/test_dereference.rb +51 -0
  192. data/test/hexapdf/task/test_optimize.rb +162 -0
  193. data/test/hexapdf/test_composer.rb +258 -0
  194. data/test/hexapdf/test_configuration.rb +93 -0
  195. data/test/hexapdf/test_data_dir.rb +32 -0
  196. data/test/hexapdf/test_dictionary.rb +340 -0
  197. data/test/hexapdf/test_dictionary_fields.rb +269 -0
  198. data/test/hexapdf/test_document.rb +641 -0
  199. data/test/hexapdf/test_filter.rb +100 -0
  200. data/test/hexapdf/test_importer.rb +106 -0
  201. data/test/hexapdf/test_object.rb +258 -0
  202. data/test/hexapdf/test_parser.rb +645 -0
  203. data/test/hexapdf/test_pdf_array.rb +169 -0
  204. data/test/hexapdf/test_rectangle.rb +73 -0
  205. data/test/hexapdf/test_reference.rb +50 -0
  206. data/test/hexapdf/test_revision.rb +188 -0
  207. data/test/hexapdf/test_revisions.rb +196 -0
  208. data/test/hexapdf/test_serializer.rb +195 -0
  209. data/test/hexapdf/test_stream.rb +274 -0
  210. data/test/hexapdf/test_tokenizer.rb +80 -0
  211. data/test/hexapdf/test_type.rb +18 -0
  212. data/test/hexapdf/test_writer.rb +140 -0
  213. data/test/hexapdf/test_xref_section.rb +61 -0
  214. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +795 -0
  215. data/test/hexapdf/type/acro_form/test_button_field.rb +308 -0
  216. data/test/hexapdf/type/acro_form/test_choice_field.rb +220 -0
  217. data/test/hexapdf/type/acro_form/test_field.rb +259 -0
  218. data/test/hexapdf/type/acro_form/test_form.rb +357 -0
  219. data/test/hexapdf/type/acro_form/test_signature_field.rb +38 -0
  220. data/test/hexapdf/type/acro_form/test_text_field.rb +201 -0
  221. data/test/hexapdf/type/acro_form/test_variable_text_field.rb +88 -0
  222. data/test/hexapdf/type/actions/test_launch.rb +24 -0
  223. data/test/hexapdf/type/actions/test_uri.rb +23 -0
  224. data/test/hexapdf/type/annotations/test_markup_annotation.rb +22 -0
  225. data/test/hexapdf/type/annotations/test_text.rb +34 -0
  226. data/test/hexapdf/type/annotations/test_widget.rb +225 -0
  227. data/test/hexapdf/type/test_annotation.rb +97 -0
  228. data/test/hexapdf/type/test_catalog.rb +48 -0
  229. data/test/hexapdf/type/test_cid_font.rb +61 -0
  230. data/test/hexapdf/type/test_file_specification.rb +141 -0
  231. data/test/hexapdf/type/test_font.rb +67 -0
  232. data/test/hexapdf/type/test_font_descriptor.rb +61 -0
  233. data/test/hexapdf/type/test_font_simple.rb +176 -0
  234. data/test/hexapdf/type/test_font_true_type.rb +31 -0
  235. data/test/hexapdf/type/test_font_type0.rb +120 -0
  236. data/test/hexapdf/type/test_font_type1.rb +142 -0
  237. data/test/hexapdf/type/test_font_type3.rb +26 -0
  238. data/test/hexapdf/type/test_form.rb +120 -0
  239. data/test/hexapdf/type/test_image.rb +261 -0
  240. data/test/hexapdf/type/test_info.rb +9 -0
  241. data/test/hexapdf/type/test_object_stream.rb +117 -0
  242. data/test/hexapdf/type/test_page.rb +598 -0
  243. data/test/hexapdf/type/test_page_tree_node.rb +315 -0
  244. data/test/hexapdf/type/test_resources.rb +209 -0
  245. data/test/hexapdf/type/test_trailer.rb +116 -0
  246. data/test/hexapdf/type/test_xref_stream.rb +143 -0
  247. data/test/hexapdf/utils/test_bit_field.rb +63 -0
  248. data/test/hexapdf/utils/test_bit_stream.rb +69 -0
  249. data/test/hexapdf/utils/test_graphics_helpers.rb +37 -0
  250. data/test/hexapdf/utils/test_lru_cache.rb +22 -0
  251. data/test/hexapdf/utils/test_object_hash.rb +120 -0
  252. data/test/hexapdf/utils/test_pdf_doc_encoding.rb +18 -0
  253. data/test/hexapdf/utils/test_sorted_tree_node.rb +239 -0
  254. data/test/test_helper.rb +58 -0
  255. metadata +263 -3
@@ -0,0 +1,93 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/configuration'
5
+
6
+ describe HexaPDF::Configuration do
7
+ before do
8
+ @config = HexaPDF::Configuration.new
9
+ @config['test'] = :test
10
+ end
11
+
12
+ it "can create a config based on the default one with certain values overwritten" do
13
+ config = HexaPDF::Configuration.with_defaults('io.chunk_size' => 10)
14
+ assert_equal(10, config['io.chunk_size'])
15
+ assert_equal(:A4, config['page.default_media_box'])
16
+ end
17
+
18
+ it "can check the availabilty of an option" do
19
+ assert(@config.option?('test'))
20
+ end
21
+
22
+ it "can return the value for an option" do
23
+ assert_equal(:test, @config['test'])
24
+ end
25
+
26
+ it "can set the value for an option" do
27
+ @config['test'] = :other
28
+ assert_equal(:other, @config['test'])
29
+ end
30
+
31
+ it "can create a new config object by merging another one or a hash" do
32
+ @config['hash'] = {'test' => :test, 'other' => :other}
33
+ @config['array'] = [5, 6]
34
+ config = @config.merge('test' => :other)
35
+ assert_equal(:other, config['test'])
36
+
37
+ config['hash']['test'] = :other
38
+ config1 = @config.merge(config)
39
+ assert_equal(:other, config1['hash']['test'])
40
+ assert_equal(:other, config1['hash']['other'])
41
+
42
+ config2 = @config.merge(config)
43
+ config2['array'].unshift(4)
44
+ assert_equal([4, 5, 6], config2['array'])
45
+ assert_equal([5, 6], config['array'])
46
+ end
47
+
48
+ describe "constantize" do
49
+ it "returns a constant for an option with a string value" do
50
+ @config['test'] = 'HexaPDF'
51
+ assert_equal(HexaPDF, @config.constantize('test'))
52
+ end
53
+
54
+ it "returns a constant for an option with a constant as value" do
55
+ @config['test'] = HexaPDF
56
+ assert_equal(HexaPDF, @config.constantize('test'))
57
+ end
58
+
59
+ it "returns a constant for a nested option" do
60
+ @config['test'] = {'test' => ['HexaPDF'], 'const' => {'const' => HexaPDF}}
61
+ assert_equal(HexaPDF, @config.constantize('test', 'test', 0))
62
+ assert_equal(HexaPDF, @config.constantize('test', 'const', 'const'))
63
+
64
+ @config['test'] = ['HexaPDF', HexaPDF]
65
+ assert_equal(HexaPDF, @config.constantize('test', 0))
66
+ assert_equal(HexaPDF, @config.constantize('test', 1))
67
+ end
68
+
69
+ def assert_constantize_error(&block) # :nodoc:
70
+ exp = assert_raises(HexaPDF::Error, &block)
71
+ assert_match(/Error getting constant for configuration option/, exp.message)
72
+ end
73
+
74
+ it "raises an error for an unknown option" do
75
+ assert_constantize_error { @config.constantize('unknown') }
76
+ end
77
+
78
+ it "raises an error for an unknown constant" do
79
+ @config['test'] = 'SomeUnknownConstant'
80
+ assert_constantize_error { @config.constantize('test') }
81
+ end
82
+
83
+ it "raises an error for an unknown constant using a nested option" do
84
+ @config['test'] = {}
85
+ assert_constantize_error { @config.constantize('test', 'test') }
86
+ assert_constantize_error { @config.constantize('test', nil) }
87
+ end
88
+
89
+ it "returns the result of the given block when no constant is found" do
90
+ assert_equal(:test, @config.constantize('unk') {|name| assert_equal('unk', name); :test })
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/data_dir'
5
+
6
+ describe 'HexaPDF.data_dir' do
7
+ before do
8
+ @local = File.expand_path(File.join(__dir__, '..', '..', 'data', 'hexapdf'))
9
+ @global = File.expand_path(File.join(RbConfig::CONFIG["datadir"], "hexapdf"))
10
+ HexaPDF.remove_instance_variable(:@data_dir) if HexaPDF.instance_variable_defined?(:@data_dir)
11
+ end
12
+
13
+ after do
14
+ HexaPDF.remove_instance_variable(:@data_dir) if HexaPDF.instance_variable_defined?(:@data_dir)
15
+ end
16
+
17
+ it "returns the 'local' data directory by default, e.g. in case of gem installations" do
18
+ assert_equal(@local, HexaPDF.data_dir)
19
+ end
20
+
21
+ it "returns the global data directory if the local one isn't found" do
22
+ File.stub(:directory?, lambda {|path| path != @local }) do
23
+ assert_equal(@global, HexaPDF.data_dir)
24
+ end
25
+ end
26
+
27
+ it "fails if no data directory is found" do
28
+ File.stub(:directory?, lambda {|_path| false }) do
29
+ assert_raises { HexaPDF.data_dir }
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,340 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/dictionary'
5
+ require 'hexapdf/reference'
6
+
7
+ describe HexaPDF::Dictionary do
8
+ def deref(obj)
9
+ if obj.kind_of?(HexaPDF::Reference)
10
+ HexaPDF::Object.new('deref', oid: obj.oid, gen: obj.gen)
11
+ else
12
+ obj
13
+ end
14
+ end
15
+
16
+ def add(obj)
17
+ klass = HexaPDF::Object
18
+ klass = HexaPDF::Dictionary if obj.kind_of?(HexaPDF::Dictionary) || obj.kind_of?(Hash)
19
+ klass.new(obj, oid: 1)
20
+ end
21
+
22
+ def delete(_obj)
23
+ end
24
+
25
+ def wrap(obj, type:)
26
+ type.new(obj, document: self)
27
+ end
28
+
29
+ attr_accessor :version
30
+
31
+ before do
32
+ @version = '1.2'
33
+ @test_class = Class.new(HexaPDF::Dictionary)
34
+ @test_class.define_field(:Boolean, type: [TrueClass, FalseClass], default: false, version: '1.3')
35
+ @test_class.define_field(:Array, type: Array, required: true, default: [])
36
+ @test_class.define_field(:TestClass, type: @test_class, indirect: true)
37
+
38
+ @dict = @test_class.new({Array: [3, 4], Other: 5, Object: HexaPDF::Object.new(:obj)},
39
+ document: self)
40
+ end
41
+
42
+ describe "class methods" do
43
+ it "allows defining fields and retrieving their info" do
44
+ field = @test_class.field(:Boolean)
45
+ refute_nil(field)
46
+ assert_equal('1.3', field.version)
47
+ assert_equal(false, field.default)
48
+ refute(field.required?)
49
+
50
+ field = @test_class.field(:Array)
51
+ assert(field.required?)
52
+ assert_equal([], field.default)
53
+
54
+ assert(@test_class.field(:TestClass).indirect)
55
+ end
56
+
57
+ it "can retrieve fields from parent classes" do
58
+ @inherited_class = Class.new(@test_class)
59
+
60
+ assert(@inherited_class.field(:Boolean))
61
+ refute(@inherited_class.field(:Unknown))
62
+ end
63
+
64
+ it "can iterate over all fields" do
65
+ @inherited_class = Class.new(@test_class)
66
+ @inherited_class.define_field(:Inherited, type: [Array, Symbol])
67
+ assert_equal([:Boolean, :Array, :TestClass, :Inherited], @inherited_class.each_field.map {|k, _| k })
68
+ end
69
+
70
+ it "allows field access without subclassing" do
71
+ refute(HexaPDF::Dictionary.field(:Test))
72
+ assert_equal([], HexaPDF::Dictionary.each_field.to_a)
73
+ end
74
+
75
+ it "allows defining a static type" do
76
+ @test_class.define_type(:MyClass)
77
+ assert_equal(:MyClass, @test_class.type)
78
+ assert_equal(:MyClass, @test_class.new({}).type)
79
+ end
80
+
81
+ it "::type returns nil if no static type has been defined" do
82
+ assert_nil(@test_class.type)
83
+ end
84
+ end
85
+
86
+ describe "after_data_change" do
87
+ it "fails if the value is not a hash" do
88
+ assert_raises(ArgumentError) { HexaPDF::Dictionary.new(:Name) }
89
+ end
90
+
91
+ it "sets the default value for a required field that has one" do
92
+ @test_class.define_field(:Type, type: Symbol, required: true, default: :MyType)
93
+ obj = @test_class.new(nil)
94
+ assert_equal(:MyType, obj.value[:Type])
95
+ end
96
+ end
97
+
98
+ describe "[]" do
99
+ it "allows retrieving set field values" do
100
+ assert_equal([3, 4], @dict[:Array])
101
+ assert_equal(5, @dict[:Other])
102
+ end
103
+
104
+ it "uses a default value if no value is set" do
105
+ assert_equal(false, @dict[:Boolean])
106
+ @dict.value[:Boolean] = true
107
+ assert_equal(true, @dict[:Boolean])
108
+ end
109
+
110
+ it "resolves references and stores the resolved object in place of the reference" do
111
+ @dict[:value] = HexaPDF::Reference.new(1, 0)
112
+ assert_equal('deref', @dict[:value])
113
+ assert_kind_of(HexaPDF::Object, @dict.value[:value])
114
+ end
115
+
116
+ it "wraps hash values in specific subclasses" do
117
+ @dict.value[:TestClass] = {Array: [1, 2]}
118
+ assert_kind_of(@test_class, @dict[:TestClass])
119
+ assert_equal([1, 2], @dict[:TestClass][:Array])
120
+
121
+ @dict.value[:TestClass] = HexaPDF::Object.new([1, 2])
122
+ refute_kind_of(@test_class, @dict[:TestClass])
123
+ assert_equal([1, 2], @dict[:TestClass])
124
+ end
125
+
126
+ it "fetches the value out of a HexaPDF::Object" do
127
+ assert_equal(:obj, @dict[:Object])
128
+ end
129
+
130
+ it "can convert data even if it is inside a HexaPDF::Object" do
131
+ @test_class.define_field(:Binary, type: HexaPDF::DictionaryFields::PDFByteString)
132
+ @dict[:Binary] = HexaPDF::Object.new('test')
133
+ result = @dict[:Binary]
134
+ assert_equal('test', result)
135
+ assert_equal(Encoding::BINARY, result.encoding)
136
+ assert_kind_of(HexaPDF::Object, @dict.value[:Binary])
137
+ assert_same(result, @dict.value[:Binary].value)
138
+
139
+ @dict[:Test] = HexaPDF::Dictionary.new({})
140
+ @dict[:Test].data.value = nil
141
+ assert_nil(@dict[:Test])
142
+ end
143
+ end
144
+
145
+ describe "[]=" do
146
+ it "directly stores the value if the stored value is no HexaPDF::Object" do
147
+ @dict[:Array] = [4, 5]
148
+ assert_equal([4, 5], @dict.value[:Array])
149
+
150
+ @dict[:NewValue] = 7
151
+ assert_equal(7, @dict.value[:NewValue])
152
+ end
153
+
154
+ it "stores the value in an existing HexaPDF::Object but only if it is not such an object" do
155
+ @dict[:Object] = [4, 5]
156
+ assert_equal([4, 5], @dict.value[:Object].value)
157
+
158
+ @dict[:Object] = temp = HexaPDF::Object.new(:other)
159
+ assert_equal(temp, @dict.value[:Object])
160
+ end
161
+
162
+ it "doesn't store the value inside for subclasses of HexaPDF::Object" do
163
+ (@dict[:TestClass] ||= {})[:Array] = [4, 5]
164
+ assert_kind_of(@test_class, @dict[:TestClass])
165
+ @dict[:TestClass] = [4, 5]
166
+ assert_equal([4, 5], @dict[:TestClass])
167
+ end
168
+
169
+ it "doesn't store the value inside for HexaPDF::Reference objects" do
170
+ @dict[:Object] = HexaPDF::Object.new(:test)
171
+ assert_kind_of(HexaPDF::Object, @dict.value[:Object])
172
+ @dict[:Object] = HexaPDF::Reference.new(5, 0)
173
+ assert_kind_of(HexaPDF::Reference, @dict.value[:Object])
174
+ end
175
+
176
+ it "raises an error if the key is not a symbol object" do
177
+ assert_raises(ArgumentError) { @dict[5] = 6 }
178
+ end
179
+ end
180
+
181
+ describe "key?" do
182
+ it "returns false for unset keys" do
183
+ refute(@dict.key?(:UnsetKey))
184
+ end
185
+
186
+ it "returns false for keys with a nil value" do
187
+ @dict[:NilKey] = nil
188
+ refute(@dict.key?(:NilKey))
189
+ end
190
+
191
+ it "returns true for keys with a non-nil value" do
192
+ assert(@dict.key?(:Other))
193
+ end
194
+ end
195
+
196
+ describe "validate_fields" do
197
+ before do
198
+ @test_class.define_field(:Inherited, type: [Array, Symbol], required: true, indirect: false)
199
+ @test_class.define_field(:AllowedValues, type: Integer, allowed_values: [1, 5])
200
+ @obj = @test_class.new({Array: [], Inherited: :symbol}, document: self)
201
+ end
202
+
203
+ it "checks for the required fields w/wo auto_correct" do
204
+ assert(@obj.validate(auto_correct: false))
205
+ assert_equal({Array: [], Inherited: :symbol}, @obj.value)
206
+
207
+ @obj.value.delete(:Array)
208
+ refute(@obj.validate(auto_correct: false))
209
+ assert(@obj.validate(auto_correct: true))
210
+ assert_equal({Array: [], Inherited: :symbol}, @obj.value)
211
+
212
+ @obj.value.delete(:Inherited)
213
+ refute(@obj.validate(auto_correct: true))
214
+ end
215
+
216
+ it "updates the PDF version of the document if needed" do
217
+ @obj.validate
218
+ assert_equal('1.2', @version)
219
+
220
+ @obj[:Boolean] = true
221
+ refute(@obj.validate(auto_correct: false))
222
+ assert_equal('1.2', @version)
223
+ assert(@obj.validate(auto_correct: true))
224
+ assert_equal('1.3', @version)
225
+ end
226
+
227
+ it "checks for the correct type of a set field" do
228
+ @obj.value[:Inherited] = 'string'
229
+ refute(@obj.validate(auto_correct: false))
230
+
231
+ @obj.value[:Inherited] = HexaPDF::Object.new(:symbol)
232
+ assert(@obj.validate(auto_correct: false))
233
+
234
+ @obj.value[:Inherited] = Class.new(Array).new([5])
235
+ assert(@obj.validate(auto_correct: false))
236
+
237
+ @test_class.define_field(:StringField, type: String)
238
+ @test_class.define_field(:NameField, type: Symbol)
239
+ @obj.value[:StringField] = :symbol
240
+ refute(@obj.validate(auto_correct: false))
241
+ assert(@obj.validate(auto_correct: true))
242
+ @obj.value[:NameField] = "string"
243
+ assert(@obj.validate(auto_correct: true))
244
+ assert(@obj.validate(auto_correct: true))
245
+ end
246
+
247
+ it "checks whether the value is an allowed one" do
248
+ @obj.value[:AllowedValues] = 7
249
+ refute(@obj.validate(auto_correct: false))
250
+ @obj.value[:AllowedValues] = 1
251
+ assert(@obj.validate(auto_correct: false))
252
+ end
253
+
254
+ it "checks whether a field needs to be indirect w/wo auto_correct" do
255
+ @obj.value[:Inherited] = HexaPDF::Object.new(:test, oid: 1)
256
+ refute(@obj.validate(auto_correct: false))
257
+ assert(@obj.validate(auto_correct: true))
258
+ assert_equal(:test, @obj.value[:Inherited])
259
+
260
+ @obj.value[:TestClass] = {Inherited: :symbol}
261
+ refute(@obj.validate(auto_correct: false))
262
+ assert(@obj.validate(auto_correct: true))
263
+ assert_equal(1, @obj.value[:TestClass].oid)
264
+
265
+ @obj.value[:TestClass] = HexaPDF::Object.new({Inherited: :symbol})
266
+ assert(@obj.validate(auto_correct: true))
267
+ assert_equal(1, @obj.value[:TestClass].oid)
268
+ end
269
+
270
+ it "validates values that are PDF objects" do
271
+ @obj.value[:TestClass] = @test_class.new(nil, document: self)
272
+ refute(@obj.validate)
273
+ @obj.value[:TestClass][:Inherited] = :symbol
274
+ assert(@obj.validate)
275
+ end
276
+
277
+ it "validates direct PDF objects nested in hashes" do
278
+ @obj[:TestClass] = {
279
+ Inherited: :symbol,
280
+ Nested: {Nested: {TestClass: @test_class.new(nil, document: self)}},
281
+ }
282
+ refute(@obj.validate)
283
+ @obj[:TestClass][:Nested][:Nested][:TestClass][:Inherited] = :symbol
284
+ assert(@obj.validate)
285
+ end
286
+
287
+ it "makes sure validation works in special case where the dictionary is modified" do
288
+ @dict[:Array] = 5
289
+ refute(@dict.validate {|_, _, object| object[:Boolean] })
290
+ end
291
+ end
292
+
293
+ describe "delete" do
294
+ it "deletes an entry from the underlying hash value and returns its value" do
295
+ assert_equal(5, @dict.delete(:Other))
296
+ refute(@dict.value.key?(:Other))
297
+ end
298
+
299
+ it "returns nil if no entry with the given name exists" do
300
+ assert_nil(@dict.delete(:SomethingUnknown))
301
+ end
302
+ end
303
+
304
+ describe "each" do
305
+ it "iterates over all name-value pairs in the dictionary" do
306
+ @dict[:TestClass] = {}
307
+ data = [:Array, [3, 4], :Other, 5, :Object, :obj, :TestClass, @dict[:TestClass]]
308
+ @dict.each do |name, value|
309
+ assert_equal(data.shift, name)
310
+ assert_equal(data.shift, value)
311
+ end
312
+ end
313
+ end
314
+
315
+ describe "to_h" do
316
+ it "returns a shallow copy of the value" do
317
+ obj = @dict.to_h
318
+ refute_equal(obj.object_id, @dict.value.object_id)
319
+ assert_equal(obj, @dict.value)
320
+ end
321
+ end
322
+
323
+ describe "type" do
324
+ it "returns the /Type entry" do
325
+ @dict[:Type] = :Test
326
+ assert_equal(:Test, @dict.type)
327
+ end
328
+
329
+ it "returns the value from Object#type if not /Type entry is present" do
330
+ assert_equal(:Unknown, @dict.type)
331
+ end
332
+ end
333
+
334
+ describe "empty?" do
335
+ it "returns true if the dictionary contains no entries" do
336
+ assert(HexaPDF::Dictionary.new({}).empty?)
337
+ refute(HexaPDF::Dictionary.new({x: 5}).empty?)
338
+ end
339
+ end
340
+ end