require File.expand_path(File.dirname(__FILE__) + '/spec_helper') describe "HashPersistent::Basic" do context "(before use)" do it "should accept a hash-like store, and a string-like prefix, as class initialisers" do HashPersistent::Basic.setup({}, "_prefix") end it "should reject a non-hash-like store" do lambda {HashPersistent::Basic.setup(1, "_prefix")}.should raise_error(ArgumentError) end it "should reject a non-string-like prefix" do lambda {HashPersistent::Basic.setup({}, Dummy_NoStringRep.new)}.should raise_error(ArgumentError) end end context "(creating objects)" do it "should allow not objects to be created without a key" do HashPersistent::Basic.setup({}, "") lambda{HashPersistent::Basic.new}.should raise_error end it "should allow objects to be created with a key" do HashPersistent::Basic.setup({}, "") lambda{HashPersistent::Basic.new("a_key")}.should_not raise_error end it "should not allow objects to be created with a duplicate key" do HashPersistent::Basic.setup({}, "") HashPersistent::Basic.new("a_key") lambda{HashPersistent::Basic.new("a_key")}.should raise_error end it "should return an object after creation" do HashPersistent::Basic.setup({}, "") new_object = HashPersistent::Basic.new("a_key") new_object.class.should == HashPersistent::Basic new_object.key.should == "a_key" end end context "(retrieving objects)" do it "should not return an object when no objects have been created" do HashPersistent::Basic.setup({}, "") HashPersistent::Basic.find("a_key").should be_nil end it "should return created objects when given the correct key" do HashPersistent::Basic.setup({}, "") HashPersistent::Basic.new("a_key") new_object = HashPersistent::Basic.find("a_key") new_object.class.should == HashPersistent::Basic new_object.key.should == "a_key" end it "should not return an object when given an incorrect key" do HashPersistent::Basic.setup({}, "") HashPersistent::Basic.new("a_key") HashPersistent::Basic.find("another_key").should be_nil end end context "(deleting objects)" do it "should delete an object when asked" do HashPersistent::Basic.setup({}, "") new_object = HashPersistent::Basic.new("a_key") new_object.delete HashPersistent::Basic.find("a_key").should be_nil end it "should not allow an object to be deleted twice" do HashPersistent::Basic.setup({}, "") new_object = HashPersistent::Basic.new("a_key") new_object.delete lambda{new_object.delete}.should raise_error end end context "(key namespacing)" do it "should (transparently) prepend the supplied prefix to the key of the created object" do store = {} HashPersistent::Basic.setup(store, "a_namespace::") new_object = HashPersistent::Basic.new("a_key") new_object.class.should == HashPersistent::Basic new_object.key.should == "a_key" store.should_not have_key("a_key") store.should have_key("a_namespace::a_key") end it "should correctly find objects when given a namespace" do HashPersistent::Basic.setup({}, "a_namespace::") HashPersistent::Basic.new("a_key") new_object = HashPersistent::Basic.find("a_key") new_object.should_not be_nil new_object.key.should == "a_key" end it "should not find objects when mistakenly given a namespaced key" do HashPersistent::Basic.setup({}, "a_namespace::") HashPersistent::Basic.new("a_key") HashPersistent::Basic.find("a_namespace::a_key").should be_nil end it "should correctly delete objects when given a namespace" do store = {} HashPersistent::Basic.setup(store, "a_namespace::") new_object = HashPersistent::Basic.new("a_key") new_object.delete HashPersistent::Basic.find("a_key").should be_nil store.should_not have_key("a_namespace::a_key") end end class Dummy_BasicDerivedClass < HashPersistent::Basic attr_accessor :dummy def initialize(key, dummy) super(key) @dummy = dummy end end context "(derived classes)" do it "should correctly store the full member list of a derived class" do Dummy_BasicDerivedClass.setup({}, "") created_dummy = Dummy_BasicDerivedClass.new("a_key", 123) created_dummy.key.should == "a_key" created_dummy.dummy.should == 123 retrieved_dummy = Dummy_BasicDerivedClass.find("a_key") retrieved_dummy.key.should == "a_key" retrieved_dummy.dummy.should == 123 end end context "(updating objects)" do it "should correctly update members of a derived class" do Dummy_BasicDerivedClass.setup({}, "prefix::") created_dummy = Dummy_BasicDerivedClass.new("a_key", 123) duplicated_dummy = created_dummy.dup duplicated_dummy.dummy = 456 duplicated_dummy.update retrieved_dummy = Dummy_BasicDerivedClass.find("a_key") retrieved_dummy.dummy.should_not == 123 retrieved_dummy.dummy.should == 456 end it "should not allow a deleted object to update" do Dummy_BasicDerivedClass.setup({}, "prefix::") created_dummy = Dummy_BasicDerivedClass.new("a_key", 123) created_dummy.delete created_dummy.dummy = 456 lambda{created_dummy.update}.should raise_error end end context "(restricted hash api)" do it "should use only the restricted hash api provided by moneta" do lambda { Dummy_BasicDerivedClass.setup(Dummy_RestrictedHash.new, "prefix::") created_dummy = Dummy_BasicDerivedClass.new("a_key", 123) duplicated_dummy = created_dummy.dup duplicated_dummy.dummy = 456 duplicated_dummy.update retrieved_dummy = Dummy_BasicDerivedClass.find("a_key") retrieved_dummy.delete }.should_not raise_error end end context "(concurrent access)" do it "should be careful doing various operations" do # What to test here? Duplicate in the other similar classes # Test: Update, update vs delete, delete vs find, update vs find # Eugh, how best to do this? Options: # Subclass Hash and slow the set/get methods down? # Monkey patch the Mutex class to add lock/unlock callbacks? pending end end end