spec/resource_spec.rb in kissifer-hash-persistent-0.2.2 vs spec/resource_spec.rb in kissifer-hash-persistent-0.3.1

- old
+ new

@@ -23,11 +23,24 @@ self.dummy == other.dummy end end describe "A class that includes HashPersistent::Resource" do - context "(class methods)" do + context "(not initially useful)" do + it "not gain much from the module" do + # Grey-box here... + lambda{ResourceFoo.store}.should raise_error + lambda{ResourceFoo.prefix}.should raise_error + lambda{ResourceFoo.on_save}.should raise_error + lambda{ResourceFoo.on_delete}.should raise_error + lambda{ResourceFoo.find}.should raise_error + + ResourceFoo.new.respond_to?(:key=).should be_false + ResourceFoo.new.respond_to?(:save).should be_false + ResourceFoo.new.respond_to?(:delete).should be_false + end + it "should acquire a persist_to class method" do ResourceFoo.respond_to?(:persist_to).should be_true end end @@ -41,285 +54,302 @@ end it "should reject a non-string-like prefix" do lambda {ResourceFoo.persist_to({}, Dummy_NoStringRep.new)}.should raise_error(ArgumentError) end - end - + + it "should return a sub-class in response to persist_to" do + resource_class = ResourceFoo.persist_to({}, "") + resource_class.should_not == ResourceFoo + resource_class.superclass.should == ResourceFoo + end + + it "should return a different sub-class each time" do + resource_class_1 = ResourceFoo.persist_to({}, "") + resource_class_2 = ResourceFoo.persist_to({}, "") + resource_class_1.should_not == resource_class_2 + end + + it "should return a sub-class that references the correct store and prefix" do + store = Hash.new + store["foo"] = "bar" + prefix = "baz" + resource_class = ResourceFoo.persist_to(store, prefix) + resource_class.store.should == store + resource_class.prefix.should == prefix + end + + it "should return not cross-contaminate the store and prefix of subclasses" do + store_1 = Hash.new + store_1["foo"] = "bar" + prefix_1 = "baz" + resource_class_1 = ResourceFoo.persist_to(store_1, prefix_1) + resource_class_2 = ResourceFoo.persist_to(store_1, prefix_1) + + store_3 = Hash.new + store_3["fred"] = "barney" + prefix_3 = "wilma" + resource_class_3 = ResourceFoo.persist_to(store_3, prefix_3) + + resource_class_1.store.should == resource_class_2.store + resource_class_1.prefix.should == resource_class_2.prefix + + resource_class_1.store.should_not == resource_class_3.store + resource_class_1.prefix.should_not == resource_class_3.prefix + + resource_class_1.store.should == store_1 + resource_class_2.store.should == store_1 + resource_class_3.store.should == store_3 + + resource_class_1.prefix.should == prefix_1 + resource_class_2.prefix.should == prefix_1 + resource_class_3.prefix.should == prefix_3 + end + end + context "(an instance that has not been saved)" do + before(:each) do + @resource_class = ResourceFoo.persist_to({}, "") + end + it "should maintain a key attribute" do - ResourceFoo.new.respond_to?(:key).should be_true - ResourceFoo.new.respond_to?(:key=).should be_true + @resource_class.new.respond_to?(:key).should be_true + @resource_class.new.respond_to?(:key=).should be_true end it "should respond to a save method" do - ResourceFoo.new.respond_to?(:save).should be_true + @resource_class.new.respond_to?(:save).should be_true end it "should respond to a delete method" do - ResourceFoo.new.respond_to?(:delete).should be_true + @resource_class.new.respond_to?(:delete).should be_true end it "should not save unless the key has been explictly set" do - lambda{ResourceFoo.new.save}.should raise_error + lambda{@resource_class.new.save}.should raise_error end it "should not delete unless the key has been explictly set" do - lambda{ResourceFoo.new.delete}.should raise_error + lambda{@resource_class.new.delete}.should raise_error end it "should not complain when deleted, even after a key is set" do - ResourceFoo.persist_to(Hash.new, "") - resource = ResourceFoo.new + resource = @resource_class.new resource.key = "fred" lambda{resource.delete}.should_not raise_error end it "should not be findable via its key" do - ResourceFoo.persist_to(Hash.new, "") - resource = ResourceFoo.new + resource = @resource_class.new resource.key = "fred" - ResourceFoo.find("fred").should == nil - ResourceFoo.find("barney").should == nil + @resource_class.find("fred").should == nil + @resource_class.find("barney").should == nil end end context "(an instance that has been saved)" do + before(:each) do + @resource_class = ResourceFoo.persist_to({}, "") + @resource_class_with_state = ResourceFooWithState.persist_to({}, "") + end + it "should be findable via its key" do - ResourceFoo.persist_to(Hash.new, "") - resource = ResourceFoo.new + resource = @resource_class.new resource.key = "fred" resource.save - ResourceFoo.find("fred").should_not be_nil + @resource_class.find("fred").should_not be_nil end it "should correctly recover all of its state" do - ResourceFooWithState.persist_to(Hash.new, "") - resource = ResourceFooWithState.new + resource = @resource_class_with_state.new resource.key = "fred" resource.dummy = ["something random", {}] resource.save resource_dup = resource.dup - ResourceFooWithState.find("fred").should == resource_dup + @resource_class_with_state.find("fred").should == resource_dup end it "should be deletable" do - ResourceFoo.persist_to(Hash.new, "") - resource = ResourceFoo.new + resource = @resource_class.new resource.key = "fred" resource.save lambda{resource.delete}.should_not raise_error end it "should save a new state when asked" do - ResourceFooWithState.persist_to(Hash.new, "") - resource = ResourceFooWithState.new + resource = @resource_class_with_state.new resource.key = "fred" resource.dummy = ["something random", {}] resource.save resource_dup_1 = resource.dup resource.dummy = ["something else random", 1] resource.save resource_dup_2 = resource.dup - ResourceFooWithState.find("fred").should_not == resource_dup_1 - ResourceFooWithState.find("fred").should == resource_dup_2 + @resource_class_with_state.find("fred").should_not == resource_dup_1 + @resource_class_with_state.find("fred").should == resource_dup_2 end end context "(an instance that has been saved and then deleted)" do + before(:each) do + @resource_class = ResourceFoo.persist_to({}, "") + end + it "should not be findable via its key" do - ResourceFoo.persist_to(Hash.new, "") - resource = ResourceFoo.new + resource = @resource_class.new resource.key = "fred" resource.save resource.delete - ResourceFoo.find("fred").should == nil + @resource_class.find("fred").should == nil end it "should not complain when deleted" do - ResourceFoo.persist_to(Hash.new, "") - resource = ResourceFoo.new + resource = @resource_class.new resource.key = "fred" resource.save resource.delete lambda{resource.delete}.should_not raise_error end end context "(use of prefix to namespace keys)" do + before(:each) do + @resource_class = ResourceFoo.persist_to({}, "a_random_namespace::") + end + it "should (transparently) prepend the supplied prefix to the key of the saved instance" do - store = Hash.new - ResourceFoo.persist_to(store, "a_random_namespace::") - resource = ResourceFoo.new + resource = @resource_class.new resource.key = "fred" resource.save - store.should_not have_key("fred") - store.should have_key("a_random_namespace::fred") + @resource_class.store.should_not have_key("fred") + @resource_class.store.should have_key("a_random_namespace::fred") end it "should find instances when using a namespace, using only the key" do - store = Hash.new - ResourceFoo.persist_to(store, "a_random_namespace::") - resource = ResourceFoo.new + resource = @resource_class.new resource.key = "fred" resource.save - ResourceFoo.find("fred").should_not == nil + @resource_class.find("fred").should_not == nil end it "should not find instances when mistakenly given a namespaced key" do - store = Hash.new - ResourceFoo.persist_to(store, "a_random_namespace::") - resource = ResourceFoo.new + resource = @resource_class.new resource.key = "fred" resource.save - ResourceFoo.find("a_random_namespace::fred").should == nil + @resource_class.find("a_random_namespace::fred").should == nil end it "should correctly delete an instance from the store when using a prefix" do - store = Hash.new - ResourceFoo.persist_to(store, "a_random_namespace::") - resource = ResourceFoo.new + resource = @resource_class.new resource.key = "fred" resource.save resource.delete - ResourceFoo.find("fred").should == nil + @resource_class.find("fred").should == nil + @resource_class.store.should == {} end end context "(use of store)" do it "should correctly delete items from the store" do - store = Hash.new - ResourceFoo.persist_to(store, "") - resource_1 = ResourceFoo.new + @resource_class = ResourceFoo.persist_to({}, "") + resource_1 = @resource_class.new resource_1.key = "fred" resource_1.save - resource_2 = ResourceFoo.new + resource_2 = @resource_class.new resource_2.key = "barney" resource_2.save - store.should_not == Hash.new + @resource_class.store.should_not == {} resource_1.delete + @resource_class.store.should_not == {} + resource_2.delete - store.should == Hash.new + @resource_class.store.should == {} end end - + context "(use of restricted hash api)" do it "should use only the restricted hash api provided by moneta" do lambda { - ResourceFooWithState.persist_to(Dummy_RestrictedHash.new, "prefix::") - resource_1 = ResourceFooWithState.new + @resource_class = ResourceFooWithState.persist_to(Dummy_RestrictedHash.new, "prefix::") + resource_1 = @resource_class.new resource_1.key = "fred" resource_1.dummy = ["barney"] resource_1.save - ResourceFooWithState.find("fred").delete + @resource_class.find("fred").delete }.should_not raise_error end end - - context "(default store)" do - it "should function with a vdefault store/prefix if none is supplied" do - # This is implicitly tested elsewhere. Which makes this test documentation, I guess - resource_1 = ResourceFooOnlyUsedOnce.new - resource_1.key = "fred" - resource_1.dummy = ["barney"] - resource_1.save - ResourceFooOnlyUsedOnce.find("fred").should == resource_1.dup - lambda {ResourceFooOnlyUsedOnce.find("fred").delete}.should_not raise_error - end - end - - context "(multiple classes using module)" do - # TODO: should check the callbacks here? Seems over the top... - it "should not cross-contaminate classes that include the module" do - store_1 = Hash.new - ResourceFoo.persist_to(store_1, "") - store_2 = Hash.new - ResourceFooWithState.persist_to(store_2, "prefix::") - - store_1.should == Hash.new - store_2.should == Hash.new - - resource_1 = ResourceFoo.new - resource_1.key = "1" - resource_1.save - - store_1.should_not == Hash.new - store_2.should == Hash.new - store_1.should have_key("1") - store_1.should_not have_key("prefix::1") - - resource_1.delete - - store_1.should == Hash.new - store_2.should == Hash.new - - resource_2 = ResourceFooWithState.new - resource_2.key = "2" - resource_2.save - - store_1.should == Hash.new - store_2.should_not == Hash.new - store_2.should have_key("prefix::2") - store_2.should_not have_key("2") - - resource_2.delete - - store_1.should == Hash.new - store_2.should == Hash.new - end - end context "(callbacks)" do it "should allow a class level callback to be set and retrieved for save events" do - ResourceFoo.on_save.should == nil - lambda{ResourceFoo.on_save do + @resource_class = ResourceFoo.persist_to({}, "") + @resource_class.on_save.should == nil + + @resource_class.on_save do "thing" - end}.should_not raise_error - ResourceFoo.on_save.call.should == "thing" - lambda{ResourceFoo.on_save(1)}.should raise_error + end + @resource_class.on_save.call.should == "thing" end it "should allow a class level callback to be set and retrieved for delete events" do - ResourceFoo.on_delete.should == nil - lambda{ResourceFoo.on_delete do + @resource_class = ResourceFoo.persist_to({}, "") + @resource_class.on_delete.should == nil + @resource_class.on_delete do "thing" - end}.should_not raise_error - ResourceFoo.on_delete.call.should == "thing" - lambda{ResourceFoo.on_delete(1)}.should raise_error + end + @resource_class.on_delete.call.should == "thing" end it "should yield an instance to the save callback when the instance is saved" do + @resource_class = ResourceFoo.persist_to({}, "") yielded_instance = nil - ResourceFoo.on_save do |yielded| + @resource_class.on_save do |yielded| yielded_instance = yielded end - instance = ResourceFoo.new - instance.key = "1" + instance = @resource_class.new + instance.key = "fah" instance.save yielded_instance.should_not == nil yielded_instance.should == instance end it "should yield an instance to the delete callback when the instance is deleted" do + @resource_class = ResourceFoo.persist_to({}, "") yielded_instance = nil - ResourceFoo.on_delete do |yielded| + @resource_class.on_delete do |yielded| yielded_instance = yielded end - instance = ResourceFoo.new - instance.key = "1" + instance = @resource_class.new + instance.key = "bah" instance.save instance.delete yielded_instance.should_not == nil yielded_instance.should == instance end + it "should maintain separate callbacks for each created subclass" do + @resource_class_1 = ResourceFoo.persist_to({}, "") + @resource_class_2 = ResourceFoo.persist_to({}, "") + + @resource_class_1.on_save do "on_save_1" end + @resource_class_1.on_delete do "on_delete_1" end + + @resource_class_2.on_save do "on_save_2" end + @resource_class_2.on_delete do "on_delete_2" end + + @resource_class_1.on_delete.call.should == "on_delete_1" + @resource_class_1.on_save.call.should == "on_save_1" + + @resource_class_2.on_delete.call.should == "on_delete_2" + @resource_class_2.on_save.call.should == "on_save_2" + end end end