1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe PDF::Core::NameTree do
def tree_dump(tree)
if tree.is_a?(PDF::Core::NameTree::Node)
"[#{tree.children.map { |child| tree_dump(child) }.join(',')}]"
else
"#{tree.name}=#{tree.value}"
end
end
def tree_add(tree, *args)
args.each do |(name, value)|
tree.add(name, value)
end
end
def tree_value(name, value)
PDF::Core::NameTree::Value.new(name, value)
end
let(:pdf) do
document_class =
Class.new do
def initialize
@object_store = []
end
attr_reader :object_store
def ref!(obj)
@object_store << obj
end
end
document_class.new
end
it 'has no children when first initialized' do
node = PDF::Core::NameTree::Node.new(pdf, 3)
expect(node.children.length).to eq 0
end
it 'has no subtrees while child limit is not reached' do
node = PDF::Core::NameTree::Node.new(pdf, 3)
tree_add(node, ['one', 1], ['two', 2], ['three', 3])
expect(tree_dump(node)).to eq '[one=1,three=3,two=2]'
end
it 'splits into subtrees when limit is exceeded' do
node = PDF::Core::NameTree::Node.new(pdf, 3)
tree_add(node, ['one', 1], ['two', 2], ['three', 3], ['four', 4])
expect(tree_dump(node)).to eq '[[four=4,one=1],[three=3,two=2]]'
end
it 'creates a two new references when root is split' do
ref_count = pdf.object_store.length
node = PDF::Core::NameTree::Node.new(pdf, 3)
tree_add(node, ['one', 1], ['two', 2], ['three', 3], ['four', 4])
expect(pdf.object_store.length).to eq ref_count + 2
end
it 'creates a one new reference when subtree is split' do
node = PDF::Core::NameTree::Node.new(pdf, 3)
tree_add(node, ['one', 1], ['two', 2], ['three', 3], ['four', 4])
ref_count = pdf.object_store.length # save when root is split
tree_add(node, ['five', 5], ['six', 6], ['seven', 7])
expect(tree_dump(node)).to eq(
'[[five=5,four=4,one=1],[seven=7,six=6],[three=3,two=2]]'
)
expect(pdf.object_store.length).to eq ref_count + 1
end
it 'keeps tree balanced when subtree split cascades to root' do
node = PDF::Core::NameTree::Node.new(pdf, 3)
tree_add(node, ['one', 1], ['two', 2], ['three', 3], ['four', 4])
tree_add(node, ['five', 5], ['six', 6], ['seven', 7], ['eight', 8])
expect(tree_dump(node)).to eq(
'[[[eight=8,five=5],[four=4,one=1]],[[seven=7,six=6],[three=3,two=2]]]'
)
end
it 'maintains order of already properly ordered nodes' do
node = PDF::Core::NameTree::Node.new(pdf, 3)
tree_add(node, ['eight', 8], ['five', 5], ['four', 4], ['one', 1])
tree_add(node, ['seven', 7], ['six', 6], ['three', 3], ['two', 2])
expect(tree_dump(node)).to eq(
'[[[eight=8,five=5],[four=4,one=1]],[[seven=7,six=6],[three=3,two=2]]]'
)
end
it 'emits only :Names key with to_hash if root is only node' do
node = PDF::Core::NameTree::Node.new(pdf, 3)
tree_add(node, ['one', 1], ['two', 2], ['three', 3])
expect(node.to_hash).to eq(
Names: [
tree_value('one', 1), tree_value('three', 3), tree_value('two', 2)
]
)
end
it 'emits only :Kids key with to_hash if root has children' do
node = PDF::Core::NameTree::Node.new(pdf, 3)
tree_add(node, ['one', 1], ['two', 2], ['three', 3], ['four', 4])
expect(node.to_hash).to eq Kids: node.children.map(&:ref)
end
it 'emits :Limits and :Names keys with to_hash for leaf node' do
node = PDF::Core::NameTree::Node.new(pdf, 3)
tree_add(node, ['one', 1], ['two', 2], ['three', 3], ['four', 4])
expect(node.children.first.to_hash).to eq(
Limits: %w[four one],
Names: [tree_value('four', 4), tree_value('one', 1)]
)
end
it 'emits :Limits and :Kids keys with to_hash for inner node' do
node = PDF::Core::NameTree::Node.new(pdf, 3)
tree_add(node, ['one', 1], ['two', 2], ['three', 3], ['four', 4])
tree_add(node, ['five', 5], ['six', 6], ['seven', 7], ['eight', 8])
tree_add(node, ['nine', 9], ['ten', 10], ['eleven', 11], ['twelve', 12])
tree_add(
node, ['thirteen', 13], ['fourteen', 14], ['fifteen', 15], ['sixteen', 16]
)
expect(node.children.first.to_hash).to eq(
Limits: %w[eight one],
Kids: node.children.first.children.map(&:ref)
)
end
end
|