summaryrefslogtreecommitdiff
path: root/spec/ruby/library/prime/each_spec.rb
blob: c89e871582512a194124aa705a4115a93273749b (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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
require_relative '../../spec_helper'

ruby_version_is ""..."3.1" do
  require 'prime'

  describe :prime_each, shared: true do
    before :each do
      ScratchPad.record []
    end

    it "enumerates primes" do
      primes = Prime.instance
      result = []

      primes.each { |p|
        result << p
        break if p > 10
      }

      result.should == [2, 3, 5, 7, 11]
    end

    it "yields ascending primes to the block" do
      previous = 1
      @object.each do |prime|
        break if prime > 1000
        ScratchPad << prime
        prime.should > previous
        previous = prime
      end

      all_prime = true
      ScratchPad.recorded.all? do |prime|
        all_prime &&= (2..Math.sqrt(prime)).all? { |d| prime % d != 0 }
      end

      all_prime.should be_true
    end

    it "returns the last evaluated expression in the passed block" do
      @object.each { break :value }.should equal(:value)
    end

    describe "when not passed a block" do
      before :each do
        @prime_enum = @object.each
      end

      it "returns an object that is Enumerable" do
        @prime_enum.each.should be_kind_of(Enumerable)
      end

      it "returns an object that responds to #with_index" do
        @prime_enum.should respond_to(:with_index)
      end

      it "returns an object that responds to #with_object" do
        @prime_enum.should respond_to(:with_object)
      end

      it "returns an object that responds to #next" do
        @prime_enum.should respond_to(:next)
      end

      it "returns an object that responds to #rewind" do
        @prime_enum.should respond_to(:rewind)
      end

      it "yields primes starting at 2 independent of prior enumerators" do
        @prime_enum.next.should == 2
        @prime_enum.next.should == 3

        @object.each { |prime| break prime }.should == 2
      end

      it "returns an enumerator that yields previous primes when #rewind is called" do
        @prime_enum.next.should == 2
        @prime_enum.next.should == 3
        @prime_enum.rewind
        @prime_enum.next.should == 2
      end

      it "returns independent enumerators" do
        enum = @object.each
        enum.next.should == 2
        enum.next.should == 3

        @prime_enum.next.should == 2

        enum.next.should == 5
      end
    end
  end

  describe :prime_each_with_arguments, shared: true do
    before :each do
      ScratchPad.record []
    end

    it "yields ascending primes less than or equal to the argument" do
      bound = 1000
      previous = 1
      @object.each(bound) do |prime|
        ScratchPad << prime
        prime.should > previous
        previous = prime
      end

      ScratchPad.recorded.all? do |prime|
        (2..Math.sqrt(prime)).all? { |d| prime % d != 0 }
      end.should be_true

      ScratchPad.recorded.all? { |prime| prime <= bound }.should be_true
    end

    it "returns nil when no prime is generated" do
      @object.each(1) { :value }.should be_nil
    end

    it "yields primes starting at 2 independent of prior enumeration" do
      @object.each(10) { |prime| prime }.should == 7
      @object.each(10) { |prime| break prime }.should == 2
    end

    it "accepts a pseudo-prime generator as the second argument" do
      generator = mock('very bad pseudo-prime generator')
      generator.should_receive(:upper_bound=).with(100)
      generator.should_receive(:each).and_yield(2).and_yield(3).and_yield(4)

      @object.each(100, generator) { |prime| ScratchPad << prime }
      ScratchPad.recorded.should == [2, 3, 4]
    end

    describe "when not passed a block" do
      it "returns an object that returns primes less than or equal to the bound" do
        bound = 100
        @object.each(bound).all? { |prime| prime <= bound }.should be_true
      end
    end
  end

  describe "Prime.each" do
    it_behaves_like :prime_each, :each, Prime
  end

  describe "Prime.each" do
    it_behaves_like :prime_each_with_arguments, :each, Prime
  end

  describe "Prime#each with Prime.instance" do
    it_behaves_like :prime_each, :each, Prime.instance
  end

  describe "Prime#each with Prime.instance" do
    it_behaves_like :prime_each_with_arguments, :each, Prime.instance
  end

  describe "Prime#each with Prime.instance" do
    before :each do
      @object = Prime.instance
    end

    it_behaves_like :prime_each, :each

    it "resets the enumerator with each call" do
      @object.each { |prime| break if prime > 10 }
      @object.each { |prime| break prime }.should == 2
    end
  end
end