hexapdf 0.24.0 → 0.24.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -0
  3. data/lib/hexapdf/cli/command.rb +2 -2
  4. data/lib/hexapdf/cli/info.rb +1 -1
  5. data/lib/hexapdf/cli/optimize.rb +1 -1
  6. data/lib/hexapdf/document/files.rb +1 -1
  7. data/lib/hexapdf/document/images.rb +1 -1
  8. data/lib/hexapdf/document.rb +7 -5
  9. data/lib/hexapdf/object.rb +7 -4
  10. data/lib/hexapdf/parser.rb +1 -1
  11. data/lib/hexapdf/revisions.rb +3 -0
  12. data/lib/hexapdf/task/dereference.rb +1 -1
  13. data/lib/hexapdf/task/optimize.rb +2 -2
  14. data/lib/hexapdf/task.rb +1 -1
  15. data/lib/hexapdf/test_utils.rb +114 -0
  16. data/lib/hexapdf/version.rb +1 -1
  17. data/test/hexapdf/content/graphic_object/test_geom2d.rb +0 -1
  18. data/test/hexapdf/content/graphic_object/test_solid_arc.rb +11 -21
  19. data/test/hexapdf/content/test_canvas.rb +0 -1
  20. data/test/hexapdf/content/test_parser.rb +1 -2
  21. data/test/hexapdf/encryption/test_aes.rb +9 -9
  22. data/test/hexapdf/encryption/test_arc4.rb +2 -2
  23. data/test/hexapdf/encryption/test_security_handler.rb +1 -1
  24. data/test/hexapdf/filter/common.rb +0 -1
  25. data/test/hexapdf/filter/test_predictor.rb +0 -1
  26. data/test/hexapdf/font/true_type/common.rb +4 -8
  27. data/test/hexapdf/font/true_type/table/common.rb +18 -16
  28. data/test/hexapdf/font/true_type/test_font.rb +1 -1
  29. data/test/hexapdf/font/true_type/test_table.rb +4 -4
  30. data/test/hexapdf/layout/test_box.rb +0 -1
  31. data/test/hexapdf/layout/test_column_box.rb +0 -1
  32. data/test/hexapdf/layout/test_image_box.rb +0 -1
  33. data/test/hexapdf/layout/test_list_box.rb +0 -1
  34. data/test/hexapdf/layout/test_style.rb +0 -1
  35. data/test/hexapdf/layout/test_text_box.rb +0 -1
  36. data/test/hexapdf/layout/test_text_fragment.rb +0 -1
  37. data/test/hexapdf/layout/test_text_layouter.rb +1 -2
  38. data/test/hexapdf/test_composer.rb +0 -1
  39. data/test/hexapdf/test_object.rb +1 -1
  40. data/test/hexapdf/test_parser.rb +12 -5
  41. data/test/hexapdf/test_stream.rb +0 -2
  42. data/test/hexapdf/test_writer.rb +2 -2
  43. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +0 -1
  44. data/test/hexapdf/type/acro_form/test_button_field.rb +0 -1
  45. data/test/hexapdf/type/acro_form/test_text_field.rb +0 -1
  46. data/test/hexapdf/type/signature/common.rb +55 -53
  47. data/test/hexapdf/type/test_form.rb +3 -4
  48. data/test/hexapdf/type/test_page.rb +1 -2
  49. data/test/test_helper.rb +1 -39
  50. metadata +4 -5
  51. data/test/hexapdf/content/common.rb +0 -39
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9be9871c8033a23eb240dc0b6300bcb33ba8ccef107f35189cb8af3faf308a61
4
- data.tar.gz: 875797999dc46cefdb39dd31f1649525a11716915af5a83a6c38c0dc100cca2e
3
+ metadata.gz: 9d7da895c4baff0d0e5114a6c423f3f6ca3de02004807d7f5a81c19e404edff1
4
+ data.tar.gz: 89c6dd4709077bf6c6ccb710addeccfdf23a4a75d37dda4357f36c25d5f8865d
5
5
  SHA512:
6
- metadata.gz: 8700678297a316b14a604045ab7da8c371d7cbcebb771d8c878fff4306e36ff7e72b898fb4c63e98599493a7b93480a34bd099dc102ef0e431d825fe1e11ae41
7
- data.tar.gz: 4892bb8868475b4bfe65c5938097589f9544bb4b7b9bef568b1ac60a7932eced09f2eee53edc38212654e522c4cc4e5edd8fde7cb6b6078e27ccf18e131e96aa
6
+ metadata.gz: f5400d99a41fec977ba734bf487af5ce847bdea1f762a0f2df98b45f20952ee4059b08b75ff76ddb3e87db2191f1f7d18b01d9c1d8911b44fbdfc54ea2faa478
7
+ data.tar.gz: f70679b7844a27d2da4f208900309b1820c39174923ab7d0645edbeddaa60455bd359a6e355c254e8764de013078d199846ec5ac443de3d39dd1abc4ad93c890
data/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## 0.24.1 - 2022-08-11
2
+
3
+ ### Added
4
+
5
+ * [HexaPDF::TestUtils] module that contains helper methods useful for testing
6
+ various parts of HexaPDF
7
+
8
+ ### Changed
9
+
10
+ * All applicable places to only load the current version of PDF objects, to
11
+ avoid possible inconsistencies when working with files containing multiple
12
+ revisions
13
+
14
+ ### Fixed
15
+
16
+ * Parsing of streams with an invalid length value that led to a parsing error
17
+ * [HexaPDF::Object#==] to only allow comparing simple values to non-indirect
18
+ objects and not also other HexaPDF::Object instances
19
+
20
+
1
21
  ## 0.24.0 - 2022-08-01
2
22
 
3
23
  ### Added
@@ -244,7 +244,7 @@ module HexaPDF
244
244
  compress_pages: @out_options.compress_pages,
245
245
  prune_page_resources: @out_options.prune_page_resources)
246
246
  if @out_options.streams != :preserve || @out_options.optimize_fonts
247
- doc.each(only_current: false) do |obj|
247
+ doc.each do |obj|
248
248
  optimize_stream(obj)
249
249
  optimize_font(obj)
250
250
  end
@@ -352,7 +352,7 @@ module HexaPDF
352
352
  def remove_unused_pages(doc)
353
353
  retained = doc.pages.each_with_object({}) {|page, h| h[page.data] = true }
354
354
  retained[doc.pages.root.data] = true
355
- doc.each(only_current: false) do |obj|
355
+ doc.each do |obj|
356
356
  next unless obj.kind_of?(HexaPDF::Dictionary)
357
357
  if (obj.type == :Pages || obj.type == :Page) && !retained.key?(obj.data)
