2009-10-31 13:40:32 +01:00
|
|
|
# encoding: utf-8
|
2010-05-10 21:19:24 +02:00
|
|
|
require File.expand_path('../../spec_helper', __FILE__)
|
2010-06-20 22:01:11 +02:00
|
|
|
require File.join(FIXTURE_PATH, 'more', 'cat')
|
2009-06-08 03:51:31 +02:00
|
|
|
require File.join(FIXTURE_PATH, 'more', 'person')
|
2009-01-30 03:45:01 +01:00
|
|
|
require File.join(FIXTURE_PATH, 'more', 'card')
|
2009-02-03 04:21:32 +01:00
|
|
|
require File.join(FIXTURE_PATH, 'more', 'invoice')
|
2009-02-25 07:51:13 +01:00
|
|
|
require File.join(FIXTURE_PATH, 'more', 'service')
|
|
|
|
require File.join(FIXTURE_PATH, 'more', 'event')
|
2009-10-31 13:40:32 +01:00
|
|
|
require File.join(FIXTURE_PATH, 'more', 'user')
|
2009-07-20 23:17:27 +02:00
|
|
|
require File.join(FIXTURE_PATH, 'more', 'course')
|
2009-02-09 20:20:23 +01:00
|
|
|
|
2009-01-30 03:45:01 +01:00
|
|
|
|
2010-06-20 22:01:11 +02:00
|
|
|
describe "Model properties" do
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-01-30 03:45:01 +01:00
|
|
|
before(:each) do
|
2009-03-08 15:27:30 +01:00
|
|
|
reset_test_db!
|
2009-01-30 03:45:01 +01:00
|
|
|
@card = Card.new(:first_name => "matt")
|
|
|
|
end
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-01-30 03:45:01 +01:00
|
|
|
it "should be accessible from the object" do
|
|
|
|
@card.properties.should be_an_instance_of(Array)
|
|
|
|
@card.properties.map{|p| p.name}.should include("first_name")
|
|
|
|
end
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2010-11-11 01:33:46 +01:00
|
|
|
it "should list object properties with values" do
|
|
|
|
@card.properties_with_values.should be_an_instance_of(Hash)
|
|
|
|
@card.properties_with_values["first_name"].should == "matt"
|
|
|
|
end
|
|
|
|
|
2009-01-30 03:45:01 +01:00
|
|
|
it "should let you access a property value (getter)" do
|
|
|
|
@card.first_name.should == "matt"
|
|
|
|
end
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-01-30 03:45:01 +01:00
|
|
|
it "should let you set a property value (setter)" do
|
|
|
|
@card.last_name = "Aimonetti"
|
|
|
|
@card.last_name.should == "Aimonetti"
|
|
|
|
end
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-01-30 03:45:01 +01:00
|
|
|
it "should not let you set a property value if it's read only" do
|
|
|
|
lambda{@card.read_only_value = "test"}.should raise_error
|
|
|
|
end
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-01-30 03:45:01 +01:00
|
|
|
it "should let you use an alias for an attribute" do
|
|
|
|
@card.last_name = "Aimonetti"
|
|
|
|
@card.family_name.should == "Aimonetti"
|
|
|
|
@card.family_name.should == @card.last_name
|
|
|
|
end
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-06-08 03:51:31 +02:00
|
|
|
it "should let you use an alias for a casted attribute" do
|
2010-06-18 01:24:49 +02:00
|
|
|
@card.cast_alias = Person.new(:name => ["Aimonetti"])
|
2009-07-20 23:17:27 +02:00
|
|
|
@card.cast_alias.name.should == ["Aimonetti"]
|
|
|
|
@card.calias.name.should == ["Aimonetti"]
|
2010-06-18 01:24:49 +02:00
|
|
|
card = Card.new(:first_name => "matt", :cast_alias => {:name => ["Aimonetti"]})
|
2009-07-20 23:17:27 +02:00
|
|
|
card.cast_alias.name.should == ["Aimonetti"]
|
|
|
|
card.calias.name.should == ["Aimonetti"]
|
2009-06-08 03:51:31 +02:00
|
|
|
end
|
2010-06-18 01:24:49 +02:00
|
|
|
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-02-04 02:33:31 +01:00
|
|
|
it "should be auto timestamped" do
|
|
|
|
@card.created_at.should be_nil
|
|
|
|
@card.updated_at.should be_nil
|
2009-02-11 01:10:35 +01:00
|
|
|
@card.save.should be_true
|
2009-02-04 02:33:31 +01:00
|
|
|
@card.created_at.should_not be_nil
|
|
|
|
@card.updated_at.should_not be_nil
|
|
|
|
end
|
2010-06-16 22:02:12 +02:00
|
|
|
|
2010-08-12 05:27:53 +02:00
|
|
|
describe '#read_attribute' do
|
|
|
|
it "should let you use read_attribute method" do
|
|
|
|
@card.last_name = "Aimonetti"
|
|
|
|
@card.read_attribute(:last_name).should eql('Aimonetti')
|
|
|
|
@card.read_attribute('last_name').should eql('Aimonetti')
|
|
|
|
last_name_prop = @card.properties.find{|p| p.name == 'last_name'}
|
|
|
|
@card.read_attribute(last_name_prop).should eql('Aimonetti')
|
|
|
|
end
|
2010-06-16 22:02:12 +02:00
|
|
|
|
2010-08-12 05:27:53 +02:00
|
|
|
it 'should raise an error if the property does not exist' do
|
|
|
|
expect { @card.read_attribute(:this_property_should_not_exist) }.to raise_error(ArgumentError)
|
|
|
|
end
|
2010-06-16 22:02:12 +02:00
|
|
|
end
|
|
|
|
|
2010-08-12 05:27:53 +02:00
|
|
|
describe '#write_attribute' do
|
|
|
|
it "should let you use write_attribute method" do
|
|
|
|
@card.write_attribute(:last_name, 'Aimonetti 1')
|
|
|
|
@card.last_name.should eql('Aimonetti 1')
|
|
|
|
@card.write_attribute('last_name', 'Aimonetti 2')
|
|
|
|
@card.last_name.should eql('Aimonetti 2')
|
|
|
|
last_name_prop = @card.properties.find{|p| p.name == 'last_name'}
|
|
|
|
@card.write_attribute(last_name_prop, 'Aimonetti 3')
|
|
|
|
@card.last_name.should eql('Aimonetti 3')
|
|
|
|
end
|
2010-06-16 22:02:12 +02:00
|
|
|
|
2010-08-12 05:27:53 +02:00
|
|
|
it 'should raise an error if the property does not exist' do
|
|
|
|
expect { @card.write_attribute(:this_property_should_not_exist, 823) }.to raise_error(ArgumentError)
|
|
|
|
end
|
|
|
|
|
2010-09-17 23:25:56 +02:00
|
|
|
|
2010-08-12 05:27:53 +02:00
|
|
|
it "should let you use write_attribute on readonly properties" do
|
|
|
|
lambda {
|
|
|
|
@card.read_only_value = "foo"
|
|
|
|
}.should raise_error
|
|
|
|
@card.write_attribute(:read_only_value, "foo")
|
|
|
|
@card.read_only_value.should == 'foo'
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should cast via write_attribute" do
|
|
|
|
@card.write_attribute(:cast_alias, {:name => ["Sam", "Lown"]})
|
|
|
|
@card.cast_alias.class.should eql(Person)
|
|
|
|
@card.cast_alias.name.last.should eql("Lown")
|
|
|
|
end
|
2010-06-16 22:02:12 +02:00
|
|
|
|
2010-08-12 05:27:53 +02:00
|
|
|
it "should not cast via write_attribute if property not casted" do
|
|
|
|
@card.write_attribute(:first_name, {:name => "Sam"})
|
|
|
|
@card.first_name.class.should eql(Hash)
|
|
|
|
@card.first_name[:name].should eql("Sam")
|
|
|
|
end
|
2010-06-16 22:02:12 +02:00
|
|
|
end
|
|
|
|
|
2010-09-18 15:19:15 +02:00
|
|
|
describe "mass updating attributes without property" do
|
|
|
|
|
|
|
|
describe "when mass_assign_any_attribute false" do
|
|
|
|
|
|
|
|
it "should not allow them to be set" do
|
|
|
|
@card.attributes = {:test => 'fooobar'}
|
|
|
|
@card['test'].should be_nil
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "when mass_assign_any_attribute true" do
|
|
|
|
before(:each) do
|
|
|
|
# dup Card class so that no other tests are effected
|
|
|
|
card_class = Card.dup
|
|
|
|
card_class.class_eval do
|
|
|
|
mass_assign_any_attribute true
|
|
|
|
end
|
|
|
|
@card = card_class.new(:first_name => 'Sam')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'should allow them to be updated' do
|
|
|
|
@card.attributes = {:test => 'fooobar'}
|
|
|
|
@card['test'].should eql('fooobar')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-10-31 13:40:32 +01:00
|
|
|
describe "mass assignment protection" do
|
|
|
|
|
|
|
|
it "should not store protected attribute using mass assignment" do
|
|
|
|
cat_toy = CatToy.new(:name => "Zorro")
|
|
|
|
cat = Cat.create(:name => "Helena", :toys => [cat_toy], :favorite_toy => cat_toy, :number => 1)
|
|
|
|
cat.number.should be_nil
|
|
|
|
cat.number = 1
|
|
|
|
cat.save
|
|
|
|
cat.number.should == 1
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should not store protected attribute when 'declare accessible poperties, assume all the rest are protected'" do
|
|
|
|
user = User.create(:name => "Marcos Tapajós", :admin => true)
|
|
|
|
user.admin.should be_nil
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should not store protected attribute when 'declare protected properties, assume all the rest are accessible'" do
|
|
|
|
user = SpecialUser.create(:name => "Marcos Tapajós", :admin => true)
|
|
|
|
user.admin.should be_nil
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-02-03 04:21:32 +01:00
|
|
|
describe "validation" do
|
|
|
|
before(:each) do
|
|
|
|
@invoice = Invoice.new(:client_name => "matt", :employee_name => "Chris", :location => "San Diego, CA")
|
|
|
|
end
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-02-03 04:21:32 +01:00
|
|
|
it "should be able to be validated" do
|
2009-02-06 02:06:12 +01:00
|
|
|
@card.valid?.should == true
|
2009-02-03 01:10:07 +01:00
|
|
|
end
|
2009-02-09 20:20:23 +01:00
|
|
|
|
2009-02-03 04:21:32 +01:00
|
|
|
it "should let you validate the presence of an attribute" do
|
|
|
|
@card.first_name = nil
|
|
|
|
@card.should_not be_valid
|
|
|
|
@card.errors.should_not be_empty
|
2010-06-20 22:01:11 +02:00
|
|
|
@card.errors[:first_name].should == ["can't be blank"]
|
2009-02-03 04:21:32 +01:00
|
|
|
end
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-03-24 23:37:52 +01:00
|
|
|
it "should let you look up errors for a field by a string name" do
|
|
|
|
@card.first_name = nil
|
|
|
|
@card.should_not be_valid
|
2010-06-20 22:01:11 +02:00
|
|
|
@card.errors['first_name'].should == ["can't be blank"]
|
2009-03-24 23:37:52 +01:00
|
|
|
end
|
2009-02-09 20:20:23 +01:00
|
|
|
|
2009-02-03 04:21:32 +01:00
|
|
|
it "should validate the presence of 2 attributes" do
|
|
|
|
@invoice.clear
|
|
|
|
@invoice.should_not be_valid
|
|
|
|
@invoice.errors.should_not be_empty
|
2010-06-20 22:01:11 +02:00
|
|
|
@invoice.errors[:client_name].should == ["can't be blank"]
|
|
|
|
@invoice.errors[:employee_name].should_not be_empty
|
2009-02-03 04:21:32 +01:00
|
|
|
end
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-02-03 04:21:32 +01:00
|
|
|
it "should let you set an error message" do
|
|
|
|
@invoice.location = nil
|
|
|
|
@invoice.valid?
|
2010-06-20 22:01:11 +02:00
|
|
|
@invoice.errors[:location].should == ["Hey stupid!, you forgot the location"]
|
2009-02-03 04:21:32 +01:00
|
|
|
end
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-02-04 02:33:31 +01:00
|
|
|
it "should validate before saving" do
|
|
|
|
@invoice.location = nil
|
|
|
|
@invoice.should_not be_valid
|
|
|
|
@invoice.save.should be_false
|
2009-06-05 05:44:44 +02:00
|
|
|
@invoice.should be_new
|
2009-02-04 02:33:31 +01:00
|
|
|
end
|
2009-02-03 01:10:07 +01:00
|
|
|
end
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-02-25 07:51:13 +01:00
|
|
|
describe "casting" do
|
2009-07-20 23:17:27 +02:00
|
|
|
before(:each) do
|
|
|
|
@course = Course.new(:title => 'Relaxation')
|
|
|
|
end
|
2009-02-25 07:51:13 +01:00
|
|
|
|
2009-07-20 23:17:27 +02:00
|
|
|
describe "when value is nil" do
|
|
|
|
it "leaves the value unchanged" do
|
|
|
|
@course.title = nil
|
|
|
|
@course['title'].should == nil
|
2009-02-25 07:51:13 +01:00
|
|
|
end
|
2009-07-20 23:17:27 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
describe "when type primitive is an Object" do
|
|
|
|
it "it should not cast given value" do
|
|
|
|
@course.participants = [{}, 'q', 1]
|
2010-03-16 01:07:41 +01:00
|
|
|
@course['participants'].should == [{}, 'q', 1]
|
2009-02-25 07:51:13 +01:00
|
|
|
end
|
2010-02-17 23:35:42 +01:00
|
|
|
|
2010-02-26 00:25:51 +01:00
|
|
|
it "should cast started_on to Date" do
|
|
|
|
@course.started_on = Date.today
|
|
|
|
@course['started_on'].should be_an_instance_of(Date)
|
2009-09-03 04:54:25 +02:00
|
|
|
end
|
2009-02-25 07:51:13 +01:00
|
|
|
end
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-07-20 23:17:27 +02:00
|
|
|
describe "when type primitive is a String" do
|
|
|
|
it "keeps string value unchanged" do
|
|
|
|
value = "1.0"
|
|
|
|
@course.title = value
|
|
|
|
@course['title'].should equal(value)
|
2009-07-17 04:52:53 +02:00
|
|
|
end
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-07-20 23:17:27 +02:00
|
|
|
it "it casts to string representation of the value" do
|
|
|
|
@course.title = 1.0
|
|
|
|
@course['title'].should eql("1.0")
|
2009-07-17 04:52:53 +02:00
|
|
|
end
|
2009-07-20 23:17:27 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
describe 'when type primitive is a Float' do
|
|
|
|
it 'returns same value if a float' do
|
|
|
|
value = 24.0
|
|
|
|
@course.estimate = value
|
|
|
|
@course['estimate'].should equal(value)
|
2009-07-17 04:52:53 +02:00
|
|
|
end
|
2009-07-20 23:17:27 +02:00
|
|
|
|
|
|
|
it 'returns float representation of a zero string integer' do
|
|
|
|
@course.estimate = '0'
|
|
|
|
@course['estimate'].should eql(0.0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns float representation of a positive string integer' do
|
|
|
|
@course.estimate = '24'
|
|
|
|
@course['estimate'].should eql(24.0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns float representation of a negative string integer' do
|
|
|
|
@course.estimate = '-24'
|
|
|
|
@course['estimate'].should eql(-24.0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns float representation of a zero string float' do
|
|
|
|
@course.estimate = '0.0'
|
|
|
|
@course['estimate'].should eql(0.0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns float representation of a positive string float' do
|
|
|
|
@course.estimate = '24.35'
|
|
|
|
@course['estimate'].should eql(24.35)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns float representation of a negative string float' do
|
|
|
|
@course.estimate = '-24.35'
|
|
|
|
@course['estimate'].should eql(-24.35)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns float representation of a zero string float, with no leading digits' do
|
|
|
|
@course.estimate = '.0'
|
|
|
|
@course['estimate'].should eql(0.0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns float representation of a positive string float, with no leading digits' do
|
|
|
|
@course.estimate = '.41'
|
|
|
|
@course['estimate'].should eql(0.41)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns float representation of a zero integer' do
|
|
|
|
@course.estimate = 0
|
|
|
|
@course['estimate'].should eql(0.0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns float representation of a positive integer' do
|
|
|
|
@course.estimate = 24
|
|
|
|
@course['estimate'].should eql(24.0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns float representation of a negative integer' do
|
|
|
|
@course.estimate = -24
|
|
|
|
@course['estimate'].should eql(-24.0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns float representation of a zero decimal' do
|
|
|
|
@course.estimate = BigDecimal('0.0')
|
|
|
|
@course['estimate'].should eql(0.0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns float representation of a positive decimal' do
|
|
|
|
@course.estimate = BigDecimal('24.35')
|
|
|
|
@course['estimate'].should eql(24.35)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns float representation of a negative decimal' do
|
|
|
|
@course.estimate = BigDecimal('-24.35')
|
|
|
|
@course['estimate'].should eql(-24.35)
|
|
|
|
end
|
|
|
|
|
2010-10-23 20:59:24 +02:00
|
|
|
it 'return float of a number with commas instead of points for decimals' do
|
|
|
|
@course.estimate = '23,35'
|
|
|
|
@course['estimate'].should eql(23.35)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should handle numbers with commas and points" do
|
|
|
|
@course.estimate = '1,234.00'
|
|
|
|
@course.estimate.should eql(1234.00)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should handle a mis-match of commas and points and maintain the last one" do
|
|
|
|
@course.estimate = "1,232.434.123,323"
|
|
|
|
@course.estimate.should eql(1232434123.323)
|
|
|
|
end
|
|
|
|
|
2009-07-20 23:17:27 +02:00
|
|
|
[ Object.new, true, '00.0', '0.', '-.0', 'string' ].each do |value|
|
|
|
|
it "does not typecast non-numeric value #{value.inspect}" do
|
|
|
|
@course.estimate = value
|
|
|
|
@course['estimate'].should equal(value)
|
|
|
|
end
|
2009-07-17 04:52:53 +02:00
|
|
|
end
|
2010-10-23 20:59:24 +02:00
|
|
|
|
2009-07-17 04:52:53 +02:00
|
|
|
end
|
2009-07-20 23:17:27 +02:00
|
|
|
|
|
|
|
describe 'when type primitive is a Integer' do
|
|
|
|
it 'returns same value if an integer' do
|
|
|
|
value = 24
|
|
|
|
@course.hours = value
|
|
|
|
@course['hours'].should equal(value)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns integer representation of a zero string integer' do
|
|
|
|
@course.hours = '0'
|
|
|
|
@course['hours'].should eql(0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns integer representation of a positive string integer' do
|
|
|
|
@course.hours = '24'
|
|
|
|
@course['hours'].should eql(24)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns integer representation of a negative string integer' do
|
|
|
|
@course.hours = '-24'
|
|
|
|
@course['hours'].should eql(-24)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns integer representation of a zero string float' do
|
|
|
|
@course.hours = '0.0'
|
|
|
|
@course['hours'].should eql(0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns integer representation of a positive string float' do
|
|
|
|
@course.hours = '24.35'
|
|
|
|
@course['hours'].should eql(24)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns integer representation of a negative string float' do
|
|
|
|
@course.hours = '-24.35'
|
|
|
|
@course['hours'].should eql(-24)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns integer representation of a zero string float, with no leading digits' do
|
|
|
|
@course.hours = '.0'
|
|
|
|
@course['hours'].should eql(0)
|
2009-07-25 05:12:03 +02:00
|
|
|
end
|
|
|
|
|
2009-07-20 23:17:27 +02:00
|
|
|
it 'returns integer representation of a positive string float, with no leading digits' do
|
|
|
|
@course.hours = '.41'
|
|
|
|
@course['hours'].should eql(0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns integer representation of a zero float' do
|
|
|
|
@course.hours = 0.0
|
|
|
|
@course['hours'].should eql(0)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns integer representation of a positive float' do
|
|
|
|
@course.hours = 24.35
|
|
|
|
@course['hours'].should eql(24)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns integer representation of a negative float' do
|
|
|
|
@course.hours = -24.35
|
|
|
|
@course['hours'].should eql(-24)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns integer representation of a zero decimal' do
|
|
|
|
@course.hours = '0.0'
|
|
|
|
@course['hours'].should eql(0)
|
|
|
|
end
|
2009-07-25 05:12:03 +02:00
|
|
|
|
2009-07-20 23:17:27 +02:00
|
|
|
it 'returns integer representation of a positive decimal' do
|
|
|
|
@course.hours = '24.35'
|
|
|
|
@course['hours'].should eql(24)
|
2009-07-25 05:12:03 +02:00
|
|
|
end
|
|
|
|
|
2009-07-20 23:17:27 +02:00
|
|
|
it 'returns integer representation of a negative decimal' do
|
|
|
|
@course.hours = '-24.35'
|
|
|
|
@course['hours'].should eql(-24)
|
|
|
|
end
|
|
|
|
|
|
|
|
[ Object.new, true, '00.0', '0.', '-.0', 'string' ].each do |value|
|
|
|
|
it "does not typecast non-numeric value #{value.inspect}" do
|
|
|
|
@course.hours = value
|
|
|
|
@course['hours'].should equal(value)
|
|
|
|
end
|
2009-07-25 05:12:03 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-07-20 23:17:27 +02:00
|
|
|
describe 'when type primitive is a BigDecimal' do
|
|
|
|
it 'returns same value if a decimal' do
|
|
|
|
value = BigDecimal('24.0')
|
|
|
|
@course.profit = value
|
|
|
|
@course['profit'].should equal(value)
|
|
|
|
end
|
2009-05-29 02:56:42 +02:00
|
|
|
|
2009-07-20 23:17:27 +02:00
|
|
|
it 'returns decimal representation of a zero string integer' do
|
|
|
|
@course.profit = '0'
|
|
|
|
@course['profit'].should eql(BigDecimal('0.0'))
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns decimal representation of a positive string integer' do
|
|
|
|
@course.profit = '24'
|
|
|
|
@course['profit'].should eql(BigDecimal('24.0'))
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns decimal representation of a negative string integer' do
|
|
|
|
@course.profit = '-24'
|
|
|
|
@course['profit'].should eql(BigDecimal('-24.0'))
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns decimal representation of a zero string float' do
|
|
|
|
@course.profit = '0.0'
|
|
|
|
@course['profit'].should eql(BigDecimal('0.0'))
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns decimal representation of a positive string float' do
|
|
|
|
@course.profit = '24.35'
|
|
|
|
@course['profit'].should eql(BigDecimal('24.35'))
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns decimal representation of a negative string float' do
|
|
|
|
@course.profit = '-24.35'
|
|
|
|
@course['profit'].should eql(BigDecimal('-24.35'))
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns decimal representation of a zero string float, with no leading digits' do
|
|
|
|
@course.profit = '.0'
|
|
|
|
@course['profit'].should eql(BigDecimal('0.0'))
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns decimal representation of a positive string float, with no leading digits' do
|
|
|
|
@course.profit = '.41'
|
|
|
|
@course['profit'].should eql(BigDecimal('0.41'))
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns decimal representation of a zero integer' do
|
|
|
|
@course.profit = 0
|
|
|
|
@course['profit'].should eql(BigDecimal('0.0'))
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns decimal representation of a positive integer' do
|
|
|
|
@course.profit = 24
|
|
|
|
@course['profit'].should eql(BigDecimal('24.0'))
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns decimal representation of a negative integer' do
|
|
|
|
@course.profit = -24
|
|
|
|
@course['profit'].should eql(BigDecimal('-24.0'))
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns decimal representation of a zero float' do
|
|
|
|
@course.profit = 0.0
|
|
|
|
@course['profit'].should eql(BigDecimal('0.0'))
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns decimal representation of a positive float' do
|
|
|
|
@course.profit = 24.35
|
|
|
|
@course['profit'].should eql(BigDecimal('24.35'))
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns decimal representation of a negative float' do
|
|
|
|
@course.profit = -24.35
|
|
|
|
@course['profit'].should eql(BigDecimal('-24.35'))
|
|
|
|
end
|
|
|
|
|
|
|
|
[ Object.new, true, '00.0', '0.', '-.0', 'string' ].each do |value|
|
|
|
|
it "does not typecast non-numeric value #{value.inspect}" do
|
|
|
|
@course.profit = value
|
|
|
|
@course['profit'].should equal(value)
|
|
|
|
end
|
|
|
|
end
|
2009-05-29 02:56:42 +02:00
|
|
|
end
|
2009-07-20 23:17:27 +02:00
|
|
|
|
|
|
|
describe 'when type primitive is a DateTime' do
|
|
|
|
describe 'and value given as a hash with keys like :year, :month, etc' do
|
|
|
|
it 'builds a DateTime instance from hash values' do
|
|
|
|
@course.updated_at = {
|
|
|
|
:year => '2006',
|
|
|
|
:month => '11',
|
|
|
|
:day => '23',
|
|
|
|
:hour => '12',
|
|
|
|
:min => '0',
|
|
|
|
:sec => '0'
|
|
|
|
}
|
|
|
|
result = @course['updated_at']
|
|
|
|
|
|
|
|
result.should be_kind_of(DateTime)
|
|
|
|
result.year.should eql(2006)
|
|
|
|
result.month.should eql(11)
|
|
|
|
result.day.should eql(23)
|
|
|
|
result.hour.should eql(12)
|
|
|
|
result.min.should eql(0)
|
|
|
|
result.sec.should eql(0)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'and value is a string' do
|
|
|
|
it 'parses the string' do
|
|
|
|
@course.updated_at = 'Dec, 2006'
|
|
|
|
@course['updated_at'].month.should == 12
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not typecast non-datetime values' do
|
|
|
|
@course.updated_at = 'not-datetime'
|
|
|
|
@course['updated_at'].should eql('not-datetime')
|
|
|
|
end
|
2009-05-29 02:56:42 +02:00
|
|
|
end
|
2009-07-20 23:17:27 +02:00
|
|
|
|
|
|
|
describe 'when type primitive is a Date' do
|
|
|
|
describe 'and value given as a hash with keys like :year, :month, etc' do
|
|
|
|
it 'builds a Date instance from hash values' do
|
|
|
|
@course.started_on = {
|
|
|
|
:year => '2007',
|
|
|
|
:month => '3',
|
|
|
|
:day => '25'
|
|
|
|
}
|
|
|
|
result = @course['started_on']
|
|
|
|
|
|
|
|
result.should be_kind_of(Date)
|
|
|
|
result.year.should eql(2007)
|
|
|
|
result.month.should eql(3)
|
|
|
|
result.day.should eql(25)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'and value is a string' do
|
|
|
|
it 'parses the string' do
|
|
|
|
@course.started_on = 'Dec 20th, 2006'
|
|
|
|
@course.started_on.month.should == 12
|
|
|
|
@course.started_on.day.should == 20
|
|
|
|
@course.started_on.year.should == 2006
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not typecast non-date values' do
|
|
|
|
@course.started_on = 'not-date'
|
|
|
|
@course['started_on'].should eql('not-date')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'when type primitive is a Time' do
|
|
|
|
describe 'and value given as a hash with keys like :year, :month, etc' do
|
|
|
|
it 'builds a Time instance from hash values' do
|
|
|
|
@course.ends_at = {
|
|
|
|
:year => '2006',
|
|
|
|
:month => '11',
|
|
|
|
:day => '23',
|
|
|
|
:hour => '12',
|
|
|
|
:min => '0',
|
|
|
|
:sec => '0'
|
|
|
|
}
|
|
|
|
result = @course['ends_at']
|
|
|
|
|
|
|
|
result.should be_kind_of(Time)
|
|
|
|
result.year.should eql(2006)
|
|
|
|
result.month.should eql(11)
|
|
|
|
result.day.should eql(23)
|
|
|
|
result.hour.should eql(12)
|
|
|
|
result.min.should eql(0)
|
|
|
|
result.sec.should eql(0)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'and value is a string' do
|
|
|
|
it 'parses the string' do
|
2009-07-21 05:31:18 +02:00
|
|
|
t = Time.now
|
|
|
|
@course.ends_at = t.strftime('%Y/%m/%d %H:%M:%S %z')
|
|
|
|
@course['ends_at'].year.should eql(t.year)
|
|
|
|
@course['ends_at'].month.should eql(t.month)
|
|
|
|
@course['ends_at'].day.should eql(t.day)
|
|
|
|
@course['ends_at'].hour.should eql(t.hour)
|
2010-08-18 19:36:01 +02:00
|
|
|
@course['ends_at'].min.should eql(t.min)
|
|
|
|
@course['ends_at'].sec.should eql(t.sec)
|
|
|
|
end
|
|
|
|
it 'parses the string without offset' do
|
|
|
|
t = Time.now
|
|
|
|
@course.ends_at = t.strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
@course['ends_at'].year.should eql(t.year)
|
|
|
|
@course['ends_at'].month.should eql(t.month)
|
|
|
|
@course['ends_at'].day.should eql(t.day)
|
|
|
|
@course['ends_at'].hour.should eql(t.hour)
|
2009-07-21 05:31:18 +02:00
|
|
|
@course['ends_at'].min.should eql(t.min)
|
|
|
|
@course['ends_at'].sec.should eql(t.sec)
|
2009-07-20 23:17:27 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not typecast non-time values' do
|
2009-07-21 05:31:18 +02:00
|
|
|
@course.ends_at = 'not-time'
|
2009-07-20 23:17:27 +02:00
|
|
|
@course['ends_at'].should eql('not-time')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'when type primitive is a Class' do
|
|
|
|
it 'returns same value if a class' do
|
|
|
|
value = Course
|
|
|
|
@course.klass = value
|
|
|
|
@course['klass'].should equal(value)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns the class if found' do
|
|
|
|
@course.klass = 'Course'
|
|
|
|
@course['klass'].should eql(Course)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not typecast non-class values' do
|
|
|
|
@course.klass = 'NoClass'
|
|
|
|
@course['klass'].should eql('NoClass')
|
2009-07-17 04:52:53 +02:00
|
|
|
end
|
|
|
|
end
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-07-20 23:17:27 +02:00
|
|
|
describe 'when type primitive is a Boolean' do
|
2010-05-22 00:24:07 +02:00
|
|
|
|
2009-07-20 23:17:27 +02:00
|
|
|
[ true, 'true', 'TRUE', '1', 1, 't', 'T' ].each do |value|
|
|
|
|
it "returns true when value is #{value.inspect}" do
|
|
|
|
@course.active = value
|
|
|
|
@course['active'].should be_true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
[ false, 'false', 'FALSE', '0', 0, 'f', 'F' ].each do |value|
|
|
|
|
it "returns false when value is #{value.inspect}" do
|
|
|
|
@course.active = value
|
|
|
|
@course['active'].should be_false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
[ 'string', 2, 1.0, BigDecimal('1.0'), DateTime.now, Time.now, Date.today, Class, Object.new, ].each do |value|
|
|
|
|
it "does not typecast value #{value.inspect}" do
|
|
|
|
@course.active = value
|
|
|
|
@course['active'].should equal(value)
|
|
|
|
end
|
|
|
|
end
|
2010-05-21 23:00:19 +02:00
|
|
|
|
|
|
|
it "should respond to requests with ? modifier" do
|
2010-08-12 05:27:53 +02:00
|
|
|
@course.active = nil
|
2010-05-21 23:00:19 +02:00
|
|
|
@course.active?.should be_false
|
2010-05-22 00:24:07 +02:00
|
|
|
@course.active = false
|
|
|
|
@course.active?.should be_false
|
|
|
|
@course.active = true
|
|
|
|
@course.active?.should be_true
|
2010-05-21 23:00:19 +02:00
|
|
|
end
|
2010-05-22 00:17:33 +02:00
|
|
|
|
2010-05-22 00:24:07 +02:00
|
|
|
it "should respond to requests with ? modifier on TrueClass" do
|
2010-08-12 05:27:53 +02:00
|
|
|
@course.very_active = nil
|
2010-05-22 00:24:07 +02:00
|
|
|
@course.very_active?.should be_false
|
|
|
|
@course.very_active = false
|
|
|
|
@course.very_active?.should be_false
|
|
|
|
@course.very_active = true
|
2010-05-21 23:00:19 +02:00
|
|
|
@course.very_active?.should be_true
|
|
|
|
end
|
2009-05-29 02:56:42 +02:00
|
|
|
end
|
2010-05-21 23:00:19 +02:00
|
|
|
|
2009-05-29 02:56:42 +02:00
|
|
|
end
|
2009-03-08 15:27:30 +01:00
|
|
|
end
|
2009-05-29 02:56:42 +02:00
|
|
|
|
2010-06-18 01:24:49 +02:00
|
|
|
describe "properties of array of casted models" do
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2010-06-18 01:24:49 +02:00
|
|
|
before(:each) do
|
|
|
|
@course = Course.new :title => 'Test Course'
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should allow attribute to be set from an array of objects" do
|
|
|
|
@course.questions = [Question.new(:q => "works?"), Question.new(:q => "Meaning of Life?")]
|
|
|
|
@course.questions.length.should eql(2)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should allow attribute to be set from an array of hashes" do
|
|
|
|
@course.questions = [{:q => "works?"}, {:q => "Meaning of Life?"}]
|
|
|
|
@course.questions.length.should eql(2)
|
|
|
|
@course.questions.last.q.should eql("Meaning of Life?")
|
|
|
|
@course.questions.last.class.should eql(Question) # typecasting
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should allow attribute to be set from hash with ordered keys and objects" do
|
|
|
|
@course.questions = { '0' => Question.new(:q => "Test1"), '1' => Question.new(:q => 'Test2') }
|
|
|
|
@course.questions.length.should eql(2)
|
|
|
|
@course.questions.last.q.should eql('Test2')
|
|
|
|
@course.questions.last.class.should eql(Question)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should allow attribute to be set from hash with ordered keys and sub-hashes" do
|
|
|
|
@course.questions = { '0' => {:q => "Test1"}, '1' => {:q => 'Test2'} }
|
|
|
|
@course.questions.length.should eql(2)
|
|
|
|
@course.questions.last.q.should eql('Test2')
|
|
|
|
@course.questions.last.class.should eql(Question)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should allow attribute to be set from hash with ordered keys and HashWithIndifferentAccess" do
|
|
|
|
# This is similar to what you'd find in an HTML POST parameters
|
|
|
|
hash = HashWithIndifferentAccess.new({ '0' => {:q => "Test1"}, '1' => {:q => 'Test2'} })
|
|
|
|
@course.questions = hash
|
|
|
|
@course.questions.length.should eql(2)
|
|
|
|
@course.questions.last.q.should eql('Test2')
|
|
|
|
@course.questions.last.class.should eql(Question)
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
it "should raise an error if attempting to set single value for array type" do
|
|
|
|
lambda {
|
|
|
|
@course.questions = Question.new(:q => 'test1')
|
|
|
|
}.should raise_error
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2009-05-29 02:56:42 +02:00
|
|
|
describe "a casted model retrieved from the database" do
|
|
|
|
before(:each) do
|
|
|
|
reset_test_db!
|
|
|
|
@cat = Cat.new(:name => 'Stimpy')
|
|
|
|
@cat.favorite_toy = CatToy.new(:name => 'Stinky')
|
|
|
|
@cat.toys << CatToy.new(:name => 'Feather')
|
|
|
|
@cat.toys << CatToy.new(:name => 'Mouse')
|
|
|
|
@cat.save
|
|
|
|
@cat = Cat.get(@cat.id)
|
|
|
|
end
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-05-29 02:56:42 +02:00
|
|
|
describe "as a casted property" do
|
|
|
|
it "should already be casted_by its parent" do
|
|
|
|
@cat.favorite_toy.casted_by.should === @cat
|
|
|
|
end
|
|
|
|
end
|
2010-08-12 05:27:53 +02:00
|
|
|
|
2009-05-29 02:56:42 +02:00
|
|
|
describe "from a casted collection" do
|
|
|
|
it "should already be casted_by its parent" do
|
|
|
|
@cat.toys[0].casted_by.should === @cat
|
|
|
|
@cat.toys[1].casted_by.should === @cat
|
|
|
|
end
|
|
|
|
end
|
2010-03-03 03:18:32 +01:00
|
|
|
end
|
2010-06-16 22:02:12 +02:00
|
|
|
|
|
|
|
describe "Property Class" do
|
|
|
|
|
|
|
|
it "should provide name as string" do
|
2010-06-20 22:01:11 +02:00
|
|
|
property = CouchRest::Model::Property.new(:test, String)
|
2010-06-16 22:02:12 +02:00
|
|
|
property.name.should eql('test')
|
|
|
|
property.to_s.should eql('test')
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should provide class from type" do
|
2010-06-20 22:01:11 +02:00
|
|
|
property = CouchRest::Model::Property.new(:test, String)
|
2010-06-16 22:02:12 +02:00
|
|
|
property.type_class.should eql(String)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should provide base class from type in array" do
|
2010-06-20 22:01:11 +02:00
|
|
|
property = CouchRest::Model::Property.new(:test, [String])
|
2010-06-16 22:02:12 +02:00
|
|
|
property.type_class.should eql(String)
|
|
|
|
end
|
|
|
|
|
2010-06-20 22:01:11 +02:00
|
|
|
it "should raise error if type as string requested" do
|
|
|
|
lambda {
|
|
|
|
property = CouchRest::Model::Property.new(:test, 'String')
|
|
|
|
}.should raise_error
|
2010-06-16 22:02:12 +02:00
|
|
|
end
|
|
|
|
|
2010-06-20 22:01:11 +02:00
|
|
|
it "should leave type nil and return class as nil also" do
|
|
|
|
property = CouchRest::Model::Property.new(:test, nil)
|
2010-06-16 22:02:12 +02:00
|
|
|
property.type.should be_nil
|
2010-06-20 22:01:11 +02:00
|
|
|
property.type_class.should be_nil
|
2010-06-16 22:02:12 +02:00
|
|
|
end
|
|
|
|
|
2010-06-20 22:01:11 +02:00
|
|
|
it "should convert empty type array to [Object]" do
|
|
|
|
property = CouchRest::Model::Property.new(:test, [])
|
|
|
|
property.type_class.should eql(Object)
|
2010-06-16 22:02:12 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should set init method option or leave as 'new'" do
|
|
|
|
# (bad example! Time already typecast)
|
2010-06-20 22:01:11 +02:00
|
|
|
property = CouchRest::Model::Property.new(:test, Time)
|
2010-06-16 22:02:12 +02:00
|
|
|
property.init_method.should eql('new')
|
2010-06-20 22:01:11 +02:00
|
|
|
property = CouchRest::Model::Property.new(:test, Time, :init_method => 'parse')
|
2010-06-16 22:02:12 +02:00
|
|
|
property.init_method.should eql('parse')
|
|
|
|
end
|
|
|
|
|
|
|
|
## Property Casting method. More thoroughly tested earlier.
|
|
|
|
|
|
|
|
describe "casting" do
|
|
|
|
it "should cast a value" do
|
2010-06-20 22:01:11 +02:00
|
|
|
property = CouchRest::Model::Property.new(:test, Date)
|
2010-06-16 22:02:12 +02:00
|
|
|
parent = mock("FooObject")
|
|
|
|
property.cast(parent, "2010-06-16").should eql(Date.new(2010, 6, 16))
|
|
|
|
property.cast_value(parent, "2010-06-16").should eql(Date.new(2010, 6, 16))
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should cast an array of values" do
|
2010-06-20 22:01:11 +02:00
|
|
|
property = CouchRest::Model::Property.new(:test, [Date])
|
2010-06-16 22:02:12 +02:00
|
|
|
parent = mock("FooObject")
|
|
|
|
property.cast(parent, ["2010-06-01", "2010-06-02"]).should eql([Date.new(2010, 6, 1), Date.new(2010, 6, 2)])
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should set a CastedArray on array of Objects" do
|
2010-06-20 22:01:11 +02:00
|
|
|
property = CouchRest::Model::Property.new(:test, [Object])
|
2010-06-16 22:02:12 +02:00
|
|
|
parent = mock("FooObject")
|
2010-06-20 22:01:11 +02:00
|
|
|
property.cast(parent, ["2010-06-01", "2010-06-02"]).class.should eql(CouchRest::Model::CastedArray)
|
2010-06-16 22:02:12 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should not set a CastedArray on array of Strings" do
|
2010-06-20 22:01:11 +02:00
|
|
|
property = CouchRest::Model::Property.new(:test, [String])
|
2010-06-16 22:02:12 +02:00
|
|
|
parent = mock("FooObject")
|
2010-06-20 22:01:11 +02:00
|
|
|
property.cast(parent, ["2010-06-01", "2010-06-02"]).class.should_not eql(CouchRest::Model::CastedArray)
|
2010-06-16 22:02:12 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should raise and error if value is array when type is not" do
|
2010-06-20 22:01:11 +02:00
|
|
|
property = CouchRest::Model::Property.new(:test, Date)
|
2010-06-16 22:02:12 +02:00
|
|
|
parent = mock("FooClass")
|
|
|
|
lambda {
|
|
|
|
cast = property.cast(parent, [Date.new(2010, 6, 1)])
|
|
|
|
}.should raise_error
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
it "should set parent as casted_by object in CastedArray" do
|
2010-06-20 22:01:11 +02:00
|
|
|
property = CouchRest::Model::Property.new(:test, [Object])
|
2010-06-16 22:02:12 +02:00
|
|
|
parent = mock("FooObject")
|
2010-08-12 05:27:53 +02:00
|
|
|
property.cast(parent, ["2010-06-01", "2010-06-02"]).casted_by.should eql(parent)
|
2010-06-16 22:02:12 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should set casted_by on new value" do
|
2010-06-20 22:01:11 +02:00
|
|
|
property = CouchRest::Model::Property.new(:test, CatToy)
|
2010-06-16 22:02:12 +02:00
|
|
|
parent = mock("CatObject")
|
|
|
|
cast = property.cast(parent, {:name => 'catnip'})
|
|
|
|
cast.casted_by.should eql(parent)
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
2010-11-11 01:33:46 +01:00
|
|
|
|