Permalink
Browse files

Mutate Hash mutating its values

  • Loading branch information...
1 parent b45aa63 commit 0a570bb4dd2904994e05d7981bc7d6fa061b47e5 @txus committed Feb 22, 2012
View
2 lib/mutant/formatter.rb
@@ -34,6 +34,8 @@ def item_value(value = item.value)
Regexp.new(value.source)
when Rubinius::AST::ArrayLiteral
value.body
+ when Rubinius::AST::HashLiteral
+ Hash[*value.array]
else
value.respond_to?(:string) ? value.string.inspect : value.value.inspect
end
View
22 lib/mutant/literal.rb
@@ -82,6 +82,28 @@ def swap
end
end
+ class HashLiteral < BaseLiteral
+ def swap
+ new_body = @node.array.each_slice(2).inject([]) do |body, array|
+ key, value = array
+ new_value = literal_class(value).new(value.clone).swap
+
+ body.push key
+ body.push new_value
+ body
+ end
+
+ @node.array = new_body
+ @node
+ end
+
+ private
+
+ def literal_class(value)
+ Module.nesting[1].literal_class(value)
+ end
+ end
+
class LocalVariableAssignment < BaseLiteral
def swap
@node.value = literal_class.new(@node.value.clone).swap
View
51 spec/functional/instance_method/hash_spec.rb
@@ -0,0 +1,51 @@
+require 'spec_helper'
+
+describe 'Mutating hashes' do
+ context 'for an instance method' do
+ context 'that contains {:foo => {:bar => 3}}' do
+ before do
+ write_file 'thing.rb', """
+ class Thing
+ def to_hash
+ {:foo => {:bar => 3}}
+ end
+ end
+ """
+ end
+
+ context 'with an expectation that hash[:foo][:bar] is 3' do
+ before do
+ write_file 'spec/thing_spec.rb', """
+ require 'thing'
+
+ describe 'Thing#to_hash' do
+ specify { Thing.new.to_hash[:foo][:bar].should eq(3) }
+ end
+ """
+ run_simple '../../bin/mutate Thing#to_hash spec/thing_spec.rb'
+ end
+
+ specify 'the mutation passes' do
+ all_output.should include('passed')
+ end
+ end
+
+ context 'with an expectation that hash[:foo][:bar] is a Fixnum' do
+ before do
+ write_file 'spec/thing_spec.rb', """
+ require 'thing'
+
+ describe 'Thing#to_hash' do
+ specify { Thing.new.to_hash[:foo][:bar].should be_kind_of(Fixnum) }
+ end
+ """
+ run_simple '../../bin/mutate Thing#to_hash spec/thing_spec.rb'
+ end
+
+ specify 'the mutation fails' do
+ all_output.should include('failed')
+ end
+ end
+ end
+ end
+end
View
51 spec/functional/singleton_method/hash_spec.rb
@@ -0,0 +1,51 @@
+require 'spec_helper'
+
+describe 'Mutating hashes' do
+ context 'for a singleton method' do
+ context 'that contains {:foo => {:bar => 3}}' do
+ before do
+ write_file 'thing.rb', """
+ class Thing
+ def self.to_hash
+ {:foo => {:bar => 3}}
+ end
+ end
+ """
+ end
+
+ context 'with an expectation that hash[:foo][:bar] is 3' do
+ before do
+ write_file 'spec/thing_spec.rb', """
+ require 'thing'
+
+ describe 'Thing.to_hash' do
+ specify { Thing.to_hash[:foo][:bar].should eq(3) }
+ end
+ """
+ run_simple '../../bin/mutate Thing.to_hash spec/thing_spec.rb'
+ end
+
+ specify 'the mutation passes' do
+ all_output.should include('passed')
+ end
+ end
+
+ context 'with an expectation that hash[:foo][:bar] is a Fixnum' do
+ before do
+ write_file 'spec/thing_spec.rb', """
+ require 'thing'
+
+ describe 'Thing.to_hash' do
+ specify { Thing.to_hash[:foo][:bar].should be_kind_of(Fixnum) }
+ end
+ """
+ run_simple '../../bin/mutate Thing.to_hash spec/thing_spec.rb'
+ end
+
+ specify 'the mutation fails' do
+ all_output.should include('failed')
+ end
+ end
+ end
+ end
+end

2 comments on commit 0a570bb

@dkubb

Should the key be mutated too?

@txus
Owner

Hmm, I think it's not necessary, but I might be missing a possible scenario. Imagine your code has a hash that has useless keys, i.e. keys that are not referenced ever. If this is the case, mutating the value won't affect the tests (causing the mutation to fail), so it's the same as if we mutated the key, only that to me it makes more sense to deeply mutate the hash values. Anyway it's an open discussion, tell me more about what you think :)

Please sign in to comment.