358
358
  doc.delete(obj)
@@ -103,7 +103,7 @@ module HexaPDF
103
103
  "#{correctable ? '(correctable)' : ''}"
104
104
  end
105
105
  doc.trailer.validate(auto_correct: true, &validation_block)
106
- doc.each(only_current: true, only_loaded: false) do |obj|
106
+ doc.each(only_loaded: false) do |obj|
107
107
  indirect_object = obj
108
108
  obj.validate(auto_correct: true, &validation_block)
109
109
  end
@@ -90,7 +90,7 @@ module HexaPDF
90
90
  end
91
91
  doc.catalog[:Pages] = page_tree
92
92
 
93
- doc.each(only_current: false) do |obj, revision|
93
+ doc.each do |obj, revision|
94
94
  next unless obj.kind_of?(HexaPDF::Dictionary)
95
95
  if (obj.type == :Pages || obj.type == :Page) && !retained.key?(obj.data)
96
96
  revision.delete(obj)
@@ -104,7 +104,7 @@ module HexaPDF
104
104
  return to_enum(__method__, search: search) unless block_given?
105
105
 
106
106
  if search
107
- @document.each(only_current: false) do |obj|
107
+ @document.each do |obj|
108
108
  yield(obj) if obj.type == :Filespec
109
109
  end
110
110
  else
@@ -88,7 +88,7 @@ module HexaPDF
88
88
  # Note that only real images are yielded which means, for example, that images used as soft
89
89
  # mask are not.
90
90
  def each(&block)
91
- images = @document.each(only_current: false).select do |obj|
91
+ images = @document.each.select do |obj|
92
92
  next unless obj.kind_of?(HexaPDF::Dictionary)
93
93
  obj[:Subtype] == :Image && !obj[:ImageMask]
94
94
  end
@@ -386,8 +386,10 @@ module HexaPDF
386
386
  #
387
387
  # Yields every object and the revision it is in.
388
388
  #
389
- # If +only_current+ is +true+, only the current version of each object is yielded, otherwise
390
- # all objects from all revisions.
389
+ # If +only_current+ is +true+, only the current version of each object is yielded, otherwise all
390
+ # objects from all revisions. *Note* that it is normally not necessary or useful to retrieve all
391
+ # objects from all revisions and if it is still done that care has to be taken to avoid an
392
+ # invalid document state.
391
393
  #
392
394
  # If +only_loaded+ is +true+, only the already loaded objects are yielded.
393
395
  #
@@ -602,15 +604,15 @@ module HexaPDF
602
604
  signatures.add(file_or_io, handler, signature: signature, write_options: write_options)
603
605
  end
604
606
 
605
- # Validates all objects, or, if +only_loaded+ is +true+, only loaded objects, with optional
606
- # auto-correction, and returns +true+ if everything is fine.
607
+ # Validates all current objects, or, if +only_loaded+ is +true+, only loaded objects, with
608
+ # optional auto-correction, and returns +true+ if everything is fine.
607
609
  #
608
610
  # If a block is given, it is called on validation problems.
609
611
  #
610
612
  # See HexaPDF::Object#validate for more information.
611
613
  def validate(auto_correct: true, only_loaded: false, &block) #:yield: msg, correctable, object
612
614
  result = trailer.validate(auto_correct: auto_correct, &block)
613
- each(only_current: false, only_loaded: only_loaded) do |obj|
615
+ each(only_loaded: only_loaded) do |obj|
614
616
  result &&= obj.validate(auto_correct: auto_correct, &block)
615
617
  end
616
618
  result
@@ -333,12 +333,15 @@ module HexaPDF
333
333
  (oid == other.oid ? gen <=> other.gen : oid <=> other.oid)
334
334
  end
335
335
 
336
- # Returns +true+ if the other object is an Object and wraps the same #data structure, if the
337
- # other object is a Reference with the same oid/gen, or if this object is not indirect and its
338
- # value is equal to the other object.
336
+ # Returns +true+ in the following cases:
337
+ #
338
+ # * The other object is an Object and wraps the same #data structure.
339
+ # * The other object is a Reference with the same oid/gen.
340
+ # * This object is not indirect and the other object is not an Object and equal to the value of
341
+ # this object.
339
342
  def ==(other)
340
343
  (other.kind_of?(Object) && data == other.data) || (other.kind_of?(Reference) && other == self) ||
341
- (!indirect? && other == data.value)
344
+ (!indirect? && !other.kind_of?(Object) && other == data.value)
342
345
  end
343
346
 
344
347
  # Returns +true+ if the other object references the same PDF object as this object.
@@ -172,7 +172,7 @@ module HexaPDF
172
172
  end
173
173
  @tokenizer.pos = pos + length rescue pos
174
174
 
175
- tok = @tokenizer.next_token
175
+ tok = @tokenizer.next_token rescue nil
176
176
  unless tok.kind_of?(Tokenizer::Token) && tok == 'endstream'
177
177
  maybe_raise("Invalid stream length, keyword endstream not found", pos: @tokenizer.pos)
178
178
  @tokenizer.pos = pos
@@ -233,6 +233,9 @@ module HexaPDF
233
233
  # * Additionally, there may also be objects with the same object number but different
234
234
  # generation numbers in different revisions, e.g. one object with oid/gen [3,0] and one with
235
235
  # oid/gen [3,1].
236
+ #
237
+ # *Note* that setting +only_current+ to +false+ is normally not necessary and should not be
238
+ # done. If it is still done, one has to take care to avoid an invalid document state.
236
239
  def each_object(only_current: true, only_loaded: false, &block)
237
240
  unless block_given?
238
241
  return to_enum(__method__, only_current: only_current, only_loaded: only_loaded)
@@ -72,7 +72,7 @@ module HexaPDF
72
72
  else
73
73
  dereference_all(@doc.trailer)
74
74
  @result = []
75
- @doc.each(only_current: false) do |obj|
75
+ @doc.each do |obj|
76
76
  if !@seen.key?(obj.data) && obj.type != :ObjStm && obj.type != :XRef
77
77
  @result << obj
78
78
  elsif obj.kind_of?(HexaPDF::Stream) && (val = obj.value[:Length]) &&
@@ -92,7 +92,7 @@ module HexaPDF
92
92
  elsif xref_streams != :preserve
93
93
  process_xref_streams(doc, xref_streams)
94
94
  else
95
- doc.each(only_current: false, &method(:delete_fields_with_defaults))
95
+ doc.each(&method(:delete_fields_with_defaults))
96
96
  end
97
97
  end
98
98
 
@@ -193,7 +193,7 @@ module HexaPDF
193
193
  def self.process_xref_streams(doc, method)
