spec/document_spec.rb in mongodoc-0.1.2 vs spec/document_spec.rb in mongodoc-0.2.0
- old
+ new
@@ -1,78 +1,93 @@
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
describe "MongoDoc::Document" do
context "satisfies form_for requirements" do
- class FormForTest < MongoDoc::Document
+ class FormForTest
+ include MongoDoc::Document
+
+ key :data
end
-
+
before do
@doc = FormForTest.new
@doc._id = '1'
end
-
+
it "#id returns the _id" do
@doc.id.should == @doc._id
end
-
+
it "#to_param returns the _id" do
@doc.to_param.should == @doc._id
end
-
+
context "#new_record?" do
it "is true when the object does not have an _id" do
@doc._id = nil
@doc.should be_new_record
end
-
+
it "is false when the object has an id" do
@doc.should_not be_new_record
end
end
+
+ context "attributes" do
+ it "has an initialize method that takes a hash" do
+ data = 'data'
+ FormForTest.new(:data => data).data.should == data
+ end
+
+ it "can set attributes from a hash" do
+ test = FormForTest.new
+ data = 'data'
+ test.attributes = {:data => data}
+ test.data.should == data
+ end
+
+ it "returns all its attributes" do
+ data = 'data'
+ test = FormForTest.new(:data => data)
+ test.attributes.should == {:data => data}
+ end
+ end
end
context "validations" do
- class SimpleValidationTest < MongoDoc::Document
+ class SimpleValidationTest
+ include MongoDoc::Document
+
key :data
validates_presence_of :data
end
- it "are part of Base" do
- Validatable.should === MongoDoc::Document.new
+ it "are included by MongoDoc::Document" do
+ Validatable.should === SimpleValidationTest.new
end
it "valid? fails when a document is invalid" do
doc = SimpleValidationTest.new
doc.should_not be_valid
doc.should have(1).error_on(:data)
end
end
- context ".criteria" do
- class CriteriaTest < MongoDoc::Document
- key :data
- end
-
- it "creates a new criteria for the document" do
- CriteriaTest.criteria.should be_a_kind_of(MongoDoc::Criteria)
- end
-
- it "sets the criteria klass" do
- CriteriaTest.criteria.klass.should == CriteriaTest
- end
- end
-
context "saving" do
- class SaveRoot < MongoDoc::Document
+ class SaveRoot
+ include MongoDoc::Document
+
has_many :save_children
end
-
- class SaveChild < MongoDoc::Document
+
+ class SaveChild
+ include MongoDoc::Document
+
key :data
end
-
+
before do
@root = SaveRoot.new
@root.stub(:_save)
@child = SaveChild.new
@root.save_children << @child
@@ -82,17 +97,17 @@
it "delegates to the root" do
validate = true
@root.should_receive(:save).with(validate)
@child.save(validate)
end
-
+
context "when validating" do
it "validates" do
@root.should_receive(:valid?)
@root.save(true)
end
-
+
context "and valid" do
it "delegates to _save" do
@root.should_receive(:_save).with(false)
@root.save(true)
end
@@ -102,25 +117,25 @@
@root.stub(:valid?).and_return(true)
@root.should_receive(:_save).and_return(id)
@root.save(true).should == id
end
end
-
+
context "and invalid" do
it "does not call _save" do
@root.stub(:valid?).and_return(false)
@root.should_not_receive(:_save)
@root.save(true)
end
-
+
it "returns false" do
@root.stub(:valid?).and_return(false)
@root.save(true).should be_false
end
end
end
-
+
context "when not validating" do
it "does not validate" do
@root.should_not_receive(:valid?)
@root.save(false)
end
@@ -135,22 +150,22 @@
@root.stub(:_save).and_return(id)
@root.save(false).should == id
end
end
end
-
+
context "#save!" do
it "delegates to the root" do
@root.should_receive(:save!)
@child.save!
end
-
+
it "validates" do
@root.should_receive(:valid?).and_return(true)
@root.save!
end
-
+
it "returns the result of _save if valid" do
id = 'id'
@root.stub(:valid?).and_return(true)
@root.should_receive(:_save).with(true).and_return(id)
@root.save!.should == id
@@ -162,27 +177,28 @@
@root.save!
end.should raise_error(MongoDoc::DocumentInvalidError)
end
end
end
-
+
context "#_save" do
- class SaveTest < MongoDoc::Document
+ class SaveTest
+ include MongoDoc::Document
end
-
+
before do
@collection = stub('collection')
@doc = SaveTest.new
@doc.stub(:_collection).and_return(@collection)
end
-
+
it "delegates to the collection save" do
safe = true
@collection.should_receive(:save)
@doc.send(:_save, safe)
end
-
+
it "sets the _id of the document" do
id = 'id'
@collection.stub(:save).and_return(id)
@doc.send(:_save, true)
@doc._id.should == id
@@ -194,173 +210,191 @@
@doc.send(:_save, true).should == id
end
end
context "creating" do
- class CreateTest < MongoDoc::Document
+ class CreateTest
+ include MongoDoc::Document
+
key :data
validates_presence_of :data
end
before do
@value = 'value'
CreateTest.stub(:_create).and_return(true)
end
-
+
context ".create" do
it "creates a new document" do
obj = CreateTest.new
CreateTest.should_receive(:new).and_return(obj)
CreateTest.create
end
-
+
it "delegates to _create with safe => false" do
obj = CreateTest.new(:data => @value)
CreateTest.stub(:new).and_return(obj)
CreateTest.should_receive(:_create).with(obj, false).and_return(true)
CreateTest.create(:data => @value)
end
-
+
it "sets the passed attributes" do
CreateTest.create(:data => @value).data.should == @value
end
it "returns a valid document" do
CreateTest.should === CreateTest.create(:data => @value)
end
-
+
it "validates" do
CreateTest.create.errors.should_not be_empty
end
it "returns an invalid document" do
CreateTest.should === CreateTest.create
end
end
-
+
context ".create!" do
it "creates a new document" do
obj = CreateTest.new
CreateTest.should_receive(:new).and_return(obj)
CreateTest.create! rescue nil
end
-
+
it "delegates to _create with safe => true" do
obj = CreateTest.new(:data => @value)
CreateTest.stub(:new).and_return(obj)
CreateTest.should_receive(:_create).with(obj, true).and_return(true)
CreateTest.create!(:data => @value)
end
-
+
it "sets the passed attributes" do
CreateTest.create!(:data => @value).data.should == @value
end
it "returns a valid document" do
CreateTest.should === CreateTest.create!(:data => @value)
end
-
+
it "raises when invalid" do
expect do
CreateTest.create!
end.should raise_error(MongoDoc::DocumentInvalidError)
end
end
end
context "#_create" do
- class CreateTest < MongoDoc::Document
+ class CreateTest
+ include MongoDoc::Document
end
-
+
before do
@collection = stub('collection')
@collection.stub(:insert)
@doc = CreateTest.new
CreateTest.stub(:collection).and_return(@collection)
end
-
+
it "delegates to the collection insert with safe" do
safe = true
@collection.should_receive(:insert).with(@doc, hash_including(:safe => safe))
CreateTest.send(:_create, @doc, safe)
end
-
+
it "sets the _id of the document" do
id = 'id'
@collection.stub(:insert).and_return(id)
CreateTest.send(:_create, @doc, false)
@doc._id.should == id
end
-
+
it "returns the _id" do
id = 'id'
@collection.stub(:insert).and_return(id)
CreateTest.send(:_create, @doc, false).should == id
- end
+ end
end
context "updating attributes" do
- class UpdateAttributesRoot < MongoDoc::Document
+ class UpdateAttributesRoot
+ include MongoDoc::Document
+
has_one :update_attribute_child
end
-
- class UpdateAttributesChild < MongoDoc::Document
+
+ class UpdateAttributesChild
+ include MongoDoc::Document
+
key :data
end
-
+
before do
@data = 'data'
@doc = UpdateAttributesChild.new
UpdateAttributesRoot.new.update_attribute_child = @doc
@attrs = {:data => @data}
@path_attrs = {'update_attribute_child.data' => @data}
- @doc.stub(:_propose_update_attributes)
+ @doc.stub(:_naive_update_attributes)
end
context "#update_attributes" do
+
it "sets the attributes" do
@doc.update_attributes(@attrs)
@doc.data.should == @data
end
it "normalizes the attributes to the parent" do
- @doc.should_receive(:path_to_root)
+ @doc.should_receive(:_path_to_root)
@doc.update_attributes(@attrs)
end
it "validates" do
@doc.should_receive(:valid?)
@doc.update_attributes(@attrs)
end
-
+
it "returns false if the object is not valid" do
@doc.stub(:valid?).and_return(false)
@doc.update_attributes(@attrs).should be_false
end
-
+
context "if valid" do
- it "delegates to _propose_update_attributes" do
- @doc.should_receive(:_propose_update_attributes).with(@doc, @path_attrs, false)
- @doc.update_attributes(@attrs)
+ context "and strict" do
+ it "delegates to _strict_update_attributes" do
+ strict_attrs = @attrs.merge(:__strict__ => true)
+ @doc.should_receive(:_strict_update_attributes).with(@path_attrs, false)
+ @doc.update_attributes(strict_attrs)
+ end
end
- it "returns the result of _propose_update_attributes" do
+ context "and naive" do
+ it "delegates to _naive_update_attributes" do
+ @doc.should_receive(:_naive_update_attributes).with(@path_attrs, false)
+ @doc.update_attributes(@attrs)
+ end
+ end
+
+ it "returns the result of _naive_update_attributes" do
result = 'check'
- @doc.stub(:_propose_update_attributes).and_return(result)
+ @doc.stub(:_naive_update_attributes).and_return(result)
@doc.update_attributes(@attrs).should == result
end
end
end
-
+
context "#update_attributes!" do
it "sets the attributes" do
@doc.update_attributes!(@attrs)
@doc.data.should == @data
end
it "normalizes the attributes to the parent" do
- @doc.should_receive(:path_to_root)
+ @doc.should_receive(:_path_to_root)
@doc.update_attributes!(@attrs)
end
it "validates" do
@doc.should_receive(:valid?).and_return(true)
@@ -373,201 +407,135 @@
@doc.update_attributes!(@attrs)
end.should raise_error(MongoDoc::DocumentInvalidError)
end
context "if valid" do
- it "delegates to _propose_update_attributes with safe == true" do
- @doc.should_receive(:_propose_update_attributes).with(@doc, @path_attrs, true)
- @doc.update_attributes!(@attrs)
+ context "and strict" do
+ it "delegates to _strict_update_attributes with safe == true" do
+ strict_attrs = @attrs.merge(:__strict__ => true)
+ @doc.should_receive(:_strict_update_attributes).with(@path_attrs, true)
+ @doc.update_attributes!(strict_attrs)
+ end
end
-
- it "returns the result of _propose_update_attributes" do
+
+ context "and naive" do
+ it "delegates to _naive_update_attributes with safe == true" do
+ @doc.should_receive(:_naive_update_attributes).with(@path_attrs, true)
+ @doc.update_attributes!(@attrs)
+ end
+ end
+
+ it "returns the result of _naive_update_attributes" do
result = 'check'
- @doc.stub(:_propose_update_attributes).and_return(result)
+ @doc.stub(:_naive_update_attributes).and_return(result)
@doc.update_attributes!(@attrs).should == result
end
end
end
end
-
- context "#_propose_update_attributes" do
- class ProposeUpdateAttributes < MongoDoc::Document
- end
- before do
- @attrs = {:data => 1}
- @safe = true
+ context "#_naive_update_attributes" do
+ class NaiveUpdateAttributes
+ include MongoDoc::Document
end
-
- context "when not a child" do
- before do
- @obj = ProposeUpdateAttributes.new
- end
-
- it "delegates to _update_attributes when not a child" do
- @obj.should_receive(:_update_attributes).with(@attrs, @safe)
- @obj.send(:_propose_update_attributes, @obj, @attrs, @safe)
- end
-
- it "returns the results of _update_attributes" do
- result = 'check'
- @obj.stub(:_update_attributes).and_return(result)
- @obj.send(:_propose_update_attributes, @obj, @attrs, @safe).should == result
- end
- end
-
- context "when a child" do
- before do
- @obj = ProposeUpdateAttributes.new
- @parent = stub('parent')
- @obj._parent = @parent
- end
-
- it "delegates to the parent when a child" do
- @parent.should_receive(:_propose_update_attributes).with(@obj, @attrs, @safe)
- @obj.send(:_propose_update_attributes, @obj, @attrs, @safe)
- end
-
- it "returns the results of the parent's _propose_update_attributes" do
- result = 'check'
- @parent.stub(:_propose_update_attributes).and_return(result)
- @obj.send(:_propose_update_attributes, @obj, @attrs, @safe).should == result
- end
- end
- end
- context "#_update_attributes" do
- class UpdateAttributes < MongoDoc::Document
- end
-
before do
+ @id = 'id'
+ @attrs = {:data => 'data'}
+ @safe = false
+ @doc = NaiveUpdateAttributes.new
+ @doc.stub(:_id).and_return(@id)
@collection = stub('collection')
@collection.stub(:update)
- @doc = UpdateAttributes.new
- @doc.stub(:_id).and_return(@id)
- UpdateAttributes.stub(:collection).and_return(@collection)
- @attrs = {:data => 'value'}
+ @doc.stub(:_collection).and_return(@collection)
end
-
- it "uses the set modifier for the attributes" do
- safe = true
- MongoDoc::Query.should_receive(:set_modifier).with(@attrs)
- @collection.stub(:update)
- @doc.send(:_update_attributes, @attrs, safe)
- end
- it "delegates to the collection update with safe" do
- safe = true
- @collection.should_receive(:update).with({'_id' => @id}, MongoDoc::Query.set_modifier(@attrs), {:safe => safe})
- @doc.send(:_update_attributes, @attrs, safe)
+ it "calls update on the collection without a root" do
+ @collection.should_receive(:update).with({'_id' => @id}, MongoDoc::Query.set_modifier(@attrs), {:safe => @safe})
+ @doc.send(:_naive_update_attributes, @attrs, @safe)
end
- it "returns the result" do
- result = 'check'
- @collection.stub(:update).and_return(result)
- @doc.send(:_update_attributes, @attrs, true)
- end
- end
-
- context "from a nested document" do
- class NestedDocsRoot < MongoDoc::Document
- has_many :nested_children
+ it "with a root, calls _naive_update_attributes on the root" do
+ root = NaiveUpdateAttributes.new
+ @doc.stub(:_root).and_return(root)
+ root.should_receive(:_naive_update_attributes).with(@attrs, @safe)
+ @doc.send(:_naive_update_attributes, @attrs, @safe)
end
+ end
- class NestedChild < MongoDoc::Document
- has_one :leaf
+ context "#_strict_update_attributes" do
+ class StrictUpdateAttributes
+ include MongoDoc::Document
end
- class LeafDoc < MongoDoc::Document
- key :data
+ before do
+ @id = 'id'
+ @attrs = {:data => 'data'}
+ @selector = {'selector' => 'selector'}
+ @safe = false
+ @doc = StrictUpdateAttributes.new
+ @doc.stub(:_id).and_return(@id)
+ @collection = stub('collection')
+ @collection.stub(:update)
+ @doc.stub(:_collection).and_return(@collection)
end
- context "#save" do
- before do
- @leaf = LeafDoc.new
- @root = NestedDocsRoot.new(:nested_children => [NestedChild.new(:leaf => @leaf)])
+ context "without a root" do
+ it "calls update on the collection" do
+ @collection.should_receive(:update).with({'_id' => @id}.merge(@selector), MongoDoc::Query.set_modifier(@attrs), :safe => @safe)
+ @doc.send(:_strict_update_attributes, @attrs, @safe, @selector)
end
-
- it "calls the root document's save" do
- @root.should_receive(:save).with(true)
- @leaf.save
- end
-
- it "(with bang!) calls the root documents save!" do
- @root.should_receive(:save!)
- @leaf.save!
- end
end
- context "with no has_many, update_attributes" do
+ context "with a root" do
before do
- @leaf = LeafDoc.new
- @root = NestedChild.new(:leaf => @leaf)
+ @root = StrictUpdateAttributes.new
+ @root.stub(:_collection).and_return(@collection)
+ @doc.stub(:_root).and_return(@root)
+ @doc.stub(:_selector_path_to_root).and_return({'path._id' => @id})
end
- it "calls the root document's _update_attributes with a full attribute path and not safe" do
- @root.should_receive(:_update_attributes).with({'leaf.data' => 'data'}, false)
- @leaf.update_attributes(:data => 'data')
+ it "calls _selector_path_to_root on our id" do
+ @doc.should_receive(:_selector_path_to_root).with('_id' => @id).and_return({'path._id' => @id})
+ @doc.send(:_strict_update_attributes, @attrs, @safe)
end
- it "(with bang!) calls the root document's _update_attributes with a full attribute path and safe" do
- @root.should_receive(:_update_attributes).with({'leaf.data' => 'data'}, true)
- @leaf.update_attributes!(:data => 'data')
+ it "calls _strict_update_attributes on the root with our selector" do
+ @root.should_receive(:_strict_update_attributes).with(@attrs, @safe, 'path._id' => @id)
+ @doc.send(:_strict_update_attributes, @attrs, @safe)
end
end
-
- context "with has_many, update_attributes" do
- before do
- @leaf = LeafDoc.new
- NestedDocsRoot.new(:nested_children => [NestedChild.new(:leaf => @leaf)])
- end
-
- it "returns false" do
- @leaf.update_attributes(:data => 'data').should be_false
- end
-
- it "sets an error on base" do
- @leaf.update_attributes(:data => 'data')
- @leaf.errors[:base].should_not be_nil
- end
-
- it "(with bang!) returns false" do
- @leaf.update_attributes!(:data => 'data').should be_false
- end
-
- it "(with bang!) sets an error on base" do
- @leaf.update_attributes(:data => 'data')
- @leaf.errors[:base].should_not be_nil
- end
- end
-
end
describe "bson" do
- class BSONTest < MongoDoc::Document
+ class BSONTest
+ include MongoDoc::Document
+
key :other
end
class BSONDerived < BSONTest
+ include MongoDoc::Document
+
key :derived
end
-
+
class OtherObject
attr_accessor :value
end
-
+
before do
@value = 'value'
@other = OtherObject.new
@other.value = @value
@doc = BSONTest.new(:other => @other)
end
it "encodes the class for the object" do
@doc.to_bson[MongoDoc::BSON::CLASS_KEY].should == BSONTest.name
end
-
+
it "renders a json representation of the object" do
@doc.to_bson.should be_bson_eql({MongoDoc::BSON::CLASS_KEY => BSONTest.name, "other" => {MongoDoc::BSON::CLASS_KEY => OtherObject.name, "value" => @value}})
end
it "includes the _id of the object" do
@@ -592,15 +560,19 @@
MongoDoc::BSON.decode(@doc.to_bson).other.should be_kind_of(OtherObject)
end
context "associations" do
context "has_one" do
- class TestHasOneBsonDoc < MongoDoc::Document
+ class TestHasOneBsonDoc
+ include MongoDoc::Document
+
has_one :subdoc
end
- class SubHasOneBsonDoc < MongoDoc::Document
+ class SubHasOneBsonDoc
+ include MongoDoc::Document
+
key :attr
end
it "#to_bson renders a bson representation of the document" do
doc = TestHasOneBsonDoc.new
@@ -619,15 +591,18 @@
end
end
context "has_many" do
- class SubHasManyBsonDoc < MongoDoc::Document
+ class SubHasManyBsonDoc
+ include MongoDoc::Document
+
key :attr
end
- class TestHasManyBsonDoc < MongoDoc::Document
+ class TestHasManyBsonDoc
+ include MongoDoc::Document
has_many :subdoc, :class_name => 'SubHasManyBsonDoc'
end
it "#to_bson renders a bson representation of the document" do
doc = TestHasManyBsonDoc.new
@@ -652,17 +627,11 @@
end
end
end
context "misc class methods" do
- class ClassMethods < MongoDoc::Document
- end
-
- it ".count calls the collection count" do
- collection = stub('collection')
- ClassMethods.stub(:collection).and_return(collection)
- collection.should_receive(:count).and_return(1)
- ClassMethods.count
+ class ClassMethods
+ include MongoDoc::Document
end
it ".collection_name returns the name of the collection for this class" do
ClassMethods.collection_name.should == ClassMethods.to_s.tableize.gsub('/', '.')
end