Permalink
Browse files

Implement deep-dup for MentalModel::Collection

[fixes #8]
  • Loading branch information...
1 parent 2c99b21 commit 43e7341f7bedce7b1caf7d39e25b216d39c08e05 @jwilger committed Mar 28, 2012
Showing with 40 additions and 19 deletions.
  1. +3 −6 lib/kookaburra.rb
  2. +9 −1 lib/kookaburra/mental_model.rb
  3. +22 −0 spec/kookaburra/mental_model_spec.rb
  4. +6 −12 spec/kookaburra_spec.rb
View
@@ -62,10 +62,7 @@ def ui
@ui ||= @ui_driver_class.new(@configuration)
end
- # Returns a frozen copy of the specified {MentalModel::Collection}.
- # However, this is neither a deep copy nor a deep freeze, so it is possible
- # that you could modify data outside of your GivenDriver or UIDriver. Just
- # don't do that. Trust me.
+ # Returns a deep-dup of the specified {MentalModel::Collection}.
#
# This access is provided so that you can reference the current mental model
# within your test implementation and make assertions about the state
@@ -74,10 +71,10 @@ def ui
# @example
# given.a_widget(:foo)
# ui.create_a_new_widget(:bar)
- # ui.widget_list.widgets.should == k.get_data(:widgets).slice(:foo, :bar)
+ # ui.widget_list.widgets.should == k.get_data(:widgets).values_at(:foo, :bar)
#
# @return [Kookaburra::MentalModel::Collection]
def get_data(collection_name)
- @configuration.mental_model.send(collection_name).dup.freeze
+ @configuration.mental_model.send(collection_name).dup
end
end
@@ -1,5 +1,6 @@
require 'delegate'
require 'kookaburra/exceptions'
+require 'active_support/core_ext/hash'
class Kookaburra
# Each instance of {Kookaburra} has its own instance of MentalModel. This object
@@ -50,11 +51,12 @@ def respond_to?
class Collection < SimpleDelegator
# @param [String] name The name of the collection. Used to provide
# helpful error messages when unknown keys are accessed.
- def initialize(name)
+ def initialize(name, init_data = nil)
@name = name
data = Hash.new do |hash, key|
raise UnknownKeyError, "Can't find mental_model.#{@name}[#{key.inspect}]. Did you forget to set it?"
end
+ data.merge!(init_data) unless init_data.nil?
super(data)
end
@@ -104,6 +106,12 @@ def delete_if(&block)
move = lambda { |k,v| deleted[k] = v; true }
super { |k,v| block.call(k,v) && move.call(k,v) }
end
+
+ def dup
+ new_data = {}.merge(self)
+ new_data = Marshal.load(Marshal.dump(new_data))
+ self.class.new(@name, new_data)
+ end
end
end
end
@@ -90,5 +90,27 @@
lambda { collection[:foo] }.should \
raise_error(Kookaburra::UnknownKeyError, "Can't find mental_model.widgets[:foo]. Did you forget to set it?")
end
+
+ describe '#dup' do
+ it 'returns a different object' do
+ new_collection = collection.dup
+ new_collection.__id__.should_not === collection.__id__
+ end
+
+ it 'returns an object with equal values to the original' do
+ collection[:foo] = :bar
+ collection[:baz] = :bam
+ new_collection = collection.dup
+ new_collection[:foo].should == :bar
+ new_collection[:baz].should == :bam
+ end
+
+ it 'is a deep copy' do
+ collection[:foo] = {:bar => 'baz'}
+ new_collection = collection.dup
+ new_collection[:foo][:bar].should == 'baz'
+ new_collection[:foo][:bar].__id__.should_not === collection[:foo][:bar].__id__
+ end
+ end
end
end
View
@@ -30,18 +30,12 @@
end
describe '#get_data' do
- it 'returns a equivalent copy of the test data collection specified' do
- foos = {:spam => 'ham'}
- configuration.stub!(:mental_model => stub(:foos => foos))
- k.get_data(:foos).should == foos
- end
-
- it 'does not return the same object that is the test data collection' do
- k.get_data(:foos).should_not === k.get_data(:foos)
- end
-
- it 'returns a frozen object' do
- k.get_data(:foos).should be_frozen
+ it 'returns a dup of the specified MentalModel::Collection' do
+ collection = stub('MentalModel::Collection')
+ collection.should_receive(:dup) \
+ .and_return(:mental_model_collection_dup)
+ configuration.stub!(:mental_model => stub(:foos => collection))
+ k.get_data(:foos).should == :mental_model_collection_dup
end
end

0 comments on commit 43e7341

Please sign in to comment.