194
194
  case method
195
195
  when :delete
196
- doc.each(only_current: false) do |obj, rev|
196
+ doc.each do |obj, rev|
197
197
  if obj.type == :XRef
198
198
  rev.delete(obj)
199
199
  else
data/lib/hexapdf/task.rb CHANGED
@@ -58,7 +58,7 @@ module HexaPDF
58
58
  #
59
59
  # doc = HexaPDF::Document.new
60
60
  # doc.config['task.map'][:validate] = lambda do |doc|
61
- # doc.each(only_current: false) {|obj| obj.validate || raise "Invalid object #{obj}"}
61
+ # doc.each {|obj| obj.validate || raise "Invalid object #{obj}"}
62
62
  # end
63
63
  module Task
64
64
 
@@ -0,0 +1,114 @@
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
+ #
3
+ #--
4
+ # This file is part of HexaPDF.
5
+ #
6
+ # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
+ # Copyright (C) 2014-2022 Thomas Leitner
8
+ #
9
+ # HexaPDF is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU Affero General Public License version 3 as
11
+ # published by the Free Software Foundation with the addition of the
12
+ # following permission added to Section 15 as permitted in Section 7(a):
13
+ # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
14
+ # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
15
+ # INFRINGEMENT OF THIRD PARTY RIGHTS.
16
+ #
17
+ # HexaPDF is distributed in the hope that it will be useful, but WITHOUT
18
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
20
+ # License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Affero General Public License
23
+ # along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
24
+ #
25
+ # The interactive user interfaces in modified source and object code
26
+ # versions of HexaPDF must display Appropriate Legal Notices, as required
27
+ # under Section 5 of the GNU Affero General Public License version 3.
28
+ #
29
+ # In accordance with Section 7(b) of the GNU Affero General Public
30
+ # License, a covered work must retain the producer line in every PDF that
31
+ # is created or manipulated using HexaPDF.
32
+ #
33
+ # If the GNU Affero General Public License doesn't fit your need,
34
+ # commercial licenses are available at <https://gettalong.at/hexapdf/>.
35
+ #++
36
+
37
+ require 'hexapdf/content/processor'
38
+
39
+ module HexaPDF
40
+
41
+ # Contains various helper methods for testing HexaPDF
42
+ module TestUtils
43
+
44
+ # Can be used to to record operators parsed from content streams.
45
+ class OperatorRecorder < HexaPDF::Content::Processor
46
+
47
+ undef :paint_xobject
48
+
49
+ attr_reader :recorded_ops
50
+
51
+ def initialize
52
+ super
53
+ operators.clear
54
+ @recorded_ops = []
55
+ end
56
+
57
+ def respond_to_missing?(*)
58
+ true
59
+ end
60
+
61
+ def method_missing(msg, *params)
62
+ @recorded_ops << (params.empty? ? [msg] : [msg, params])
63
+ end
64
+
65
+ end
66
+
67
+ # Asserts that the content string contains the operators.
68
+ def assert_operators(content, operators, only_names: false, range: 0..-1)
69
+ processor = OperatorRecorder.new
70
+ HexaPDF::Content::Parser.new.parse(content, processor)
71
+ result = processor.recorded_ops[range]
72
+ result.map!(&:first) if only_names
73
+ assert_equal(operators, result)
74
+ end
75
+
76
+ # Asserts that the method +name+ of +object+ gets invoked with the +expected_values+ when
77
+ # executing the block. +expected_values+ should contain arrays of arguments, one array for each
78
+ # invocation of the method.
79
+ def assert_method_invoked(object, name, *expected_values, check_block: false)
80
+ args = []
81
+ block = []
82
+ object.define_singleton_method(name) {|*la, &lb| args << la; block << lb }
83
+ yield
84
+ assert_equal(expected_values, args, "Incorrect arguments for #{object.class}##{name}")
85
+ block.each do |block_arg|
86
+ assert_kind_of(Proc, block_arg, "Missing block for #{object.class}##{name}") if check_block
87
+ end
88
+ ensure
89
+ object.singleton_class.send(:remove_method, name)
90
+ end
91
+
92
+ # Creates a fiber that yields the given string in +len+ length parts.
93
+ def feeder(string, len = string.length)
94
+ Fiber.new do
95
+ until string.empty?
96
+ Fiber.yield(string.slice!(0, len).force_encoding('BINARY'))
97
+ end
98
+ end
99
+ end
100
+
101
+ # Collects the result from the HexaPDF::Filter source into a binary string.
102
+ def collector(source)
103
+ str = ''.b
104
+ while source.alive? && (data = source.resume)
105
+ str << data
106
+ end
107
+ str
108
+ end
109
+
110
+ end
111
+
112
+ end
113
+
114
+ Minitest::Spec.include(HexaPDF::TestUtils)
@@ -37,6 +37,6 @@
37
37
  module HexaPDF
38
38
 
39
39
  # The version of HexaPDF.
40
- VERSION = '0.24.0'
40
+ VERSION = '0.24.1'
41
41
 
42
42
  end
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'test_helper'
4
- require_relative '../common'
5
4
  require 'hexapdf/document'
6
5
  require 'hexapdf/content'
7
6
  require 'hexapdf/content/graphic_object'
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'test_helper'
4
- require_relative '../common'
5
4
  require 'hexapdf/document'
6
5
  require 'hexapdf/content'
7
6
  require 'hexapdf/content/graphic_object'
@@ -40,13 +39,6 @@ describe HexaPDF::Content::GraphicObject::SolidArc do
40
39
  end
41
40
 
42
41
  describe "draw" do
43
- def operators(content)
44
- processor = TestHelper::OperatorRecorder.new
45
- parser = HexaPDF::Content::Parser.new
46
- parser.parse(content, processor)
47
- processor.recorded_ops
48
- end
49
-
50
42
  before do
51
43
  @doc = HexaPDF::Document.new
52
44
  @doc.config['graphic_object.arc.max_curves'] = 4
@@ -56,31 +48,29 @@ describe HexaPDF::Content::GraphicObject::SolidArc do
56
48
 
57
49
  it "draws a disk" do
58
50
  @canvas.draw(:solid_arc)
59
- ops = operators(@canvas.contents)
60
- assert_equal([:move_to, :curve_to, :curve_to, :curve_to, :curve_to, :close_subpath],
61
- ops.map(&:first))
51
+ assert_operators(@canvas.contents,
52
+ [:move_to, :curve_to, :curve_to, :curve_to, :curve_to, :close_subpath],
53
+ only_names: true)
62
54
  end
63
55
 
64
56
  it "draws a sector" do
65
57
  @canvas.draw(:solid_arc, end_angle: 90)
