# -*- encoding: utf-8 -*-
require 'test_helper'
require 'stringio'
require 'hexapdf/document'
describe HexaPDF::Document::Metadata do
before do
@doc = HexaPDF::Document.new
@doc.trailer.info[:Title] = 'Title'
@metadata = @doc.metadata
end
it "parses the info dictionary on creation" do
assert_equal('Title', @metadata.title)
@doc.trailer.info[:Trapped] = :Unknown
assert_nil(HexaPDF::Document::Metadata.new(@doc).trapped)
@doc.trailer.info[:Trapped] = :True
assert_equal(true, HexaPDF::Document::Metadata.new(@doc).trapped)
@doc.trailer.info[:Trapped] = :False
assert_equal(false, HexaPDF::Document::Metadata.new(@doc).trapped)
end
describe "default_language" do
it "use the document's language as default" do
@doc.catalog[:Lang] = 'de'
assert_equal("de", HexaPDF::Document::Metadata.new(@doc).default_language)
end
it "falls back to the default language if the document doesn't have a default language set" do
assert_equal('x-default', @metadata.default_language)
end
it "allows changing the default language" do
@metadata.default_language('de')
assert_equal('de', @metadata.default_language)
end
end
it "enables writing the info dict by default" do
assert(@metadata.write_info_dict?)
end
it "allows setting whether the info dict is written" do
@metadata.write_info_dict(false)
refute(@metadata.write_info_dict?)
end
it "enables writing the metadata stream by default" do
assert(@metadata.write_metadata_stream?)
end
it "allows setting whether the metadata stream is written" do
@metadata.write_metadata_stream(false)
refute(@metadata.write_metadata_stream?)
end
it "resolves namespace URI via a prefix" do
assert_equal('http://www.w3.org/1999/02/22-rdf-syntax-ns#', @metadata.namespace('rdf'))
end
it "allows registering prefixes for namespaces" do
err = assert_raises(HexaPDF::Error) { @metadata.namespace('hexa') }
assert_match(/prefix.*hexa.*not registered/, err.message)
@metadata.register_namespace('hexa', 'hexa:')
assert_equal('hexa:', @metadata.namespace('hexa'))
end
it "allows registering property types" do
@metadata.register_property_type('dc', 'title', 'Boolean')
assert_equal('Boolean', @metadata.instance_variable_get(:@properties)[@metadata.namespace('dc')]['title'])
end
it "allows reading and setting properties" do
assert_equal('Title', @metadata.property('dc', 'title'))
@metadata.property('dc', 'title', 'another')
assert_equal('another', @metadata.property('dc', 'title'))
@metadata.property('dc', 'title', nil)
assert_nil(@metadata.property('dc', 'title'))
refute(@metadata.instance_variable_get(:@metadata)[@metadata.namespace('dc')].key?('title'))
end
describe "delete" do
it "deletes all properties" do
@metadata.delete
assert(@metadata.instance_variable_get(:@metadata).empty?)
end
it "deletes all properties of a single namespace" do
@metadata.creator('Test')
@metadata.delete('dc')
assert_equal('Test', @metadata.creator)
refute(@metadata.instance_variable_get(:@metadata).key?(@metadata.namespace('dc')))
end
it "deletes a specific property" do
@metadata.delete('dc', 'title')
assert_nil(@metadata.title)
end
end
it "allows reading and setting all info dictionary properties" do
[['title', 'dc', 'title'], ['author', 'dc', 'creator'], ['subject', 'dc', 'description'],
['keywords', 'pdf', 'Keywords'], ['creator', 'xmp', 'CreatorTool'],
['producer', 'pdf', 'Producer'], ['creation_date', 'xmp', 'CreateDate'],
['modification_date', 'xmp', 'ModifyDate'], ['trapped', 'pdf', 'Trapped']].each do |name, ns, property|
@metadata.property(ns, property, 'value')
assert_equal('value', @metadata.send(name), name)
@metadata.send(name, 'modified')
assert_equal('modified', @metadata.property(ns, property), name)
end
end
describe "metadata writing" do
before do
@time = Time.now.floor
@metadata.title('Title')
@metadata.author('Author')
@metadata.subject('Subject')
@metadata.keywords('Keywords')
@metadata.creator('Creator')
@metadata.producer('Producer')
@metadata.creation_date(@time)
@metadata.modification_date(@time)
@metadata.trapped(true)
end
it "writes the info dictionary properties" do
info = @doc.trailer.info
@doc.write(StringIO.new, update_fields: false)
assert_equal('Title', info[:Title])
assert_equal('Author', info[:Author])
assert_equal('Subject', info[:Subject])
assert_equal('Keywords', info[:Keywords])
assert_equal('Creator', info[:Creator])
assert_match(/HexaPDF/, info[:Producer])
assert_same(@time, info[:CreationDate])
assert_same(@time, info[:ModDate])
assert_equal(:True, info[:Trapped])
end
it "omits values in the info dictionary that are not set" do
@metadata.delete('pdf', 'Trapped')
@metadata.delete('dc', 'title')
@metadata.delete('dc', 'creator')
@doc.write(StringIO.new, update_fields: false)
info = @doc.trailer.info
refute(info.key?(:Title))
refute(info.key?(:Author))
refute(info.key?(:Trapped))
end
it "uses a correctly updated modification date if set so by Document#write" do
info = @doc.trailer.info
sleep(0.1)
@doc.write(StringIO.new)
assert_same(@time, info[:CreationDate])
refute_same(@time, info[:ModDate])
assert(@time < info[:ModDate])
end
it "correctly handles array values for title, author, and subject for info dictionary" do
@metadata.title(['Title', 'Another'])
@metadata.author(['Author', 'Author2'])
@metadata.subject(['Subject', 'Another'])
@doc.write(StringIO.new)
info = @doc.trailer.info
assert_equal('Title', info[:Title])
assert_equal('Author, Author2', info[:Author])
assert_equal('Subject', info[:Subject])
end
it "omits rdf:Description elements without values" do
@metadata.delete
@doc.write(StringIO.new, update_fields: false)
metadata = <<~XMP
HexaPDF version #{HexaPDF::VERSION}
XMP
assert_equal(metadata, @doc.catalog[:Metadata].stream.sub(/(?<=id=")\w+/, ''))
end
it "writes the custom metadata" do
@metadata.delete
@metadata.custom_metadata("Test")
@metadata.custom_metadata("Test2")
@doc.write(StringIO.new, update_fields: false)
metadata = <<~XMP
HexaPDF version #{HexaPDF::VERSION}
Test
Test2
XMP
assert_equal(metadata, @doc.catalog[:Metadata].stream.sub(/(?<=id=")\w+/, ''))
end
it "writes the XMP metadata" do
title = HexaPDF::Document::Metadata::LocalizedString.new('Der Titel')
title.language = 'de'
@metadata.title(['Title', title])
@metadata.author(['Author 1', 'Author 2'])
@metadata.register_property_type('dc', 'other', 'URI')
@metadata.property('dc', 'other', 'https://test.org/example')
@metadata.property('pdfaid', 'part', 3)
@metadata.property('pdfaid', 'conformance', 'b')
@doc.write(StringIO.new, update_fields: false)
metadata = <<~XMP
Title
Der Titel
Author 1
Author 2
Subject
Keywords
HexaPDF version #{HexaPDF::VERSION}
True
Creator
#{@metadata.send(:xmp_date, @time)}
#{@metadata.send(:xmp_date, @time)}
3
b
XMP
assert_equal(metadata, @doc.catalog[:Metadata].stream.sub(/(?<=id=")\w+/, ''))
end
it "respects the write settings for info dictionary and metadata stream" do
@metadata.write_info_dict(false)
@metadata.write_metadata_stream(false)
@doc.write(StringIO.new)
assert_nil(@doc.trailer.info[:Author])
refute(@doc.catalog.key?(:Metadata))
end
end
end