require 'spec_helper' require 'fixtures/address' require 'fixtures/person' class Watch include CouchPotato::Persistence property :time, type: Time property :date, type: Date property :custom, type: [String] property :custom_date, type: [Date] property :custom_address, type: [Address] property :overwritten_read property :overwritten_write property :diameter, type: Float def overwritten_read super.to_s end def overwritten_write=(value) super value.to_s end end class Address2 < Address end class CuckooClock < Watch property :cuckoo end class SportsWatch < Watch property :bpm end describe 'properties' do before(:all) do recreate_db end context 'inheritance' do it 'has access to superclass properties' do expect(CuckooClock.new.cuckoo).to be_nil end it "does not have access to properties of 'sibling classes'" do expect { CuckooClock.new.bpm }.to raise_error(NoMethodError) end end it "should allow me to overwrite read accessor and call super" do expect(Watch.new(:overwritten_read => 1).overwritten_read).to eq('1') end it "should allow me to overwrite write accessor and call super" do expect(Watch.new(:overwritten_write => 1).overwritten_write).to eq('1') end it "should return the property names" do expect(Comment.property_names).to eq([:created_at, :updated_at, :title]) end it "should persist a string" do c = Comment.new :title => 'my title' CouchPotato.database.save_document! c c = CouchPotato.database.load_document c.id expect(c.title).to eq('my title') end it "should persist a number" do c = Comment.new :title => 3 CouchPotato.database.save_document! c c = CouchPotato.database.load_document c.id expect(c.title).to eq(3) end it "should persist a float with leading digits" do w = Watch.new :diameter => "46.5" CouchPotato.database.save_document! w w = CouchPotato.database.load_document w.id expect(w.diameter).to eq(46.5) end it "should persist a float with no leading digits" do w = Watch.new :diameter => ".465" CouchPotato.database.save_document! w w = CouchPotato.database.load_document w.id expect(w.diameter).to eq(0.465) end it "should persist a big decimal" do require 'bigdecimal' c = BigDecimalContainer.new :number => BigDecimal.new( '42.42' ) CouchPotato.database.save_document! c c = CouchPotato.database.load_document c.id expect(c.number).to eq(BigDecimal.new( '42.42' )) end it "should persist a hash" do c = Comment.new :title => {'key' => 'value'} CouchPotato.database.save_document! c c = CouchPotato.database.load_document c.id expect(c.title).to eq({'key' => 'value'}) end it "should persist a HashWithIndifferentAccess" do c = Person.new :information => HashWithIndifferentAccess.new({"key" => "value"}) CouchPotato.database.save_document! c c = CouchPotato.database.load_document c.id expect(c.information).to eq({'key' => 'value'}) end it "should persist subclasses of the specified type" do w = Watch.new(:custom_address => [Address2.new]) CouchPotato.database.save_document! w w = CouchPotato.database.load_document w.id expect(w.custom_address[0]).to be_an_instance_of Address2 end def it_should_persist value c = Comment.new :title => value CouchPotato.database.save_document! c c = CouchPotato.database.load_document c.id expect(c.title.to_json).to eq(value.to_json) # no id provided in embedded object, need to check yourself for content equality expect(c.title).not_to eq(value) end it "should persist a child class" do it_should_persist Child.new('text' => 'some text') end it "should persist a hash with a child class" do it_should_persist 'child' => Child.new('text' => 'some text') end it "should persist an array with a child class" do it_should_persist [Child.new('text' => 'some text')] end it "should persist something very complex" do something_very_complex = [ [ [ { 'what' => [ { 'ever' => Child.new('text' => 'some text') } ], 'number' => 3 }, "string" ], Child.new('text' => 'nothing') ] ] it_should_persist something_very_complex end it "should persist an object" do p = Person.new a = Address.new :city => 'Denver' p.ship_address = a CouchPotato.database.save_document! p p = CouchPotato.database.load_document p.id expect(p.ship_address.to_json).to be === a.to_json end it "should persist null for a null " do p = Person.new p.ship_address = nil CouchPotato.database.save_document! p p = CouchPotato.database.load_document p.id expect(p.ship_address).to be_nil end it "should actually pass the null value down in the JSON document " do p = Person.new p.ship_address = nil db = double(:database) expect(db).to receive(:save_doc) { |attributes| expect(attributes.has_key?(:ship_address)).to eq(true) }.and_return({}) allow(CouchPotato.database).to receive(:couchrest_database).and_return(db) CouchPotato.database.save_document! p end it "should persist false for a false" do p = Person.new p.ship_address = false CouchPotato.database.save_document! p p = CouchPotato.database.load_document p.id expect(p.ship_address).to be_falsey end describe "time properties" do it "should persist a Time as utc" do time = Time.now w = Watch.new :time => time CouchPotato.database.save_document! w w = CouchPotato.database.load_document w.id expect(w.time.to_s).to eq(time.utc.to_s) end it "should parse a string and persist it as utc time" do w = Watch.new :time => '2009-01-01 13:25 +0100' CouchPotato.database.save_document! w w = CouchPotato.database.load_document w.id expect(w.time).to be_a(Time) expect(w.time).to eq(Time.parse('2009-01-01 12:25 +0000')) end it "should store nil" do w = Watch.new :time => nil CouchPotato.database.save_document! w w = CouchPotato.database.load_document w.id expect(w.time).to be_nil end it "should store an empty string as nil" do w = Watch.new :time => '' CouchPotato.database.save_document! w w = CouchPotato.database.load_document w.id expect(w.time).to be_nil end end describe "date properties" do it "should persist a date" do date = Date.today w = Watch.new :date => date CouchPotato.database.save_document! w w = CouchPotato.database.load_document w.id expect(w.date).to eq(date) end it "should parse a string and persist it as a date" do w = Watch.new :date => '2009-01-10' CouchPotato.database.save_document! w w = CouchPotato.database.load_document w.id expect(w.date).to eq(Date.parse('2009-01-10')) end it "should store nil" do w = Watch.new :date => nil CouchPotato.database.save_document! w w = CouchPotato.database.load_document w.id expect(w.date).to be_nil end it "should store an empty string as nil" do w = Watch.new :date => '' CouchPotato.database.save_document! w w = CouchPotato.database.load_document w.id expect(w.date).to be_nil end end describe "array properties" do it "should persist an array of strings" do w = Watch.new :custom => ["moin"] CouchPotato.database.save_document! w w = CouchPotato.database.load_document w.id expect(w.custom).to eql(["moin"]) end it "should persist an array of dates" do date = Date.today w = Watch.new :custom_date => [date] CouchPotato.database.save_document! w w = CouchPotato.database.load_document w.id expect(w.custom_date).to eql([date]) end it "should persist an array of nested documents" do address = Address.new(:verified => 1) w = Watch.new :custom_address => [address] CouchPotato.database.save_document! w w = CouchPotato.database.load_document w.id expect(w.custom_address.to_json).to eql([address].to_json) end it "should handle nil values" do address = Address.new(:verified => 1) w = Watch.new :custom_address => nil CouchPotato.database.save_document! w w = CouchPotato.database.load_document w.id expect(w.custom_address).to eql(nil) end end describe "boolean properties" do it "should persist '0' as false" do a = Address.new a.verified = '0' CouchPotato.database.save_document! a a = CouchPotato.database.load_document a.id expect(a.verified).to be_falsey end it "should persist 0 as false" do a = Address.new a.verified = 0 CouchPotato.database.save_document! a a = CouchPotato.database.load_document a.id expect(a.verified).to be_falsey end it "should persist 'false' as false" do a = Address.new a.verified = 'false' CouchPotato.database.save_document! a a = CouchPotato.database.load_document a.id expect(a.verified).to be_falsey end it "should persist '1' as true" do a = Address.new a.verified = '1' CouchPotato.database.save_document! a a = CouchPotato.database.load_document a.id expect(a.verified).to be_truthy end it "should persist 1 as true" do a = Address.new a.verified = 1 CouchPotato.database.save_document! a a = CouchPotato.database.load_document a.id expect(a.verified).to be_truthy end it "should leave nil as nil" do a = Address.new a.verified = nil CouchPotato.database.save_document! a a = CouchPotato.database.load_document a.id expect(a.verified).to be_nil end end describe "predicate" do it "should return true if property set" do expect(Comment.new(:title => 'title').title?).to be_truthy end it "should return false if property nil" do expect(Comment.new.title?).to be_falsey end it "should return false if property false" do expect(Comment.new(:title => false).title?).to be_falsey end it "should return false if property blank" do expect(Comment.new(:title => '').title?).to be_falsey end end describe "with subclasses" do it "should include properties of superclasses" do expect(CuckooClock.properties.map(&:name)).to include(:time) expect(CuckooClock.properties.map(&:name)).to include(:cuckoo) end it "should return attributes of superclasses" do clock = CuckooClock.new(:time => Time.now, :cuckoo => 'bavarian') expect(clock.attributes[:time]).not_to be_nil expect(clock.attributes[:cuckoo]).to eql('bavarian') end end describe "inspecting an object" do let(:comment) do comment = Comment.new(:title => 'title') comment.instance_eval do @_id = "123456abcdef" @_rev = "1-654321fedcba" end comment end it "should not include change-tracking variables" do expect(comment.inspect).not_to include('title_was') end it "should include the normal persistent variables" do expect(comment.inspect).to include('title: "title"') end it "should include the id" do expect(comment.inspect).to include(%Q{_id: "123456abcdef",}) end it "should include the revision" do expect(comment.inspect).to include(%Q{_rev: "1-654321fedcba",}) end it "should return a complete string" do # stub to work around (un)sorted hash on different rubies allow(comment).to receive(:attributes).and_return([['created_at', ''], ['updated_at', ''], ['title', 'title']]) doc = '#' expect(comment.inspect).to eql(doc) end it "should include complex datatypes fully inspected" do comment.title = {'en' => 'Blog post'} expect(comment.inspect).to include('title: {"en"=>"Blog post"}') comment.title = nil expect(comment.inspect).to include('title: nil') end end end