66
- ops = operators(@canvas.contents)
67
- assert_equal([:move_to, :line_to, :curve_to, :close_subpath],
68
- ops.map(&:first))
58
+ assert_operators(@canvas.contents, [:move_to, :line_to, :curve_to, :close_subpath],
59
+ only_names: true)
69
60
  end
70
61
 
71
62
  it "draws an annulus" do
72
63
  @canvas.draw(:solid_arc, inner_a: 5, inner_b: 5)
73
- ops = operators(@canvas.contents)
74
- assert_equal([:move_to, :curve_to, :curve_to, :curve_to, :curve_to, :close_subpath,
75
- :move_to, :curve_to, :curve_to, :curve_to, :curve_to, :close_subpath],
76
- ops.map(&:first))
64
+ assert_operators(@canvas.contents,
65
+ [:move_to, :curve_to, :curve_to, :curve_to, :curve_to, :close_subpath,
66
+ :move_to, :curve_to, :curve_to, :curve_to, :curve_to, :close_subpath],
67
+ only_names: true)
77
68
  end
78
69
 
79
70
  it "draws an annular sector" do
80
71
  @canvas.draw(:solid_arc, inner_a: 5, inner_b: 5, end_angle: 90)
81
- ops = operators(@canvas.contents)
82
- assert_equal([:move_to, :curve_to, :line_to, :curve_to, :close_subpath],
83
- ops.map(&:first))
72
+ assert_operators(@canvas.contents, [:move_to, :curve_to, :line_to, :curve_to, :close_subpath],
73
+ only_names: true)
84
74
  end
85
75
  end
86
76
  end
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'test_helper'
4
- require_relative 'common'
5
4
  require 'hexapdf/content/canvas'
6
5
  require 'hexapdf/document'
7
6
  require 'hexapdf/content/processor'
@@ -4,7 +4,6 @@ require 'test_helper'
4
4
  require 'hexapdf/content/parser'
5
5
  require 'hexapdf/content/processor'
6
6
  require_relative '../common_tokenizer_tests'
7
- require_relative 'common'
8
7
 
9
8
  describe HexaPDF::Content::Tokenizer do
10
9
  include CommonTokenizerTests
@@ -16,7 +15,7 @@ end
16
15
 
17
16
  describe HexaPDF::Content::Parser do
18
17
  before do
19
- @processor = TestHelper::OperatorRecorder.new
18
+ @processor = HexaPDF::TestUtils::OperatorRecorder.new
20
19
  @parser = HexaPDF::Content::Parser.new
21
20
  end
22
21
 
@@ -67,7 +67,7 @@ describe HexaPDF::Encryption::AES do
67
67
  it "returns the padded result with IV on encryption_fiber" do
68
68
  @padding_data.each do |data|
69
69
  result = @algorithm_class.encryption_fiber('some key' * 2, Fiber.new { data[:plain] })
70
- result = TestHelper.collector(result)
70
+ result = collector(result)
71
71
  assert_equal(data[:length], result.length)
72
72
  assert_equal(data[:cipher_padding][-16, 16], result[-16, 16])
73
73
  end
@@ -77,14 +77,14 @@ describe HexaPDF::Encryption::AES do
77
77
  @padding_data.each do |data|
78
78
  result = @algorithm_class.decryption_fiber('some key' * 2,
79
79
  Fiber.new { 'iv' * 8 + data[:cipher_padding] })
80
- result = TestHelper.collector(result)
80
+ result = collector(result)
81
81
  assert_equal(data[:plain], result)
82
82
  end
83
83
  end
84
84
 
85
85
  it "encryption works with multiple yielded strings" do
86
86
  f = Fiber.new { Fiber.yield('a' * 40); Fiber.yield('test'); "b" * 20 }
87
- result = TestHelper.collector(@algorithm_class.encryption_fiber('some key' * 2, f))
87
+ result = collector(@algorithm_class.encryption_fiber('some key' * 2, f))
88
88
  assert_equal('a' * 40 << 'test' << 'b' * 20, result[16..-17])
89
89
  end
90
90
 
@@ -96,32 +96,32 @@ describe HexaPDF::Encryption::AES do
96
96
  Fiber.yield('a' * 20)
97
97
  8.chr * 8
98
98
  end
99
- result = TestHelper.collector(@algorithm_class.decryption_fiber('some key' * 2, f))
99
+ result = collector(@algorithm_class.decryption_fiber('some key' * 2, f))
100
100
  assert_equal('a' * 40, result)
101
101
  end
102
102
 
103
103
  it "decryption works if the padding is invalid" do
104
104
  f = Fiber.new { 'a' * 16 }
105
- result = TestHelper.collector(@algorithm_class.decryption_fiber('some' * 4, f))
105
+ result = collector(@algorithm_class.decryption_fiber('some' * 4, f))
106
106
  assert_equal('', result)
107
107
 
108
108
  f = Fiber.new { 'a' * 32 }
109
- result = TestHelper.collector(@algorithm_class.decryption_fiber('some' * 4, f))
109
+ result = collector(@algorithm_class.decryption_fiber('some' * 4, f))
110
110
  assert_equal('a' * 16, result)
111
111
 
112
112
  f = Fiber.new { 'a' * 31 << "\x00" }
113
- result = TestHelper.collector(@algorithm_class.decryption_fiber('some' * 4, f))
113
+ result = collector(@algorithm_class.decryption_fiber('some' * 4, f))
114
114
  assert_equal('a' * 15 << "\x00", result)
115
115
 
116
116
  f = Fiber.new { 'a' * 29 << "\x00\x01\x03" }
117
- result = TestHelper.collector(@algorithm_class.decryption_fiber('some' * 4, f))
117
+ result = collector(@algorithm_class.decryption_fiber('some' * 4, f))
118
118
  assert_equal('a' * 13 << "\x00\x01\x03", result)
119
119
  end
120
120
 
121
121
  it "fails on decryption if not enough bytes are provided" do
122
122
  [4, 20, 40].each do |length|
123
123
  assert_raises(HexaPDF::EncryptionError) do
124
- TestHelper.collector(@algorithm_class.decryption_fiber('some' * 4,
124
+ collector(@algorithm_class.decryption_fiber('some' * 4,
125
125
  Fiber.new { 'a' * length }))
126
126
  end
127
127
  end
@@ -31,9 +31,9 @@ describe HexaPDF::Encryption::ARC4 do
31
31
  it "correctly uses klass.encryption_fiber and klass.decryption_fiber" do
32
32
  f = Fiber.new { Fiber.yield('first'); Fiber.yield(''); 'second' }
33
33
  assert_equal('mykeyfirstsecond',
34
- TestHelper.collector(@algorithm_class.encryption_fiber('mykey', f)))
34
+ collector(@algorithm_class.encryption_fiber('mykey', f)))
35
35
  f = Fiber.new { Fiber.yield('first'); 'second' }
36
36
  assert_equal('mykeyfirstsecond',
37
- TestHelper.collector(@algorithm_class.decryption_fiber('mykey', f)))
37
+ collector(@algorithm_class.decryption_fiber('mykey', f)))
38
38
  end
