diaspora_federation/spec/lib/diaspora_federation/entity_spec.rb
Benjamin Neff 653b0fe276 instantiate nested entities if they are provided as hash
also add debug logging to entity constructor
2016-05-30 03:23:57 +02:00

309 lines
10 KiB
Ruby

module DiasporaFederation
describe Entity do
let(:data) { {test1: "asdf", test2: 1234, test3: false, test4: false} }
it "should extend Entity" do
expect(Entities::TestDefaultEntity).to be < Entity
end
context "creation" do
it "freezes the instance after initialization" do
entity = Entities::TestDefaultEntity.new(data)
expect(entity).to be_frozen
end
it "checks for required properties" do
expect {
Entities::TestDefaultEntity.new({})
}.to raise_error ArgumentError, "missing required properties: test1, test2"
end
context "defaults" do
it "sets the defaults" do
entity = Entities::TestDefaultEntity.new(test1: "1", test2: "2")
expect(entity.test3).to be_truthy
end
it "handles callable defaults" do
entity = Entities::TestDefaultEntity.new(test1: "1", test2: "2")
expect(entity.test4).to be_truthy
end
it "uses provided values over defaults" do
entity = Entities::TestDefaultEntity.new(data)
expect(entity.test3).to be_falsey
expect(entity.test4).to be_falsey
end
end
it "sets nil if string is empty" do
data[:test1] = ""
entity = Entities::TestDefaultEntity.new(data)
expect(entity.test1).to be_nil
end
context "validation" do
let(:invalid_data) { {test1: "as;df", test2: nil, test3: "no boolean"} }
it "validates the entity and raise an error with failed properties if not valid" do
expect {
Entities::TestDefaultEntity.new(invalid_data)
}.to raise_error Entity::ValidationError, /Failed validation for properties:.*test1.*\|.*test2.*\|.*test3/
end
it "contains the failed rule" do
expect {
Entities::TestDefaultEntity.new(invalid_data)
}.to raise_error Entity::ValidationError, /property: test2, value: nil, rule: not_nil, with params: \{\}/
end
it "contains the params of the failed rule" do
expect {
Entities::TestDefaultEntity.new(invalid_data)
}.to raise_error Entity::ValidationError, /rule: regular_expression, with params: \{:regex=>.*\}/
end
end
end
describe "#to_h" do
it "returns a hash of the internal data" do
entity = Entities::TestDefaultEntity.new(data)
expect(entity.to_h).to eq(data)
end
end
describe "#to_xml" do
it "returns an Nokogiri::XML::Element" do
entity = Entities::TestDefaultEntity.new(data)
expect(entity.to_xml).to be_an_instance_of Nokogiri::XML::Element
end
it "has the root node named after the class (underscored)" do
entity = Entities::TestDefaultEntity.new(data)
expect(entity.to_xml.name).to eq("test_default_entity")
end
it "contains nodes for each of the properties" do
entity = Entities::TestDefaultEntity.new(data)
xml_children = entity.to_xml.children
expect(xml_children).to have_exactly(4).items
xml_children.each do |node|
expect(%w(test1 test2 test3 test4)).to include(node.name)
end
end
end
describe ".from_xml" do
let(:entity) { Entities::TestEntity.new(test: "asdf") }
let(:entity_xml) { entity.to_xml }
context "sanity" do
it "expects an Nokogiri::XML::Element as param" do
expect {
Entities::TestEntity.from_xml(entity_xml)
}.not_to raise_error
end
it "raises and error when the param is not an Nokogiri::XML::Element" do
["asdf", 1234, true, :test, entity].each do |val|
expect {
Entity.from_xml(val)
}.to raise_error ArgumentError, "only Nokogiri::XML::Element allowed"
end
end
it "raises an error when the entity class doesn't match the root node" do
xml = <<-XML
<unknown_entity>
<test>asdf</test>
</unknown_entity>
XML
expect {
Entity.from_xml(Nokogiri::XML::Document.parse(xml).root)
}.to raise_error Entity::InvalidRootNode, "'unknown_entity' can't be parsed by DiasporaFederation::Entity"
end
end
context "returned object" do
subject { Entities::TestEntity.from_xml(entity_xml) }
it "#to_h should match entity.to_h" do
expect(subject.to_h).to eq(entity.to_h)
end
it "returns an entity instance of the original class" do
expect(subject).to be_an_instance_of Entities::TestEntity
expect(subject.test).to eq("asdf")
end
end
context "parsing" do
it "uses xml_name for parsing" do
xml = <<-XML.strip
<test_entity_with_xml_name>
<test>asdf</test>
<asdf>qwer</asdf>
</test_entity_with_xml_name>
XML
entity = Entities::TestEntityWithXmlName.from_xml(Nokogiri::XML::Document.parse(xml).root)
expect(entity).to be_an_instance_of Entities::TestEntityWithXmlName
expect(entity.test).to eq("asdf")
expect(entity.qwer).to eq("qwer")
end
it "allows name for parsing even when property has a xml_name" do
xml = <<-XML.strip
<test_entity_with_xml_name>
<test>asdf</test>
<qwer>qwer</qwer>
</test_entity_with_xml_name>
XML
entity = Entities::TestEntityWithXmlName.from_xml(Nokogiri::XML::Document.parse(xml).root)
expect(entity).to be_an_instance_of Entities::TestEntityWithXmlName
expect(entity.test).to eq("asdf")
expect(entity.qwer).to eq("qwer")
end
end
context "nested entities" do
let(:child_entity1) { Entities::TestEntity.new(test: "bla") }
let(:child_entity2) { Entities::OtherEntity.new(asdf: "blabla") }
let(:nested_entity) {
Entities::TestNestedEntity.new(asdf: "QWERT",
test: child_entity1,
multi: [child_entity2, child_entity2])
}
let(:nested_payload) { nested_entity.to_xml }
it "parses the xml with all the nested data" do
entity = Entities::TestNestedEntity.from_xml(nested_payload)
expect(entity.test.to_h).to eq(child_entity1.to_h)
expect(entity.multi).to have(2).items
expect(entity.multi.first.to_h).to eq(child_entity2.to_h)
expect(entity.asdf).to eq("QWERT")
end
end
end
describe ".entity_name" do
it "strips the module and returns the name underscored" do
expect(Entities::TestDefaultEntity.entity_name).to eq("test_default_entity")
expect(Entities::TestNestedEntity.entity_name).to eq("test_nested_entity")
expect(Entities::OtherEntity.entity_name).to eq("other_entity")
end
it "works with a single word" do
expect(Entities::Entity.entity_name).to eq("entity")
end
end
describe ".entity_class" do
it "should parse a single word" do
expect(Entity.entity_class("entity")).to eq(Entities::Entity)
end
it "should parse with underscore" do
expect(Entity.entity_class("test_entity")).to eq(Entities::TestEntity)
end
it "should not change the input string" do
entity_name = "test_entity"
Entity.entity_class(entity_name)
expect(entity_name).to eq("test_entity")
end
it "raises an error when the entity name contains special characters" do
expect {
Entity.entity_class("te.st-enti/ty")
}.to raise_error Entity::InvalidEntityName, "'te.st-enti/ty' is invalid"
end
it "raises an error when the entity name contains upper case letters" do
expect {
Entity.entity_class("TestEntity")
}.to raise_error Entity::InvalidEntityName, "'TestEntity' is invalid"
end
it "raises an error when the entity name contains numbers" do
expect {
Entity.entity_class("te5t_ent1ty_w1th_number5")
}.to raise_error Entity::InvalidEntityName, "'te5t_ent1ty_w1th_number5' is invalid"
end
it "raises an error when the entity is unknown" do
expect {
Entity.entity_class("unknown_entity")
}.to raise_error Entity::UnknownEntity, "'UnknownEntity' not found"
end
end
context "nested entities" do
let(:nested_data) {
{
asdf: "FDSA",
test: Entities::TestEntity.new(test: "test"),
multi: [Entities::OtherEntity.new(asdf: "asdf"), Entities::OtherEntity.new(asdf: "asdf")]
}
}
let(:nested_hash) {
{
asdf: nested_data[:asdf],
test: nested_data[:test].to_h,
multi: nested_data[:multi].map(&:to_h)
}
}
it "gets returned as Hash by #to_h" do
entity = Entities::TestNestedEntity.new(nested_data)
expect(entity.to_h).to eq(nested_hash)
end
it "gets xml-ified by #to_xml" do
entity = Entities::TestNestedEntity.new(nested_data)
xml = entity.to_xml
expect(xml.children).to have_exactly(4).items
xml.children.each do |node|
expect(%w(asdf test_entity other_entity)).to include(node.name)
end
expect(xml.xpath("test_entity")).to have_exactly(1).items
expect(xml.xpath("other_entity")).to have_exactly(2).items
end
it "instantiates nested entities if provided as hash" do
entity = Entities::TestNestedEntity.new(nested_hash)
expect(entity.test).to be_instance_of(Entities::TestEntity)
expect(entity.test.test).to eq("test")
expect(entity.multi).to be_instance_of(Array)
expect(entity.multi).to have_exactly(2).items
expect(entity.multi.first).to be_instance_of(Entities::OtherEntity)
expect(entity.multi.first.asdf).to eq("asdf")
end
end
context "xml_name" do
let(:hash) { {test: "test", qwer: "qwer"} }
it "uses xml_name for the #to_xml" do
entity = Entities::TestEntityWithXmlName.new(hash)
xml_children = entity.to_xml.children
expect(xml_children).to have_exactly(2).items
xml_children.each do |node|
expect(%w(test asdf)).to include(node.name)
end
end
it "should not use the xml_name for the #to_h" do
entity = Entities::TestEntityWithXmlName.new(hash)
expect(entity.to_h).to eq(hash)
end
end
end
end