From 769d4b52e7b4fa9753d7edc36234153681e59482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Co=C3=AAlho?= Date: Fri, 20 Oct 2023 19:32:38 +0000 Subject: [PATCH] Extract `Document::SerializeObject` to test it --- lib/rubrik.rb | 1 + lib/rubrik/document/increment.rb | 44 +------ lib/rubrik/document/serialize_object.rb | 53 +++++++++ test/rubrik/document/serialize_object_test.rb | 110 ++++++++++++++++++ 4 files changed, 167 insertions(+), 41 deletions(-) create mode 100644 lib/rubrik/document/serialize_object.rb create mode 100644 test/rubrik/document/serialize_object_test.rb diff --git a/lib/rubrik.rb b/lib/rubrik.rb index cf4a487..08105d1 100644 --- a/lib/rubrik.rb +++ b/lib/rubrik.rb @@ -10,5 +10,6 @@ class Error < StandardError; end require_relative "rubrik/document" require_relative "rubrik/document/increment" +require_relative "rubrik/document/serialize_object" require_relative "rubrik/fill_signature" require_relative "rubrik/sign" diff --git a/lib/rubrik/document/increment.rb b/lib/rubrik/document/increment.rb index b9783f3..831e865 100644 --- a/lib/rubrik/document/increment.rb +++ b/lib/rubrik/document/increment.rb @@ -23,7 +23,8 @@ def call(document, io:) integer_id = T.let(object[:id].to_i, Integer) new_xref << {id: integer_id, offset: io.pos} - io << "#{integer_id} 0 obj\n" "#{serialize(object[:value])}\n" "endobj\n\n" + value = object[:value] + io << "#{integer_id} 0 obj\n" "#{SerializeObject[value]}\n" "endobj\n\n" end updated_trailer = document.objects.trailer.dup @@ -53,7 +54,7 @@ def call(document, io:) end io << "trailer\n" - io << "#{serialize(updated_trailer)}\n" + io << "#{SerializeObject[updated_trailer]}\n" io << "startxref\n" io << "#{new_xref_pos.to_s}\n" io << "%%EOF\n" @@ -61,45 +62,6 @@ def call(document, io:) private - sig {params(obj: T.untyped).returns(String)} - def serialize(obj) - case obj - when Hash - serialized_objs = obj.flatten.map { |e| serialize(e) } - "<<#{serialized_objs.join(" ")}>>" - when Symbol - "/#{obj}" - when Array - serialized_objs = obj.map { |e| serialize(e) } - "[#{serialized_objs.join(" ")}]" - when PDF::Reader::Reference - "#{obj.id} #{obj.gen} R" - when String - "(#{obj})" - when TrueClass - "true" - when FalseClass - "false" - when Document::CONTENTS_PLACEHOLDER - "<#{"0" * Document::SIGNATURE_SIZE}>" - when Document::BYTE_RANGE_PLACEHOLDER - "[0 0000000000 0000000000 0000000000]" - when Numeric - obj.to_s - when NilClass - "null" - when PDF::Reader::Stream - <<~OBJECT.chomp - #{serialize(obj.hash)} - stream - #{obj.data} - endstream - OBJECT - else - raise NotImplementedError.new("Don't know how to serialize #{obj}") - end - end - sig {params(document: Rubrik::Document).returns(Integer)} def last_xref_pos(document) PDF::Reader::Buffer.new(document.io, seek: 0).find_first_xref_offset diff --git a/lib/rubrik/document/serialize_object.rb b/lib/rubrik/document/serialize_object.rb new file mode 100644 index 0000000..2219e9c --- /dev/null +++ b/lib/rubrik/document/serialize_object.rb @@ -0,0 +1,53 @@ +# typed: true +# frozen_string_literal: true + +module Rubrik + class Document + module SerializeObject + include Kernel + extend T::Sig + extend self + + sig {params(obj: T.untyped).returns(String)} + def [](obj) + case obj + when Hash + serialized_objs = obj.flatten.map { |e| SerializeObject[e] } + "<<#{serialized_objs.join(" ")}>>" + when Symbol + "/#{obj}" + when Array + serialized_objs = obj.map { |e| SerializeObject[e] } + "[#{serialized_objs.join(" ")}]" + when PDF::Reader::Reference + "#{obj.id} #{obj.gen} R" + when String + "(#{obj})" + when TrueClass + "true" + when FalseClass + "false" + when Document::CONTENTS_PLACEHOLDER + "<#{"0" * Document::SIGNATURE_SIZE}>" + when Document::BYTE_RANGE_PLACEHOLDER + "[0 0000000000 0000000000 0000000000]" + when Float, Integer + obj.to_s + when NilClass + "null" + when PDF::Reader::Stream + <<~OBJECT.chomp + #{SerializeObject[obj.hash]} + stream + #{obj.data} + endstream + OBJECT + else + raise "Don't know how to serialize #{obj}" + end + end + + alias call [] + end + end +end diff --git a/test/rubrik/document/serialize_object_test.rb b/test/rubrik/document/serialize_object_test.rb new file mode 100644 index 0000000..92f9de9 --- /dev/null +++ b/test/rubrik/document/serialize_object_test.rb @@ -0,0 +1,110 @@ +# frozen_string_literal: true +# typed: true + +require "test_helper" + +class Rubrik::Document + class SerializeObjectTest < Rubrik::Test + def test_hash_serialization + # Arrange + hash = {Test: {Key: :Value, Array: []}} + + # Act + result = SerializeObject[hash] + + # Assert + assert_equal("<>>>", result) + end + + def test_symbol_serialization + # Act + result = SerializeObject[:Test] + + # Assert + assert_equal("/Test", result) + end + + def test_array_serialization + # Arrange + array = [0, [PDF::Reader::Reference.new(1, 0), {Key: :Value}]] + + # Act + result = SerializeObject[array] + + # Assert + assert_equal("[0 [1 0 R <>]]", result) + end + + def test_reference_serialization + # Act + result = SerializeObject[PDF::Reader::Reference.new(2, 1)] + + # Assert + assert_equal("2 1 R", result) + end + + def test_string_serialization + # Act + result = SerializeObject["Test"] + + # Assert + assert_equal("(Test)", result) + end + + def test_booleans_serialization + # Assert + assert_equal("true", SerializeObject[true]) + assert_equal("false", SerializeObject[false]) + end + + def test_contents_placeholder_serialization + # Assert + expected_result = "<#{"0" * 8_192}>" + assert_equal(expected_result, SerializeObject[CONTENTS_PLACEHOLDER]) + end + + def test_byte_range_placeholder_serialization + # Assert + assert_equal("[0 0000000000 0000000000 0000000000]", SerializeObject[BYTE_RANGE_PLACEHOLDER]) + end + + def test_numeric_serialization + # Assert + [ + ["30", SerializeObject.call(30)], + ["-30", SerializeObject.call(-30)], + ["-1.5", SerializeObject.call(-1.5)], + ["3.3", SerializeObject.call(3.3)] + ].each { |expectation| assert_equal(*expectation) } + end + + def test_nil_serialization + # Assert + assert_equal("null", SerializeObject[nil]) + end + + def test_stream_serialization + # Arrange + data = "Test Text\nTest x\x9C\xBDX[o\u00147\u0014\xB6\xB4HH\xF3\u0002)" + stream = PDF::Reader::Stream.new({Length: data.bytesize}, data) + + # Act + result = SerializeObject[stream] + + # Assert + assert_equal(<<~STREAM.chomp, result) + <> + stream + #{data} + endstream + STREAM + end + + def test_raise_on_unknown_object_serialization + # Assert + assert_raises(RuntimeError, "Don't know how to serialize Object") do + SerializeObject[Object.new] + end + end + end +end