39
39
  end
@@ -344,7 +344,7 @@ describe HexaPDF::Encryption::SecurityHandler do
344
344
  end
345
345
 
346
346
  it "encrypts streams" do
347
- result = TestHelper.collector(@handler.encrypt_stream(@stream))
347
+ result = collector(@handler.encrypt_stream(@stream))
348
348
  @stream.stream = HexaPDF::StreamData.new(proc { result })
349
349
  assert_equal('string', @handler.decrypt(@stream).stream)
350
350
  end
@@ -7,7 +7,6 @@ require 'test_helper'
7
7
  # The filter object needs to be available in the @obj variable and the @all_test_cases variable
8
8
  # needs to hold an array of test cases, i.e. [decoded, encoded] objects.
9
9
  module CommonFilterTests
10
- include TestHelper
11
10
 
12
11
  TEST_BIG_STR = ''.b
13
12
  TEST_BIG_STR << [rand(2**32)].pack('N') while TEST_BIG_STR.length < 2**16
@@ -4,7 +4,6 @@ require_relative 'common'
4
4
  require 'hexapdf/filter/predictor'
5
5
 
6
6
  describe HexaPDF::Filter::Predictor do
7
- include TestHelper
8
7
 
9
8
  module CommonPredictorTests
10
9
  def test_decoding_through_decoder_method
@@ -2,16 +2,12 @@
2
2
 
3
3
  require 'hexapdf/font/true_type/table'
4
4
 
5
- module TestHelper
5
+ class TrueTypeTestTable < HexaPDF::Font::TrueType::Table
6
6
 
7
- class TrueTypeTestTable < HexaPDF::Font::TrueType::Table
8
-
9
- attr_reader :data
10
-
11
- def parse_table
12
- @data = io.read(directory_entry.length)
13
- end
7
+ attr_reader :data
14
8
 
9
+ def parse_table
10
+ @data = io.read(directory_entry.length)
15
11
  end
16
12
 
17
13
  end
@@ -4,24 +4,26 @@ require 'test_helper'
4
4
  require 'stringio'
5
5
  require 'hexapdf/font/true_type'
6
6
 
7
- module TestHelper
7
+ module HexaPDF
8
+ module TestUtils
8
9
 
9
- def set_up_stub_true_type_font(initial_data = ''.b, register_vars: true)
10
- font = Object.new
11
- font.define_singleton_method(:io) { @io ||= StringIO.new(initial_data) }
12
- font.define_singleton_method(:config) { @config ||= {} }
13
- entry = HexaPDF::Font::TrueType::Table::Directory::Entry.new('mock', 0, 0, initial_data.length)
14
- @font, @entry = font, entry if register_vars
15
- [font, entry]
16
- end
10
+ def set_up_stub_true_type_font(initial_data = ''.b, register_vars: true)
11
+ font = ::Object.new
12
+ font.define_singleton_method(:io) { @io ||= StringIO.new(initial_data) }
13
+ font.define_singleton_method(:config) { @config ||= {} }
14
+ entry = HexaPDF::Font::TrueType::Table::Directory::Entry.new('mock', 0, 0, initial_data.length)
15
+ @font, @entry = font, entry if register_vars
16
+ [font, entry]
17
+ end
17
18
 
18
- def create_table(name, data = nil, standalone: false)
19
- font, entry = standalone ? set_up_stub_true_type_font(register_vars: false) : [@font, @entry]
20
- if data
21
- font.io.string = data
22
- entry.length = font.io.length
19
+ def create_table(name, data = nil, standalone: false)
20
+ font, entry = standalone ? set_up_stub_true_type_font(register_vars: false) : [@font, @entry]
21
+ if data
22
+ font.io.string = data
23
+ entry.length = font.io.length
24
+ end
25
+ HexaPDF::Font::TrueType::Table.const_get(name).new(font, entry)
23
26
  end
24
- HexaPDF::Font::TrueType::Table.const_get(name).new(font, entry)
25
- end
26
27
 
28
+ end
27
29
  end
@@ -10,7 +10,7 @@ describe HexaPDF::Font::TrueType::Font do
10
10
  @io = StringIO.new("TEST\x00\x01\x00\x00\x00\x00\x00\x00" \
11
11
  "TEST----\x00\x00\x00\x1C\x00\x00\x00\x05ENTRY".b)
12
12
  @font = HexaPDF::Font::TrueType::Font.new(@io)
13
- @font.config['font.true_type.table_mapping'][:TEST] = TestHelper::TrueTypeTestTable.name
13
+ @font.config['font.true_type.table_mapping'][:TEST] = TrueTypeTestTable.name
14
14
  end
15
15
 
16
16
  describe "[]" do
@@ -15,7 +15,7 @@ describe HexaPDF::Font::TrueType::Table do
15
15
 
16
16
  describe "initialize" do
17
17
  it "reads the data from the associated file" do
18
- table = TestHelper::TrueTypeTestTable.new(@file, @entry)
18
+ table = TrueTypeTestTable.new(@file, @entry)
19
19
  assert_equal(@file.io.string, table.data)
20
20
  end
21
21
  end
@@ -25,7 +25,7 @@ describe HexaPDF::Font::TrueType::Table do
25
25
  @file.io.string = 254.chr * 17 + 0.chr * 3
26
26
  @entry.checksum = (0xfefefefe * 4 + 0xfe000000) % 2**32
27
27
  @entry.length = @file.io.string.length
28
- table = TestHelper::TrueTypeTestTable.new(@file, @entry)
28
+ table = TrueTypeTestTable.new(@file, @entry)
29
29
  assert(table.checksum_valid?)
30
30
  end
31
31
  end
@@ -34,14 +34,14 @@ describe HexaPDF::Font::TrueType::Table do
34
34
  it "works for unsigned values" do
35
35
  @file.io.string = [1, 20480].pack('nn')
36
36
  @entry.length = @file.io.string.length
37
- table = TestHelper::TrueTypeTestTable.new(@file, @entry)
37
+ table = TrueTypeTestTable.new(@file, @entry)
38
38
  assert_equal(1 + Rational(20480, 65536), table.send(:read_fixed))
39
39
  end
40
40
 
41
41
  it "works for signed values" do
