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,308 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require_relative '../../content/common'
5
+ require 'hexapdf/document'
6
+ require 'hexapdf/type/acro_form/button_field'
7
+
8
+ describe HexaPDF::Type::AcroForm::ButtonField do
9
+ before do
10
+ @doc = HexaPDF::Document.new
11
+ @field = @doc.add({FT: :Btn, T: 'button'}, type: :XXAcroFormField, subtype: :Btn)
12
+ end
13
+
14
+ it "can be initialized as push button" do
15
+ @field.initialize_as_push_button
16
+ assert_nil(@field[:V])
17
+ assert(@field.push_button?)
18
+ end
19
+
20
+ it "can be initialized as check box" do
21
+ @field.initialize_as_check_box
22
+ assert_equal(:Off, @field[:V])
23
+ assert(@field.check_box?)
24
+ end
25
+
26
+ it "can be initialized as radio button" do
27
+ @field.initialize_as_radio_button
28
+ assert_equal(:Off, @field[:V])
29
+ assert_equal(1 << 15, @field[:Ff])
30
+ end
31
+
32
+ describe "push button" do
33
+ before do
34
+ @field.flag(:push_button)
35
+ end
36
+
37
+ it "can be asked whether it is a push button field" do
38
+ @field.flag(:push_button)
39
+ assert(@field.push_button?)
40
+ end
41
+
42
+ it "always returns nil when getting the field value" do
43
+ @field[:V] = :test
44
+ assert_nil(@field.field_value)
45
+ end
46
+
47
+ it "doesn't set a field value" do
48
+ @field.field_value = :test
49
+ assert_nil(@field[:V])
50
+ end
51
+
52
+ it "returns the correct concrete field type" do
53
+ assert_equal(:push_button, @field.concrete_field_type)
54
+ end
55
+
56
+ it "applies sensible default values when creating a widget" do
57
+ widget = @field.create_widget(@doc.pages.add)
58
+ border_style = widget.border_style
59
+ assert_equal([0], border_style.color.components)
60
+ assert_equal(1, border_style.width)
61
+ assert_equal(:beveled, border_style.style)
62
+ assert_equal([0.5], widget.background_color.components)
63
+ end
64
+ end
65
+
66
+ describe "check box" do
67
+ before do
68
+ @field.unflag(:push_button)
69
+ @field.unflag(:radio)
70
+ end
71
+
72
+ it "can be asked whether it is a check box field" do
73
+ assert(@field.check_box?)
74
+ end
75
+
76
+ it "returns a correct field value" do
77
+ refute(@field.field_value)
78
+ @field[:V] = :Off
79
+ refute(@field.field_value)
80
+ @field[:V] = :Yes
81
+ assert_equal(:Yes, @field.field_value)
82
+ end
83
+
84
+ it "sets a correct field value" do
85
+ @field.create_widget(@doc.pages.add, value: :check)
86
+ @field.field_value = true
87
+ assert_equal(:check, @field[:V])
88
+ @field.field_value = false
89
+ assert_equal(:Off, @field[:V])
90
+ @field.field_value = "check"
91
+ assert_equal(:check, @field[:V])
92
+ assert_raises(HexaPDF::Error) { @field.field_value = :unknown }
93
+ end
94
+
95
+ it "returns the correct concrete field type" do
96
+ assert_equal(:check_box, @field.concrete_field_type)
97
+ end
98
+
99
+ it "updates the widgets after setting the field value" do
100
+ widget = @field.create_widget(@doc.pages.add, value: :check)
101
+ @field.field_value = true
102
+ assert_equal(:check, widget[:AS])
103
+ end
104
+
105
+ it "returns an array of allowed values" do
106
+ @field.create_widget(@doc.pages.add, value: "Test")
107
+ @field.create_widget(@doc.pages.add, value: "Test")
108
+ @field.create_widget(@doc.pages.add, value: :x)
109
+ assert_equal([:Test, :x], @field.allowed_values)
110
+ end
111
+
112
+ it "applies sensible default values when creating a widget" do
113
+ widget = @field.create_widget(@doc.pages.add)
114
+ assert_equal({Yes: nil, Off: nil}, widget[:AP][:N].value)
115
+ border_style = widget.border_style
116
+ assert_equal([0], border_style.color.components)
117
+ assert_equal(1, border_style.width)
118
+ assert_equal(:solid, border_style.style)
119
+ assert_equal([1], widget.background_color.components)
120
+ assert_equal(:check, widget.marker_style.style)
121
+ end
122
+
123
+ it "fails if the value argument for create_widget doesn't respond to to_sym" do
124
+ assert_raises(ArgumentError) { @field.create_widget(@doc.pages.add, value: 5) }
125
+ end
126
+ end
127
+
128
+ describe "radio button" do
129
+ before do
130
+ @field.unflag(:push_button)
131
+ @field.flag(:radio)
132
+ end
133
+
134
+ it "can be asked whether it is a radio button field" do
135
+ assert(@field.radio_button?)
136
+ end
137
+
138
+ it "returns a correct field value" do
139
+ assert_nil(@field.field_value)
140
+ @field[:V] = :Off
141
+ assert_nil(@field.field_value)
142
+ @field[:V] = :name
143
+ assert_equal(:name, @field.field_value)
144
+ end
145
+
146
+ it "sets a correct field value" do
147
+ @field.create_widget(@doc.pages.add, value: :button1)
148
+
149
+ @field.field_value = "button1"
150
+ assert_equal(:button1, @field[:V])
151
+ @field.field_value = nil
152
+ assert_equal(:Off, @field[:V])
153
+ assert_raises(HexaPDF::Error) { @field.field_value = :unknown }
154
+ end
155
+
156
+ it "returns the correct concrete field type" do
157
+ assert_equal(:radio_button, @field.concrete_field_type)
158
+ end
159
+
160
+ it "updates the widgets after setting the field value" do
161
+ widget = @field.create_widget(@doc.pages.add, value: :Test)
162
+ @field.field_value = :Test
163
+ assert_equal(:Test, widget[:AS])
164
+ end
165
+
166
+ it "returns an array of allowed values" do
167
+ @field.create_widget(@doc.pages.add, value: "Test")
168
+ @field.create_widget(@doc.pages.add, value: :x)
169
+ @field.create_widget(@doc.pages.add, value: :y)
170
+ assert_equal([:Test, :x, :y], @field.allowed_values)
171
+ end
172
+
173
+ it "applies sensible default values when creating a widget" do
174
+ widget = @field.create_widget(@doc.pages.add, value: 'test')
175
+ border_style = widget.border_style
176
+ assert_equal([0], border_style.color.components)
177
+ assert_equal(1, border_style.width)
178
+ assert_equal(:solid, border_style.style)
179
+ assert_equal([1], widget.background_color.components)
180
+ assert_equal(:circle, widget.marker_style.style)
181
+ assert_equal({test: nil, Off: nil}, widget[:AP][:N].value)
182
+ end
183
+
184
+ it "always creates standalone widgets" do
185
+ refute_same(@field.data, @field.create_widget(@doc.pages.add, value: 'test'))
186
+ end
187
+
188
+ it "fails if the value argument is not provided for create_widget" do
189
+ assert_raises(ArgumentError) { @field.create_widget(@doc.pages.add) }
190
+ end
191
+
192
+ it "fails if the value argument for create_widget doesn't respond to to_sym" do
193
+ assert_raises(ArgumentError) { @field.create_widget(@doc.pages.add, value: 5) }
194
+ end
195
+ end
196
+
197
+ it "returns a default field value" do
198
+ assert_method_invoked(@field, :normalized_field_value, [:DV]) do
199
+ @field.default_field_value
200
+ end
201
+ end
202
+
203
+ it "sets a default field value" do
204
+ assert_method_invoked(@field, :normalized_field_value_set, [:DV, :value]) do
205
+ @field.default_field_value = :value
206
+ end
207
+ end
208
+
209
+ it "resolves /Opt as inheritable field" do
210
+ @field[:Parent] = {Opt: 5}
211
+ assert_equal(5, @field[:Opt])
212
+
213
+ @field[:Opt] = 6
214
+ assert_equal(6, @field[:Opt])
215
+ end
216
+
217
+ describe "create_appearances" do
218
+ it "works for check boxes" do
219
+ @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
220
+ @field.create_appearances
221
+ assert(@field[:AP][:N][:Yes])
222
+ end
223
+
224
+ it "works for radio buttons" do
225
+ @field.initialize_as_radio_button
226
+ widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0], value: :test)
227
+ @field.create_appearances
228
+ assert(widget[:AP][:N][:test])
229
+ end
230
+
231
+ it "won't generate appearances if they already exist" do
232
+ widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
233
+ @field.create_appearances
234
+ yes = widget.appearance_dict.normal_appearance[:Yes]
235
+ off = widget.appearance_dict.normal_appearance[:Off]
236
+ @field.create_appearances
237
+ assert_same(yes, widget.appearance_dict.normal_appearance[:Yes])
238
+ assert_same(off, widget.appearance_dict.normal_appearance[:Off])
239
+
240
+ @field.delete_widget(widget)
241
+ @field.flag(:push_button)
242
+ widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0], AP: {N: @doc.wrap({}, stream: '')})
243
+ appearance = widget.appearance_dict.normal_appearance
244
+ @field.create_appearances
245
+ assert_same(appearance, widget.appearance_dict.normal_appearance)
246
+ end
247
+
248
+ it "always generates appearances if force is true" do
249
+ widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
250
+ @field.create_appearances
251
+ yes = widget.appearance_dict.normal_appearance[:Yes]
252
+ @field.create_appearances(force: true)
253
+ refute_same(yes, widget.appearance_dict.normal_appearance[:Yes])
254
+ end
255
+
256
+ it "fails for unsupported button types" do
257
+ @field.flag(:push_button)
258
+ @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
259
+ assert_raises(HexaPDF::Error) { @field.create_appearances }
260
+ end
261
+
262
+ it "uses the configuration option acro_form.appearance_generator" do
263
+ @doc.config['acro_form.appearance_generator'] = 'NonExistent'
264
+ assert_raises(Exception) { @field.create_appearances }
265
+ end
266
+ end
267
+
268
+ describe "update_widgets" do
269
+ it "does nothing for push buttons" do
270
+ @field.flag(:push_button)
271
+ widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
272
+ @field.update_widgets
273
+ assert_nil(widget[:AS])
274
+ end
275
+
276
+ it "sets the /AS entry correctly" do
277
+ widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
278
+ assert_nil(widget[:AS])
279
+ @field.update_widgets
280
+ assert_equal(:Off, widget[:AS])
281
+
282
+ @field[:V] = :Yes
283
+ @field.update_widgets
284
+ assert_equal(:Yes, widget[:AS])
285
+ end
286
+
287
+ it "creates the appearances if necessary" do
288
+ widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
289
+ assert_nil(widget[:AP][:N][:Yes])
290
+ @field.update_widgets
291
+ assert(widget[:AP][:N][:Yes])
292
+ end
293
+ end
294
+
295
+ describe "validation" do
296
+ it "checks the value of the /FT field" do
297
+ @field.delete(:FT)
298
+ refute(@field.validate(auto_correct: false))
299
+ assert(@field.validate)
300
+ assert_equal(:Btn, @field.field_type)
301
+ end
302
+
303
+ it "sets the field value to :Off it it is not set" do
304
+ assert(@field.validate)
305
+ assert_equal(:Off, @field[:V])
306
+ end
307
+ end
308
+ end
@@ -0,0 +1,220 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/document'
5
+ require 'hexapdf/type/acro_form/choice_field'
6
+
7
+ describe HexaPDF::Type::AcroForm::ChoiceField do
8
+ before do
9
+ @doc = HexaPDF::Document.new
10
+ @field = @doc.add({FT: :Ch, T: 'choice'}, type: :XXAcroFormField, subtype: :Ch)
11
+ end
12
+
13
+ it "can be initialized as list box" do
14
+ @field.initialize_as_list_box
15
+ assert_nil(@field[:V])
16
+ assert(@field.list_box?)
17
+ end
18
+
19
+ it "can be initialized as combo box" do
20
+ @field.initialize_as_combo_box
21
+ assert_nil(@field[:V])
22
+ assert(@field.combo_box?)
23
+ end
24
+
25
+ describe "field_value" do
26
+ it "returns the correct Unicode string value" do
27
+ @field[:V] = "H\xe4llo".b
28
+ assert_equal("Hällo", @field.field_value)
29
+ end
30
+
31
+ it "returns an array of Unicode string values" do
32
+ @field[:V] = ["H\xe4llo".b, "\xFE\xFF".b << "Óthér".encode('UTF-16BE').b]
33
+ assert_equal(["Hällo", "Óthér"], @field.field_value)
34
+ end
35
+ end
36
+
37
+ describe "field_value=" do
38
+ before do
39
+ @field.option_items = ["test", "something", "other", "neu"]
40
+ end
41
+
42
+ it "updates the widgets to reflect the changed value" do
43
+ @field.initialize_as_combo_box
44
+ widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
45
+ @field.set_default_appearance_string
46
+ @field.field_value = 'test'
47
+ assert(widget[:AP][:N])
48
+ end
49
+
50
+ describe "combo_box" do
51
+ before do
52
+ @field.initialize_as_combo_box
53
+ @field[:I] = 2
54
+ end
55
+
56
+ it "can set the value for an uneditable combo box" do
57
+ @field.field_value = 'test'
58
+ assert_equal("test", @field[:V])
59
+ assert_nil(@field[:I])
60
+ end
61
+
62
+ it "can set the value for an editable combo box" do
63
+ @field.flag(:edit)
64
+ @field.field_value = 'another'
65
+ assert_equal("another", @field[:V])
66
+ assert_nil(@field[:I])
67
+ end
68
+
69
+ it "fails if mulitple values are provided for a combo box" do
70
+ assert_raises(HexaPDF::Error) { @field.field_value = ['a', 'b'] }
71
+ end
72
+
73
+ it "fails if an unlisted value is specified for an uneditable combo box" do
74
+ assert_raises(HexaPDF::Error) { @field.field_value = 'a' }
75
+ end
76
+ end
77
+
78
+ describe "list_box" do
79
+ before do
80
+ @field.initialize_as_list_box
81
+ end
82
+
83
+ it "can set a single value" do
84
+ @field.field_value = 'test'
85
+ assert_equal("test", @field[:V])
86
+ end
87
+
88
+ it "can set a multiple values if the list box is a multi-select" do
89
+ @field.flag(:multi_select)
90
+ @field.field_value = ['other', 'test']
91
+ assert_equal(['other', 'test'], @field[:V].value)
92
+ assert_equal([0, 2], @field[:I].value)
93
+ end
94
+
95
+ it "can read and set the top index" do
96
+ assert_raises(ArgumentError) { @field.list_box_top_index = 4 }
97
+ @field.delete(:Opt)
98
+ assert_raises(ArgumentError) { @field.list_box_top_index = 0 }
99
+ @field.option_items = [1, 2, 3, 4]
100
+ @field.list_box_top_index = 2
101
+ assert_equal(2, @field.list_box_top_index)
102
+ end
103
+
104
+ it "fails if mulitple values are provided but the list box is not a multi-select" do
105
+ assert_raises(HexaPDF::Error) { @field.field_value = ['a', 'b'] }
106
+ end
107
+
108
+ it "fails if an unlisted value is specified" do
109
+ assert_raises(HexaPDF::Error) { @field.field_value = 'a' }
110
+ end
111
+ end
112
+ end
113
+
114
+ it "sets and returns the default field value" do
115
+ @field.option_items = ["hällo"]
116
+ @field.default_field_value = 'hällo'
117
+ assert_equal('hällo', @field.default_field_value)
118
+ assert_raises(HexaPDF::Error) { @field.default_field_value = 'unknown' }
119
+ end
120
+
121
+ describe "option items" do
122
+ before do
123
+ @items = [["a", "Zx"], "\xFE\xFF".b << "Töne".encode('UTF-16BE').b, "H\xe4llo".b,]
124
+ end
125
+
126
+ it "sets the option items" do
127
+ @field.option_items = @items
128
+ assert_equal(@items, @field[:Opt].value)
129
+
130
+ @field.flag(:sort)
131
+ @field.option_items = @items
132
+ assert_equal(@items.values_at(2, 1, 0), @field[:Opt].value)
133
+ end
134
+
135
+ it "can retrieve the option items" do
136
+ @field[:Opt] = @items
137
+ assert_equal(["Zx", "Töne", "Hällo"], @field.option_items)
138
+ end
139
+
140
+ it "can retrieve the export values" do
141
+ @field[:Opt] = @items
142
+ assert_equal(["a", "Töne", "Hällo"], @field.export_values)
143
+ end
144
+ end
145
+
146
+ it "returns the correct concrete field type" do
147
+ assert_equal(:list_box, @field.concrete_field_type)
148
+ @field.initialize_as_combo_box
149
+ assert_equal(:combo_box, @field.concrete_field_type)
150
+ end
151
+
152
+ describe "create_appearances" do
153
+ before do
154
+ @widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
155
+ end
156
+
157
+ it "works for combo box fields" do
158
+ @field.initialize_as_combo_box
159
+ @field.set_default_appearance_string
160
+ @field.create_appearances
161
+ assert(@field[:AP][:N])
162
+ end
163
+
164
+ it "works for list box fields" do
165
+ @field.initialize_as_list_box
166
+ @field.set_default_appearance_string
167
+ @field.create_appearances
168
+ assert(@field[:AP][:N])
169
+ end
170
+
171
+ it "only creates a new appearance if the involved dictionary values have changed per widget" do
172
+ @field.initialize_as_list_box
173
+ @field.set_default_appearance_string
174
+ @field.create_appearances
175
+ appearance_stream = @field[:AP][:N].raw_stream
176
+
177
+ @field.create_appearances
178
+ assert_same(appearance_stream, @field[:AP][:N].raw_stream)
179
+
180
+ do_check = lambda do
181
+ @field.create_appearances
182
+ refute_same(appearance_stream, @field[:AP][:N].raw_stream)
183
+ appearance_stream = @field[:AP][:N].raw_stream
184
+ end
185
+
186
+ @field.option_items = ['a', 'b', 'c']
187
+ do_check.call
188
+
189
+ @field.list_box_top_index = 2
190
+ do_check.call
191
+
192
+ @field.field_value = 'b'
193
+ do_check.call
194
+
195
+ widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
196
+ assert_nil(widget[:AP])
197
+ @field.create_appearances
198
+ refute_nil(widget[:AP][:N])
199
+ end
200
+
201
+ it "force the creation of appearance streams when force: true" do
202
+ @field.initialize_as_list_box
203
+ @field.set_default_appearance_string
204
+ @field.create_appearances
205
+ appearance_stream = @field[:AP][:N].raw_stream
206
+
207
+ @field.create_appearances(force: true)
208
+ refute_same(appearance_stream, @field[:AP][:N].raw_stream)
209
+ end
210
+ end
211
+
212
+ describe "validation" do
213
+ it "checks the value of the /FT field" do
214
+ @field.delete(:FT)
215
+ refute(@field.validate(auto_correct: false))
216
+ assert(@field.validate)
217
+ assert_equal(:Ch, @field.field_type)
218
+ end
219
+ end
220
+ end