require "spec_helper"
describe Schematic::Serializers::Xsd do
before do
class EmptyModel < ActiveRecord::Base
def self.columns
[]
end
end
end
describe ".to_xsd" do
context "XSD validation" do
context "when the model is not namespaced" do
subject { SomeModel.to_xsd }
with_model :some_model do
table do |t|
t.string "some_string"
t.text "some_text"
t.float "some_float"
t.integer "some_integer"
t.datetime "some_datetime"
t.date "some_date"
t.boolean "some_boolean"
t.text "method_is_also_columns"
end
model do
validates :some_string, :presence => true, :length => { :maximum => 100 }
validates :some_text, :presence => true
validates :some_date, :presence => true, :allow_blank => true
validates :some_datetime, :presence => true, :allow_blank => false
attr_accessor :additional_method_array
class << self
def xsd_methods
{:foo => { :bar => { :baz => nil }, :quz => [:qaz] }, :method_is_also_columns => [:method_is_also_column], :additional_method_array => [] }
end
end
def to_xml(options)
super({:methods => [:additional_method_array]}.merge(options))
end
end
end
it "should generate a valid XSD" do
validate_xsd(subject)
end
it "should validate against it's own XSD" do
instance = SomeModel.new(:some_string => "ExampleString",
:some_date => Date.today,
:some_text => "here is some text",
:some_datetime => DateTime.new,
:some_boolean => true,
:some_float => 1.5,
:method_is_also_columns => [{:some => "somevalues"}],
:additional_method_array => {"somevalue" => "somekey"},
:some_integer => 2)
xml = [instance].to_xml
validate_xml_against_xsd(xml, subject)
end
end
context "when the model is namespaced" do
before do
module Namespace; end
end
subject { Namespace::SomeModel.to_xsd }
with_model :some_model do
table do |t|
t.string "some_string"
end
model do
validates :some_string, :presence => true
end
end
before do
class Namespace::SomeModel < SomeModel
end
end
it "should generate a valid XSD" do
validate_xsd(subject)
end
end
context "when the model has a nested attribute on a subclass with a reference to the superclass" do
with_model :parent do
table {}
model do
has_many :children, :class_name => "Namespace::Child"
accepts_nested_attributes_for :children
end
end
with_model :child do
table do |t|
t.integer :parent_id
end
model do
belongs_to :parent
end
end
before do
module Namespace; end
class Namespace::Child < Child
accepts_nested_attributes_for :parent
end
end
subject { Namespace::Child.to_xsd }
it "should generate a valid XSD" do
validate_xsd(subject)
end
it "should validate against its own XSD" do
child_instance = Namespace::Child.new(:parent_id => 123)
xml = [child_instance].to_xml
lambda {
validate_xml_against_xsd(xml, subject)
}.should_not raise_error
end
end
context "when the model has a nested attribute on a subclass with a different class name than the association" do
with_model :parent do
table {}
model do
has_many :children, :class_name => "SpecialChild"
accepts_nested_attributes_for :children
end
end
with_model :special_child do
table do |t|
t.integer :parent_id
end
model do
belongs_to :parent
end
end
subject { Parent.to_xsd }
it "should generate a valid XSD" do
subject.should include "children-attributes"
subject.should_not include "special-children-attributes"
validate_xsd(subject)
end
end
context "when the model has a circular nested attribute reference" do
with_model :plate do
table {}
model do
has_many :cheeses
accepts_nested_attributes_for :cheeses
end
end
with_model :cheese do
table do |t|
t.integer :plate_id
end
model do
belongs_to :plate
accepts_nested_attributes_for :plate
end
end
subject { Cheese.to_xsd }
it "should generate a valid XSD" do
validate_xsd(subject)
end
end
context "when the model has a nested reference that references another nested reference" do
with_model :blog do
table {}
model do
has_many :posts
has_many :readers
accepts_nested_attributes_for :posts
accepts_nested_attributes_for :readers
end
end
with_model :post do
table do |t|
t.integer :blog_id
end
model do
belongs_to :blog
has_many :readers
accepts_nested_attributes_for :blog
accepts_nested_attributes_for :readers
end
end
with_model :reader do
table do |t|
t.integer :blog_id
t.integer :post_id
end
end
subject { Post.to_xsd }
it "should generate a valid XSD" do
validate_xsd(subject)
end
end
end
context "for an empty model with no attributes or validations" do
subject { sanitize_xml(EmptyModel.to_xsd) }
it "should return an xsd for an array of the model" do
xsd = <<-XML
XML
subject.should == sanitize_xml(xsd)
end
end
context "for a model with attributes" do
subject { sanitize_xml(SomeModel.to_xsd) }
context "for a any attribute" do
with_model :some_model do
table :id => false do |t|
t.float 'some_float'
end
end
it "should define the correct xsd element" do
xsd = generate_xsd_for_model(SomeModel) do
<<-XML
XML
end
subject.should == xsd
end
end
describe "additional methods" do
with_model :some_model do
table {}
end
it "should include the additional method" do
xsd = generate_xsd_for_model(SomeModel) do
<<-XML
XML
end
sanitize_xml(SomeModel.to_xsd(:methods => {:foo_bar => nil})).should == xsd
end
end
end
end
describe "#nested_attribute_name" do
let(:xsd) {Schematic::Generator::Xsd.new(Object)}
it "turns 'child' into 'children-attributes'" do
xsd.nested_attribute_name('child').should == "children-attributes"
end
it "turns 'children' into 'children-attributes'" do
xsd.nested_attribute_name('children').should == "children-attributes"
end
end
end