42
42
  @file.io.string = [-1, 20480].pack('nn')
43
43
  @entry.length = @file.io.string.length
44
- table = TestHelper::TrueTypeTestTable.new(@file, @entry)
44
+ table = TrueTypeTestTable.new(@file, @entry)
45
45
  assert_equal(-1 + Rational(20480, 65536), table.send(:read_fixed))
46
46
  end
47
47
  end
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'test_helper'
4
- require_relative '../content/common'
5
4
  require 'hexapdf/document'
6
5
  require 'hexapdf/layout/box'
7
6
 
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'test_helper'
4
- require_relative '../content/common'
5
4
  require 'hexapdf/document'
6
5
  require 'hexapdf/layout/column_box'
7
6
 
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'test_helper'
4
- require_relative '../content/common'
5
4
  require 'hexapdf/document'
6
5
  require 'hexapdf/layout/image_box'
7
6
 
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'test_helper'
4
- require_relative '../content/common'
5
4
  require 'hexapdf/document'
6
5
  require 'hexapdf/layout/list_box'
7
6
 
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'test_helper'
4
- require_relative '../content/common'
5
4
  require 'hexapdf/document'
6
5
  require 'hexapdf/layout/style'
7
6
  require 'hexapdf/layout/text_layouter'
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'test_helper'
4
- require_relative '../content/common'
5
4
  require 'hexapdf/document'
6
5
  require 'hexapdf/layout/text_box'
7
6
 
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'test_helper'
4
- require_relative '../content/common'
5
4
  require 'hexapdf/document'
6
5
  require 'hexapdf/layout/text_fragment'
7
6
 
@@ -3,7 +3,6 @@
3
3
  require 'test_helper'
4
4
  require 'hexapdf/layout'
5
5
  require 'hexapdf/document'
6
- require_relative "../content/common"
7
6
 
8
7
  module TestTextLayouterHelpers
9
8
  def boxes(*dims)
@@ -707,7 +706,7 @@ describe HexaPDF::Layout::TextLayouter do
707
706
 
708
707
  describe "Result#draw" do
709
708
  def assert_positions(content, positions)
710
- processor = TestHelper::OperatorRecorder.new
709
+ processor = HexaPDF::TestUtils::OperatorRecorder.new
711
710
  HexaPDF::Content::Parser.new.parse(content, processor)
712
711
  result = processor.recorded_ops
713
712
  leading = (result.select {|name, _| name == :set_leading } || [0]).map(&:last).flatten.first
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'test_helper'
4
- require_relative 'content/common'
5
4
  require 'hexapdf/document'
6
5
  require 'hexapdf/composer'
7
6
  require 'stringio'
@@ -196,7 +196,7 @@ describe HexaPDF::Object do
196
196
  refute_equal(obj, 5)
197
197
  obj.data.oid = 0
198
198
  assert_equal(obj, 5)
199
- assert_equal(obj, HexaPDF::Object.new(5))
199
+ refute_equal(obj, HexaPDF::Object.new(5))
200
200
  end
201
201
 
202
202
  it "works correctly as hash key, is interchangable in this regard with Reference objects" do
@@ -86,19 +86,19 @@ describe HexaPDF::Parser do
86
86
  it "handles keyword stream followed only by CR without LF" do
87
87
  create_parser("1 0 obj<</Length 2>> stream\r12\nendstream endobj")
88
88
  *, stream = @parser.parse_indirect_object
89
- assert_equal('12', TestHelper.collector(stream.fiber))
89
+ assert_equal('12', collector(stream.fiber))
90
90
  end
91
91
 
92
92
  it "handles keyword stream followed by space and CR or LF" do
93
93
  create_parser("1 0 obj<</Length 2>> stream \n12\nendstream endobj")
94
94
  *, stream = @parser.parse_indirect_object
95
- assert_equal('12', TestHelper.collector(stream.fiber))
95
+ assert_equal('12', collector(stream.fiber))
96
96
  end
97
97
 
98
98
  it "handles keyword stream followed by space and CR LF" do
99
99
  create_parser("1 0 obj<</Length 2>> stream \r\n12\nendstream endobj")
100
100
  *, stream = @parser.parse_indirect_object
101
- assert_equal('12', TestHelper.collector(stream.fiber))
101
+ assert_equal('12', collector(stream.fiber))
102
102
  end
103
103
 
104
104
  it "handles invalid indirect object value consisting of number followed by endobj without space" do
@@ -117,7 +117,14 @@ describe HexaPDF::Parser do
117
117
  create_parser("1 0 obj<</Length 4>> stream\n12endstream endobj")
118
118
  obj, _, _, stream = @parser.parse_indirect_object
119
119
  assert_equal(2, obj[:Length])
120
- assert_equal('12', TestHelper.collector(stream.fiber))
120
+ assert_equal('12', collector(stream.fiber))
121
+ end
122
+
123
+ it "recovers from an incorrect stream length value which leads to a parsing error" do
124
+ create_parser("1 0 obj<</Length 2>> stream\n12(ab\nendstream endobj")
125
+ obj, _, _, stream = @parser.parse_indirect_object
126
+ assert_equal(5, obj[:Length])
127
+ assert_equal('12(ab', collector(stream.fiber))
121
128
  end
122
129
 
123
130
  it "recovers from an invalid stream length value" do
@@ -125,7 +132,7 @@ describe HexaPDF::Parser do
125
132
  @document.add([5], oid: 2)
126
133
  obj, _, _, stream = @parser.parse_indirect_object
127
134
  assert_equal(2, obj[:Length])
128
- assert_equal('12', TestHelper.collector(stream.fiber))
135
+ assert_equal('12', collector(stream.fiber))
129
136
  end
130
137
 
131
138
  it "works even if the keyword endobj is missing or mangled" do
@@ -72,8 +72,6 @@ describe HexaPDF::StreamData do
72
72
  end
73
73
 
74
74
  describe HexaPDF::Stream do
75
- include TestHelper
76
-
77
75
  before do
78
76
  @document = OpenStruct.new
79
77
  @document.config = HexaPDF::Configuration.with_defaults
@@ -40,7 +40,7 @@ describe HexaPDF::Writer do
40
40
  219
41
41
  %%EOF
42
42
  3 0 obj
43
- <</Producer(HexaPDF version 0.24.0)>>
43
+ <</Producer(HexaPDF version 0.24.1)>>
44
44
  endobj
45
45
  xref
46
46
  3 1
@@ -72,7 +72,7 @@ describe HexaPDF::Writer do
72
72
  141
73
73
  %%EOF
74
74
  6 0 obj
75
- <</Producer(HexaPDF version 0.24.0)>>
75
+ <</Producer(HexaPDF version 0.24.1)>>
76
76
  endobj
