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 "for a normal class that has XML serialization" do subject { SomeClass.to_xsd } before do class SomeClass include ActiveModel::Serializers::Xml def attributes=(hash) @hash = hash end def attributes @hash end extend Schematic::Serializers::Xsd schematic do add :foo end end end it "should generate a valid XSD" do validate_xsd(subject) end it "should validate against it's own XSD" do invalid_instance = SomeClass.new invalid_instance.attributes = { "bar" => "foo" } xml = [invalid_instance].to_xml lambda { validate_xml_against_xsd(xml, subject) }.should raise_error instance = SomeClass.new instance.attributes = { "foo" => "bar" } xml = [instance].to_xml validate_xml_against_xsd(xml, subject) end end 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 schematic do add :foo => { :bar => { :baz => nil }, :quz => [:qaz] } add :method_is_also_columns => [:method_is_also_column] add :additional_method_array => [] 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 => ["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 it "turns 'special-children' into 'special-children-attributes'" do xsd.nested_attribute_name("special_children").should == "special-children-attributes" end it "properly converts symbols" do xsd.nested_attribute_name(:very_special_children).should == "very-special-children-attributes" end end end