require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Array#permutation" do before :each do @numbers = (1..3).to_a @yielded = [] end it "returns an Enumerator of all permutations when called without a block or arguments" do enum = @numbers.permutation enum.should.instance_of?(Enumerator) enum.to_a.sort.should == [ [1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1] ].sort end it "returns an Enumerator of permutations of given length when called with an argument but no block" do enum = @numbers.permutation(1) enum.should.instance_of?(Enumerator) enum.to_a.sort.should == [[1],[2],[3]] end it "yields all permutations to the block then returns self when called with block but no arguments" do array = @numbers.permutation {|n| @yielded << n} array.should.instance_of?(Array) array.sort.should == @numbers.sort @yielded.sort.should == [ [1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1] ].sort end it "yields all permutations of given length to the block then returns self when called with block and argument" do array = @numbers.permutation(2) {|n| @yielded << n} array.should.instance_of?(Array) array.sort.should == @numbers.sort @yielded.sort.should == [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]].sort end it "returns the empty permutation ([[]]) when the given length is 0" do @numbers.permutation(0).to_a.should == [[]] @numbers.permutation(0) { |n| @yielded << n } @yielded.should == [[]] end it "returns the empty permutation([]) when called on an empty Array" do [].permutation.to_a.should == [[]] [].permutation { |n| @yielded << n } @yielded.should == [[]] end it "returns no permutations when the given length has no permutations" do @numbers.permutation(9).entries.size.should == 0 @numbers.permutation(9) { |n| @yielded << n } @yielded.should == [] end it "handles duplicate elements correctly" do @numbers << 1 @numbers.permutation(2).sort.should == [ [1,1],[1,1],[1,2],[1,2],[1,3],[1,3], [2,1],[2,1],[2,3], [3,1],[3,1],[3,2] ].sort end it "handles nested Arrays correctly" do # The ugliness is due to the order of permutations returned by # permutation being undefined combined with #sort croaking on Arrays of # Arrays. @numbers << [4,5] got = @numbers.permutation(2).to_a expected = [ [1, 2], [1, 3], [1, [4, 5]], [2, 1], [2, 3], [2, [4, 5]], [3, 1], [3, 2], [3, [4, 5]], [[4, 5], 1], [[4, 5], 2], [[4, 5], 3] ] expected.each {|e| got.include?(e).should == true} got.size.should == expected.size end it "truncates Float arguments" do @numbers.permutation(3.7).to_a.sort.should == @numbers.permutation(3).to_a.sort end it "returns an Enumerator which works as expected even when the array was modified" do @numbers = [1, 2] enum = @numbers.permutation @numbers << 3 enum.to_a.sort.should == [ [1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1] ].sort end it "generates from a defensive copy, ignoring mutations" do accum = [] ary = [1,2,3] ary.permutation(3) do |x| accum << x ary[0] = 5 end accum.should == [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] end describe "when no block is given" do describe "returned Enumerator" do describe "size" do describe "with an array size greater than 0" do it "returns the descending factorial of array size and given length" do @numbers.permutation(4).size.should == 0 @numbers.permutation(3).size.should == 6 @numbers.permutation(2).size.should == 6 @numbers.permutation(1).size.should == 3 @numbers.permutation(0).size.should == 1 end it "returns the descending factorial of array size with array size when there's no param" do @numbers.permutation.size.should == 6 [1,2,3,4].permutation.size.should == 24 [1].permutation.size.should == 1 end end describe "with an empty array" do it "returns 1 when the given length is 0" do [].permutation(0).size.should == 1 end it "returns 1 when there's param" do [].permutation.size.should == 1 end end end end end end