77
77
  2 0 obj
78
78
  <</Length 10>>stream
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'test_helper'
4
- require_relative '../../content/common'
5
4
  require 'hexapdf/document'
6
5
  require 'hexapdf/type/acro_form/appearance_generator'
7
6
 
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'test_helper'
4
- require_relative '../../content/common'
5
4
  require 'hexapdf/document'
6
5
  require 'hexapdf/type/acro_form/button_field'
7
6
 
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'test_helper'
4
- require_relative '../../content/common'
5
4
  require 'hexapdf/document'
6
5
  require 'hexapdf/type/acro_form/text_field'
7
6
 
@@ -1,71 +1,73 @@
1
1
  require 'openssl'
2
2
 
3
- module TestHelper
3
+ module HexaPDF
4
+ module TestUtils
4
5
 
5
- class Certificates
6
+ class Certificates
6
7
 
7
- def ca_key
8
- @ca_key ||= OpenSSL::PKey::RSA.new(512)
9
- end
8
+ def ca_key
9
+ @ca_key ||= OpenSSL::PKey::RSA.new(512)
10
+ end
10
11
 
11
- def ca_certificate
12
- @ca_certificate ||=
13
- begin
14
- ca_name = OpenSSL::X509::Name.parse('/C=AT/O=HexaPDF/CN=HexaPDF Test Root CA')
12
+ def ca_certificate
13
+ @ca_certificate ||=
14
+ begin
15
+ ca_name = OpenSSL::X509::Name.parse('/C=AT/O=HexaPDF/CN=HexaPDF Test Root CA')
15
16
 
16
- ca_cert = OpenSSL::X509::Certificate.new
17
- ca_cert.serial = 0
18
- ca_cert.version = 2
19
- ca_cert.not_before = Time.now - 86400
20
- ca_cert.not_after = Time.now + 86400
21
- ca_cert.public_key = ca_key.public_key
22
- ca_cert.subject = ca_name
23
- ca_cert.issuer = ca_name
17
+ ca_cert = OpenSSL::X509::Certificate.new
18
+ ca_cert.serial = 0
19
+ ca_cert.version = 2
20
+ ca_cert.not_before = Time.now - 86400
21
+ ca_cert.not_after = Time.now + 86400
22
+ ca_cert.public_key = ca_key.public_key
23
+ ca_cert.subject = ca_name
24
+ ca_cert.issuer = ca_name
24
25
 
25
- extension_factory = OpenSSL::X509::ExtensionFactory.new
26
- extension_factory.subject_certificate = ca_cert
27
- extension_factory.issuer_certificate = ca_cert
28
- ca_cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash'))
29
- ca_cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:TRUE', true))
30
- ca_cert.add_extension(extension_factory.create_extension('keyUsage', 'cRLSign,keyCertSign', true))
31
- ca_cert.sign(ca_key, OpenSSL::Digest.new('SHA1'))
26
+ extension_factory = OpenSSL::X509::ExtensionFactory.new
27
+ extension_factory.subject_certificate = ca_cert
28
+ extension_factory.issuer_certificate = ca_cert
29
+ ca_cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash'))
30
+ ca_cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:TRUE', true))
31
+ ca_cert.add_extension(extension_factory.create_extension('keyUsage', 'cRLSign,keyCertSign', true))
32
+ ca_cert.sign(ca_key, OpenSSL::Digest.new('SHA1'))
32
33
 
33
- ca_cert
34
- end
35
- end
34
+ ca_cert
35
+ end
36
+ end
36
37
 
37
- def signer_key
38
- @signer_key ||= OpenSSL::PKey::RSA.new(512)
39
- end
38
+ def signer_key
39
+ @signer_key ||= OpenSSL::PKey::RSA.new(512)
40
+ end
40
41
 
41
- def signer_certificate
42
- @signer_certificate ||=
43
- begin
44
- name = OpenSSL::X509::Name.parse('/CN=signer/DC=gettalong')
42
+ def signer_certificate
43
+ @signer_certificate ||=
44
+ begin
45
+ name = OpenSSL::X509::Name.parse('/CN=signer/DC=gettalong')
45
46
 
46
- signer_cert = OpenSSL::X509::Certificate.new
47
- signer_cert.serial = 2
48
- signer_cert.version = 2
49
- signer_cert.not_before = Time.now - 86400
50
- signer_cert.not_after = Time.now + 86400
51
- signer_cert.public_key = signer_key.public_key
52
- signer_cert.subject = name
53
- signer_cert.issuer = ca_certificate.subject
47
+ signer_cert = OpenSSL::X509::Certificate.new
48
+ signer_cert.serial = 2
49
+ signer_cert.version = 2
50
+ signer_cert.not_before = Time.now - 86400
51
+ signer_cert.not_after = Time.now + 86400
52
+ signer_cert.public_key = signer_key.public_key
53
+ signer_cert.subject = name
54
+ signer_cert.issuer = ca_certificate.subject
54
55
 
55
- extension_factory = OpenSSL::X509::ExtensionFactory.new
56
- extension_factory.subject_certificate = signer_cert
57
- extension_factory.issuer_certificate = ca_certificate
58
- signer_cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash'))
59
- signer_cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:FALSE'))
60
- signer_cert.add_extension(extension_factory.create_extension('keyUsage', 'digitalSignature'))
61
- signer_cert.sign(ca_key, OpenSSL::Digest.new('SHA1'))
56
+ extension_factory = OpenSSL::X509::ExtensionFactory.new
57
+ extension_factory.subject_certificate = signer_cert
58
+ extension_factory.issuer_certificate = ca_certificate
59
+ signer_cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash'))
60
+ signer_cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:FALSE'))
61
+ signer_cert.add_extension(extension_factory.create_extension('keyUsage', 'digitalSignature'))
62
+ signer_cert.sign(ca_key, OpenSSL::Digest.new('SHA1'))
63
+
64
+ signer_cert
65
+ end
66
+ end
62
67
 
63
- signer_cert
64
- end
65
68
  end
66
69
 
67
70
  end
68
-
69
71
  end
70
72
 
71
- CERTIFICATES = TestHelper::Certificates.new
73
+ CERTIFICATES = HexaPDF::TestUtils::Certificates.new
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'test_helper'
4
- require_relative '../content/common'
5
4
  require 'hexapdf/document'
6
5
  require 'hexapdf/type/form'
7
6
 
@@ -70,7 +69,7 @@ describe HexaPDF::Type::Form do
70
69
  describe "process_contents" do
71
70
  it "parses the contents and processes it" do
72
71
  @form.stream = '10 w'
