Skip to content

Commit

Permalink
Extract Document::SerializeObject to test it
Browse files Browse the repository at this point in the history
  • Loading branch information
tomascco committed Oct 20, 2023
1 parent bd77428 commit 769d4b5
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 41 deletions.
1 change: 1 addition & 0 deletions lib/rubrik.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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"
44 changes: 3 additions & 41 deletions lib/rubrik/document/increment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -53,53 +54,14 @@ 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"
end

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
Expand Down
53 changes: 53 additions & 0 deletions lib/rubrik/document/serialize_object.rb
Original file line number Diff line number Diff line change
@@ -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
110 changes: 110 additions & 0 deletions test/rubrik/document/serialize_object_test.rb
Original file line number Diff line number Diff line change
@@ -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("<</Test <</Key /Value /Array []>>>>", 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 <</Key /Value>>]]", 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)
<</Length 31>>
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

0 comments on commit 769d4b5

Please sign in to comment.