hexapdf 0.24.0 → 0.24.1

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 (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