73
- processor = TestHelper::OperatorRecorder.new
72
+ processor = HexaPDF::TestUtils::OperatorRecorder.new
74
73
  @form.process_contents(processor)
75
74
  assert_equal([[:set_line_width, [10]]], processor.recorded_ops)
76
75
  assert_nil(@form[:Resources])
@@ -82,7 +81,7 @@ describe HexaPDF::Type::Form do
82
81
 
83
82
  it "uses the provided resources if it has no resources itself" do
84
83
  resources = @doc.wrap({}, type: :XXResources)
85
- processor = TestHelper::OperatorRecorder.new
84
+ processor = HexaPDF::TestUtils::OperatorRecorder.new
86
85
  @form.process_contents(processor, original_resources: resources)
87
86
  assert_same(resources, processor.resources)
88
87
  end
@@ -91,7 +90,7 @@ describe HexaPDF::Type::Form do
91
90
  describe "canvas" do
92
91
  # Asserts that the form's contents contains the operators.
93
92
  def assert_operators(form, operators)
94
- processor = TestHelper::OperatorRecorder.new
93
+ processor = HexaPDF::TestUtils::OperatorRecorder.new
95
94
  form.process_contents(processor)
96
95
  assert_equal(operators, processor.recorded_ops)
97
96
  end
@@ -1,7 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'test_helper'
4
- require_relative '../content/common'
5
4
  require 'stringio'
6
5
  require 'hexapdf/document'
7
6
  require 'hexapdf/type/page'
@@ -27,7 +26,7 @@ describe HexaPDF::Type::Page do
27
26
 
28
27
  # Asserts that the page's contents contains the operators.
29
28
  def assert_page_operators(page, operators)
30
- processor = TestHelper::OperatorRecorder.new
29
+ processor = HexaPDF::TestUtils::OperatorRecorder.new
31
30
  page.process_contents(processor)
32
31
  assert_equal(operators, processor.recorded_ops)
33
32
  end
data/test/test_helper.rb CHANGED
@@ -14,6 +14,7 @@ gem 'minitest'
14
14
  require 'minitest/autorun'
15
15
  require 'fiber'
16
16
  require 'zlib'
17
+ require 'hexapdf/test_utils'
17
18
 
18
19
  TEST_DATA_DIR = File.join(__dir__, 'data')
19
20
  MINIMAL_PDF = File.binread(File.join(TEST_DATA_DIR, 'minimal.pdf')).freeze
@@ -21,42 +22,3 @@ MINIMAL_PDF = File.binread(File.join(TEST_DATA_DIR, 'minimal.pdf')).freeze
21
22
  Minitest::Test.make_my_diffs_pretty!
22
23
 
23
24
  ENV['TZ'] = 'UTC'
24
-
25
- module TestHelper
26
-
27
- # Asserts that the method +name+ of +object+ gets invoked with the +expected_values+ when
28
- # executing the block. +expected_values+ should contain arrays of arguments, one array for each
29
- # invocation of the method.
30
- def assert_method_invoked(object, name, *expected_values, check_block: false)
31
- args = []
32
- block = []
33
- object.define_singleton_method(name) {|*la, &lb| args << la; block << lb }
34
- yield
35
- assert_equal(expected_values, args, "Incorrect arguments for #{object.class}##{name}")
36
- block.each do |block_arg|
37
- assert_kind_of(Proc, block_arg, "Missing block for #{object.class}##{name}") if check_block
38
- end
39
- ensure
40
- object.singleton_class.send(:remove_method, name)
41
- end
42
-
43
- module_function
44
-
45
- def feeder(string, len = string.length)
46
- Fiber.new do
47
- until string.empty?
48
- Fiber.yield(string.slice!(0, len).force_encoding('BINARY'))
49
- end
50
- end
51
- end
52
-
53
- def collector(source)
54
- str = ''.force_encoding('BINARY')
55
- while source.alive? && (data = source.resume)
56
- str << data
57
- end
58
- str
59
- end
60
- end
61
-
62
- Minitest::Spec.include(TestHelper)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hexapdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.24.0
4
+ version: 0.24.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Leitner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-01 00:00:00.000000000 Z
11
+ date: 2022-08-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cmdparse
@@ -379,6 +379,7 @@ files:
379
379
  - lib/hexapdf/task.rb
380
380
  - lib/hexapdf/task/dereference.rb
381
381
  - lib/hexapdf/task/optimize.rb
382
+ - lib/hexapdf/test_utils.rb
382
383
  - lib/hexapdf/tokenizer.rb
383
384
  - lib/hexapdf/type.rb
384
385
  - lib/hexapdf/type/acro_form.rb
@@ -513,7 +514,6 @@ files:
513
514
  - test/data/standard-security-handler/userpwd-arc4-128bit-V4.pdf
514
515
  - test/data/standard-security-handler/userpwd-arc4-40bit-V1.pdf
515
516
  - test/hexapdf/common_tokenizer_tests.rb
516
- - test/hexapdf/content/common.rb
517
517
  - test/hexapdf/content/graphic_object/test_arc.rb
518
518
  - test/hexapdf/content/graphic_object/test_endpoint_arc.rb
519
519
  - test/hexapdf/content/graphic_object/test_geom2d.rb
@@ -698,8 +698,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
698
698
  - !ruby/object:Gem::Version
699
699
  version: '0'
700
700
  requirements: []
701
- rubyforge_project:
702
- rubygems_version: 2.7.6.2
701
+ rubygems_version: 3.2.32
703
702
  signing_key:
704
703
  specification_version: 4
705
704
  summary: HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
@@ -1,39 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
-
3
- require 'test_helper'
4
- require 'hexapdf/content/processor'
5
-
6
- module TestHelper
7
-
8
- # Can be used to to record operators parsed from content streams.
9
- class OperatorRecorder < HexaPDF::Content::Processor
10
-
11
- undef :paint_xobject
12
-
13
- attr_reader :recorded_ops
14
-
15
- def initialize
16
- super
17
- operators.clear
18
- @recorded_ops = []
19
- end
20
-
21
- def respond_to_missing?(*)
22
- true
23
- end
24
-
25
- def method_missing(msg, *params)
26
- @recorded_ops << (params.empty? ? [msg] : [msg, params])
27
- end
28
-
29
- end
30
-
31
- # Asserts that the content string contains the operators.
32
- def assert_operators(content, operators, only_names: false, range: 0..-1)
33
- processor = TestHelper::OperatorRecorder.new
34
- HexaPDF::Content::Parser.new.parse(content, processor)
35
- result = processor.recorded_ops[range]
36
- result.map!(&:first) if only_names
37
- assert_equal(operators, result)
38
- end
39
- end