summaryrefslogtreecommitdiff
path: root/spec/ruby/core/array/sample_spec.rb
blob: 73b6bdf48078fc1060644b10350656e517489f49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
require_relative '../../spec_helper'
require_relative 'fixtures/classes'

describe "Array#sample" do
  it "samples evenly" do
    ary = [0, 1, 2, 3]
    3.times do |i|
      counts = [0, 0, 0, 0]
      4000.times do
        counts[ary.sample(3)[i]] += 1
      end
      counts.each do |count|
        (800..1200).should include(count)
      end
    end
  end

  it "returns nil for an empty Array" do
    [].sample.should be_nil
  end

  it "returns a single value when not passed a count" do
    [4].sample.should equal(4)
  end

  it "returns an empty Array when passed zero" do
    [4].sample(0).should == []
  end

  it "returns an Array of elements when passed a count" do
    [1, 2, 3, 4].sample(3).should be_an_instance_of(Array)
  end

  it "returns elements from the Array" do
    array = [1, 2, 3, 4]
    array.sample(3).all? { |x| array.should include(x) }
  end

  it "returns at most the number of elements in the Array" do
    array = [1, 2, 3, 4]
    result = array.sample(20)
    result.size.should == 4
  end

  it "does not return the same value if the Array has unique values" do
    array = [1, 2, 3, 4]
    result = array.sample(20)
    result.sort.should == array
  end

  it "may return the same value if the array is not unique" do
    [4, 4].sample(2).should == [4,4]
  end

  it "calls #to_int to convert the count when passed an Object" do
    [1, 2, 3, 4].sample(mock_int(2)).size.should == 2
  end

  it "raises ArgumentError when passed a negative count" do
    -> { [1, 2].sample(-1) }.should raise_error(ArgumentError)
  end

  it "does not return subclass instances with Array subclass" do
    ArraySpecs::MyArray[1, 2, 3].sample(2).should be_an_instance_of(Array)
  end

  describe "with options" do
    it "calls #rand on the Object passed by the :random key in the arguments Hash" do
      obj = mock("array_sample_random")
      obj.should_receive(:rand).and_return(0.5)

      [1, 2].sample(random: obj).should be_an_instance_of(Fixnum)
    end

    it "raises a NoMethodError if an object passed for the RNG does not define #rand" do
      obj = BasicObject.new

      -> { [1, 2].sample(random: obj) }.should raise_error(NoMethodError)
    end

    describe "when the object returned by #rand is a Fixnum" do
      it "uses the fixnum as index" do
        random = mock("array_sample_random_ret")
        random.should_receive(:rand).and_return(0)

        [1, 2].sample(random: random).should == 1

        random = mock("array_sample_random_ret")
        random.should_receive(:rand).and_return(1)

        [1, 2].sample(random: random).should == 2
      end

      it "raises a RangeError if the value is less than zero" do
        random = mock("array_sample_random")
        random.should_receive(:rand).and_return(-1)

        -> { [1, 2].sample(random: random) }.should raise_error(RangeError)
      end

      it "raises a RangeError if the value is equal to the Array size" do
        random = mock("array_sample_random")
        random.should_receive(:rand).and_return(2)

        -> { [1, 2].sample(random: random) }.should raise_error(RangeError)
      end
    end
  end

  describe "when the object returned by #rand is not a Fixnum but responds to #to_int" do
    it "calls #to_int on the Object" do
      value = mock("array_sample_random_value")
      value.should_receive(:to_int).and_return(1)
      random = mock("array_sample_random")
      random.should_receive(:rand).and_return(value)

      [1, 2].sample(random: random).should == 2
    end

    it "raises a RangeError if the value is less than zero" do
      value = mock("array_sample_random_value")
      value.should_receive(:to_int).and_return(-1)
      random = mock("array_sample_random")
      random.should_receive(:rand).and_return(value)

      -> { [1, 2].sample(random: random) }.should raise_error(RangeError)
    end

    it "raises a RangeError if the value is equal to the Array size" do
      value = mock("array_sample_random_value")
      value.should_receive(:to_int).and_return(2)
      random = mock("array_sample_random")
      random.should_receive(:rand).and_return(value)

      -> { [1, 2].sample(random: random) }.should raise_error(RangeError)
    end
  end
end