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 be_an_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 be_an_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 be_an_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 be_an_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 be_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