flores 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Makefile CHANGED
@@ -3,25 +3,6 @@ VERSION=$(shell awk -F\" '/spec.version/ { print $$2 }' $(GEMSPEC))
3
3
  NAME=$(shell awk -F\" '/spec.name/ { print $$2 }' $(GEMSPEC))
4
4
  GEM=$(NAME)-$(VERSION).gem
5
5
 
6
- .PHONY: test
7
- test:
8
- sh notify-failure.sh ruby test/all.rb
9
-
10
- .PHONY: testloop
11
- testloop:
12
- while true; do \
13
- $(MAKE) test; \
14
- $(MAKE) wait-for-changes; \
15
- done
16
-
17
- .PHONY: serve-coverage
18
- serve-coverage:
19
- cd coverage; python -mSimpleHTTPServer
20
-
21
- .PHONY: wait-for-changes
22
- wait-for-changes:
23
- -inotifywait --exclude '\.swp' -e modify $$(find $(DIRS) -name '*.rb'; find $(DIRS) -type d)
24
-
25
6
  .PHONY: package
26
7
  package: | $(GEM)
27
8
 
@@ -1,3 +1,20 @@
1
+ # This file is part of ruby-flores.
2
+ # Copyright (C) 2015 Jordan Sissel
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as
6
+ # published by the Free Software Foundation, either version 3 of the
7
+ # License, or (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ #
17
+ # encoding: utf-8
1
18
  require "randomized"
2
19
  require "rspec/stress_it"
3
20
 
@@ -1,3 +1,20 @@
1
+ # This file is part of ruby-flores.
2
+ # Copyright (C) 2015 Jordan Sissel
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as
6
+ # published by the Free Software Foundation, either version 3 of the
7
+ # License, or (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ #
17
+ # encoding: utf-8
1
18
  require "randomized"
2
19
  require "socket"
3
20
  require "rspec/stress_it"
@@ -6,6 +23,10 @@ RSpec.configure do |c|
6
23
  c.extend RSpec::StressIt
7
24
  end
8
25
 
26
+ # A factory for encapsulating behavior of a tcp server and client for the
27
+ # purposes of testing.
28
+ #
29
+ # This is probably not really a "factory" in a purist-sense, but whatever.
9
30
  class TCPIntegrationTestFactory
10
31
  def initialize(port)
11
32
  @listener = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
@@ -33,7 +54,6 @@ class TCPIntegrationTestFactory
33
54
 
34
55
  @client.syswrite(text)
35
56
  @client.close
36
- #expect(client.syswrite(text)).to(be == text.bytesize)
37
57
  server.read
38
58
  ensure
39
59
  @client.close unless @client.closed?
@@ -42,32 +62,12 @@ class TCPIntegrationTestFactory
42
62
  end
43
63
 
44
64
  describe "TCPServer+TCPSocket" do
45
- let(:port) { Randomized.number(1024..65535) }
46
- let(:text) { Randomized.text(1..10000) }
65
+ let(:port) { Randomized.integer(1024..65535) }
66
+ let(:text) { Randomized.text(1..2000) }
47
67
  subject { TCPIntegrationTestFactory.new(port) }
48
-
49
- #describe "using before/after and stress_it2" do
50
- #before do
51
- #begin
52
- #subject.setup
53
- #rescue Errno::EADDRINUSE
54
- ## We chose a random port that was already in use, let's skip this test.
55
- #skip("Port #{port} is in use by another process, skipping")
56
- #end
57
- #end
58
-
59
- #after do
60
- #subject.teardown
61
- #end
62
-
63
- #stress_it2 "should send data correctly" do
64
- #received = subject.send_and_receive(text)
65
- #expect(received).to(be == text)
66
- #end
67
- #end
68
68
 
69
69
  describe "using stress_it" do
70
- stress_it "should send data correctly" do
70
+ analyze_it "should send data correctly", [:port, :text] do
71
71
  begin
72
72
  subject.setup
73
73
  rescue Errno::EADDRINUSE
@@ -76,6 +76,7 @@ describe "TCPServer+TCPSocket" do
76
76
 
77
77
  begin
78
78
  received = subject.send_and_receive(text)
79
+ expect(received.encoding).to(be == text.encoding)
79
80
  expect(received).to(be == text)
80
81
  ensure
81
82
  subject.teardown
@@ -1,3 +1,20 @@
1
+ # This file is part of ruby-flores.
2
+ # Copyright (C) 2015 Jordan Sissel
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as
6
+ # published by the Free Software Foundation, either version 3 of the
7
+ # License, or (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ #
17
+ # encoding: utf-8
1
18
  require "randomized"
2
19
  require "socket"
3
20
  require "rspec/stress_it"
@@ -12,7 +29,7 @@ describe TCPServer do
12
29
  after { socket.close }
13
30
 
14
31
  context "on a random port" do
15
- let(:port) { Randomized.number(-100000..100000) }
32
+ let(:port) { Randomized.integer(-100_000..100_000) }
16
33
  analyze_it "should bind successfully", [:port] do
17
34
  socket.bind(sockaddr)
18
35
  expect(socket.local_address.ip_port).to(be == port)
@@ -1,3 +1,20 @@
1
+ # This file is part of ruby-flores.
2
+ # Copyright (C) 2015 Jordan Sissel
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as
6
+ # published by the Free Software Foundation, either version 3 of the
7
+ # License, or (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ #
17
+ # encoding: utf-8
1
18
  require "randomized"
2
19
  require "socket"
3
20
  require "rspec/stress_it"
@@ -13,7 +30,7 @@ describe TCPServer do
13
30
  proc do |m, *args|
14
31
  begin
15
32
  m.call(*args)
16
- rescue Errno::EADDRINUSE
33
+ rescue Errno::EADDRINUSE # rubocop:disable Lint/HandleExceptions
17
34
  # ignore
18
35
  end
19
36
  end
@@ -24,14 +41,14 @@ describe TCPServer do
24
41
  end
25
42
 
26
43
  context "on privileged ports" do
27
- let(:port) { Randomized.number(1..1023) }
44
+ let(:port) { Randomized.integer(1..1023) }
28
45
  stress_it "should raise Errno::EACCESS" do
29
46
  expect { socket.bind(sockaddr) }.to(raise_error(Errno::EACCES))
30
47
  end
31
48
  end
32
49
 
33
50
  context "on unprivileged ports" do
34
- let(:port) { Randomized.number(1025..65535) }
51
+ let(:port) { Randomized.integer(1025..65535) }
35
52
  stress_it "should bind on a port" do
36
53
  # EADDRINUSE is expected since we are picking ports at random
37
54
  # Let's ignore this specific exception
data/flores.gemspec CHANGED
@@ -1,8 +1,8 @@
1
1
  Gem::Specification.new do |spec|
2
- files = %x{git ls-files}.split("\n")
2
+ files = %x(git ls-files).split("\n")
3
3
 
4
4
  spec.name = "flores"
5
- spec.version = "0.0.1"
5
+ spec.version = "0.0.2"
6
6
  spec.summary = "Fuzz, randomize, and stress your tests"
7
7
  spec.description = <<-DESCRIPTION
8
8
  Add fuzzing, randomization, and stress to your tests.
@@ -20,4 +20,3 @@ Gem::Specification.new do |spec|
20
20
  spec.authors = ["Jordan Sissel"]
21
21
  spec.email = ["jls@semicomplete.com"]
22
22
  end
23
-
data/lib/randomized.rb CHANGED
@@ -1,5 +1,42 @@
1
+ # This file is part of ruby-flores.
2
+ # Copyright (C) 2015 Jordan Sissel
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as
6
+ # published by the Free Software Foundation, either version 3 of the
7
+ # License, or (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ #
17
+ # encoding: utf-8
18
+
1
19
  # A collection of methods intended for use in randomized testing.
2
20
  module Randomized
21
+ # A selection of UTF-8 characters
22
+ #
23
+ # I'd love to generate this, but I don't yet know enough about how unicode
24
+ # blocks are allocated to do that. For now, hardcode a set of possible
25
+ # characters.
26
+ CHARACTERS = [
27
+ # Basic Latin
28
+ *(32..126).map(&:chr),
29
+
30
+ # hand-selected CJK Unified Ideographs Extension A
31
+ "㐤", "㐨", "㐻", "㑐",
32
+
33
+ # hand-selected Hebrew
34
+ "א", "ב", "ג", "ד", "ה",
35
+
36
+ # hand-selected Cyrillic
37
+ "Є", "Б", "Р", "н", "я"
38
+ ]
39
+
3
40
  # Generates text with random characters of a given length (or within a length range)
4
41
  #
5
42
  # * The length can be a number or a range `x..y`. If a range, it must be ascending (x < y)
@@ -8,30 +45,23 @@ module Randomized
8
45
  # @param length [Fixnum or Range] the length of text to generate
9
46
  # @return [String] the
10
47
  def self.text(length)
11
- if length.is_a?(Range)
12
- raise ArgumentError, "Requires ascending range, you gave #{length}." if length.end < length.begin
13
- raise ArgumentError, "A negative length is not permitted, I received range #{length}" if length.begin < 0
14
-
15
- length = integer(length)
16
- else
17
- raise ArgumentError, "A negative length is not permitted, I received #{length}" if length < 0
18
- end
48
+ return text_range(length) if length.is_a?(Range)
19
49
 
50
+ raise ArgumentError, "A negative length is not permitted, I received #{length}" if length < 0
20
51
  length.times.collect { character }.join
21
52
  end # def text
22
53
 
54
+ def self.text_range(range)
55
+ raise ArgumentError, "Requires ascending range, you gave #{range}." if range.end < range.begin
56
+ raise ArgumentError, "A negative range values are not permitted, I received range #{range}" if range.begin < 0
57
+ text(integer(range))
58
+ end
59
+
23
60
  # Generates a random character (A string of length 1)
24
61
  #
25
62
  # @return [String]
26
63
  def self.character
27
- # TODO(sissel): Add support to generate valid UTF-8. I started reading
28
- # Unicode 7 (http://www.unicode.org/versions/Unicode7.0.0/) and after much
29
- # reading, I realized I wasn't in my house anymore but had somehow lost
30
- # track of time and was alone in a field. Civilization had fallen centuries
31
- # ago. :P
32
-
33
- # Until UTF-8 is supported, just return a random lower ASCII character
34
- integer(32..127).chr
64
+ return CHARACTERS[integer(0...CHARACTERS.length)]
35
65
  end # def character
36
66
 
37
67
  # Return a random integer value within a given range.
@@ -64,4 +94,4 @@ module Randomized
64
94
  integer(range).times
65
95
  end
66
96
  end # def iterations
67
- end
97
+ end # module Randomized
@@ -1,6 +1,31 @@
1
+ # This file is part of ruby-flores.
2
+ # Copyright (C) 2015 Jordan Sissel
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as
6
+ # published by the Free Software Foundation, either version 3 of the
7
+ # License, or (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ #
1
17
  # encoding: utf-8
2
18
  require "rspec/core"
3
19
 
20
+ # RSpec helpers for stress testing examples
21
+ #
22
+ # Setting it up in rspec:
23
+ #
24
+ # RSpec.configure do |c|
25
+ # c.extend RSpec::StressIt
26
+ # end
27
+ #
28
+ # TODO(sissel): Show an example of stress_it and analyze_it
4
29
  module RSpec::StressIt
5
30
  DEFAULT_ITERATIONS = 1..5000
6
31
 
@@ -10,11 +35,11 @@ module RSpec::StressIt
10
35
  # of APIs to help find edge cases and weird behavior.
11
36
  #
12
37
  # The default number of iterations is randomly selected between 1 and 1000 inclusive
13
- def stress_it(name, options={}, &block)
14
- __iterations = Randomized.iterations(options.delete(:stress_iterations) || DEFAULT_ITERATIONS)
38
+ def stress_it(name, options = {}, &block)
39
+ stress__iterations = Randomized.iterations(options.delete(:stress_iterations) || DEFAULT_ITERATIONS)
15
40
  it(name, options) do
16
41
  # Run the block of an example many times
17
- __iterations.each do |i|
42
+ stress__iterations.each do
18
43
  # Run the block within 'it' scope
19
44
  instance_eval(&block)
20
45
 
@@ -34,10 +59,10 @@ module RSpec::StressIt
34
59
  # it "should be less than 100" do
35
60
  # expect(number).to(be < 100)
36
61
  # end
37
- def stress_it2(name, options={}, &block)
38
- __iterations = Randomized.iterations(options.delete(:stress_iterations) || DEFAULT_ITERATIONS)
39
- __iterations.each do |i|
40
- it(example_name + " [#{i}]", *args) do
62
+ def stress_it2(name, options = {}, &block)
63
+ stress__iterations = Randomized.iterations(options.delete(:stress_iterations) || DEFAULT_ITERATIONS)
64
+ stress__iterations.each do |i|
65
+ it(name + " [#{i}]", *args) do
41
66
  instance_eval(&block)
42
67
  end # it ...
43
68
  end # .times
@@ -57,18 +82,17 @@ module RSpec::StressIt
57
82
  # end
58
83
  #
59
84
  # Example report:
60
- def analyze_it(name, variables, &block)
85
+ def analyze_it(name, variables, &block) # rubocop:disable Metrics/AbcSize
61
86
  it(name) do
62
- results = Hash.new { |h,k| h[k] = [] }
63
- iterations = Randomized.iterations(DEFAULT_ITERATIONS)
64
- iterations.each do |i|
87
+ results = Hash.new { |h, k| h[k] = [] }
88
+ Randomized.iterations(DEFAULT_ITERATIONS).each do
65
89
  state = Hash[variables.collect { |l| [l, __send__(l)] }]
66
90
  begin
67
91
  instance_eval(&block)
68
92
  results[:success] << [state, nil]
69
93
  rescue => e
70
94
  results[e.class] << [state, e]
71
- rescue Exception => e
95
+ rescue Exception => e # rubocop:disable Lint/RescueException
72
96
  results[e.class] << [state, e]
73
97
  end
74
98
 
@@ -76,20 +100,19 @@ module RSpec::StressIt
76
100
  __memoized.clear
77
101
  end
78
102
 
79
- if results[:success] != iterations
80
- raise Analysis.new(results)
81
- end
103
+ raise StandardError, Analysis.new(results) if results.any? { |k, _| k != :success }
82
104
  end
83
- end
105
+ end # def analyze_it
84
106
 
107
+ # A formatter to show analysis of an `analyze_it` example.
85
108
  class Analysis < StandardError
86
109
  def initialize(results)
87
110
  @results = results
88
- end
111
+ end # def initialize
89
112
 
90
113
  def total
91
- @results.reduce(0) { |m, (k,v)| m + v.length }
92
- end
114
+ @results.reduce(0) { |m, (_, v)| m + v.length }
115
+ end # def total
93
116
 
94
117
  def success_count
95
118
  if @results.include?(:success)
@@ -97,33 +120,54 @@ module RSpec::StressIt
97
120
  else
98
121
  0
99
122
  end
100
- end
123
+ end # def success_count
101
124
 
102
125
  def percent(count)
103
126
  return (count + 0.0) / total
104
- end
127
+ end # def percent
105
128
 
106
129
  def percent_s(count)
107
- return sprintf("%.2f%%", percent(count) * 100)
108
- end
130
+ return format("%.2f%%", percent(count) * 100)
131
+ end # def percent_s
109
132
 
110
133
  def to_s
111
134
  # This method is crazy complex for a formatter. Should refactor this significantly.
112
135
  report = ["#{percent_s(success_count)} tests successful of #{total} tests"]
113
- if success_count < total
114
- report << "Failure analysis:"
115
- report += @results.sort_by { |k,v| -v.length }.reject { |k,v| k == :success }.collect do |k, v|
116
- sample = v.sample(5).collect { |v| v.first }.join(", ")
117
- [
118
- " #{percent_s(v.length)} -> [#{v.length}] #{k}",
119
- " Sample exception:",
120
- v.sample(1).first[1].to_s.gsub(/^/, " "),
121
- " Samples causing #{k}:",
122
- *v.sample(5).collect { |state, _exception| " #{state}" }
123
- ]
124
- end.flatten
125
- end
136
+ report += failure_summary if success_count < total
126
137
  report.join("\n")
127
- end
128
- end
138
+ end # def to_s
139
+
140
+ # TODO(sissel): All these report/summary/to_s things are an indication that the
141
+ # report formatting belongs in a separate class.
142
+ def failure_summary
143
+ report = ["Failure analysis:"]
144
+ report += @results.sort_by { |_, v| -v.length }.collect do |group, instances|
145
+ next if group == :success
146
+ error_report(group, instances)
147
+ end.reject(&:nil?).flatten
148
+ report
149
+ end # def failure_summary
150
+
151
+ def error_report(error, instances)
152
+ report = error_summary(error, instances)
153
+ report += error_sample_states(error, instances) if instances.size > 1
154
+ report
155
+ end # def error_report
156
+
157
+ def error_summary(error, instances)
158
+ sample = instances.sample(1)
159
+ [
160
+ " #{percent_s(instances.length)} -> [#{instances.length}] #{error}",
161
+ " Sample exception for #{sample.first[0]}",
162
+ sample.first[1].to_s.gsub(/^/, " ")
163
+ ]
164
+ end # def error_summary
165
+
166
+ def error_sample_states(error, instances)
167
+ [
168
+ " Samples causing #{error}:",
169
+ *instances.sample(5).collect { |state, _exception| " #{state}" }
170
+ ]
171
+ end # def error_sample_states
172
+ end # class Analysis
129
173
  end # module RSpec::StressIt
@@ -1,3 +1,20 @@
1
+ # This file is part of ruby-flores.
2
+ # Copyright (C) 2015 Jordan Sissel
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as
6
+ # published by the Free Software Foundation, either version 3 of the
7
+ # License, or (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ #
17
+ # encoding: utf-8
1
18
  require "randomized"
2
19
  require "rspec/stress_it"
3
20
 
@@ -5,10 +22,19 @@ RSpec.configure do |c|
5
22
  c.extend RSpec::StressIt
6
23
  end
7
24
 
25
+ shared_examples_for String do |variables|
26
+ analyze_it "should be a String", variables do
27
+ expect(subject).to(be_a(String))
28
+ end
29
+ analyze_it "have valid encoding", variables do
30
+ expect(subject).to(be_valid_encoding)
31
+ end
32
+ end
33
+
8
34
  describe Randomized do
9
35
  describe "#text" do
10
36
  context "with no arguments" do
11
- it "should raise ArgumentError" do
37
+ stress_it "should raise ArgumentError" do
12
38
  expect { subject.text }.to(raise_error(ArgumentError))
13
39
  end
14
40
  end
@@ -18,15 +44,15 @@ describe Randomized do
18
44
 
19
45
  context "that is positive" do
20
46
  let(:length) { rand(1..1000) }
21
- stress_it "should give a string with that length" do
22
- expect(subject).to(be_a(String))
47
+ it_behaves_like String, [:length]
48
+ analyze_it "has correct length", [:length] do
23
49
  expect(subject.length).to(eq(length))
24
50
  end
25
51
  end
26
52
 
27
53
  context "that is negative" do
28
54
  let(:length) { -1 * rand(1..1000) }
29
- stress_it "should raise ArgumentError" do
55
+ analyze_it "should raise ArgumentError", [:length] do
30
56
  expect { subject }.to(raise_error(ArgumentError))
31
57
  end
32
58
  end
@@ -38,16 +64,17 @@ describe Randomized do
38
64
  subject { described_class.text(range) }
39
65
 
40
66
  context "that is ascending" do
41
- let(:range) { start .. (start + length) }
42
- stress_it "should give a string within that length range" do
67
+ let(:range) { start..(start + length) }
68
+ it_behaves_like String, [:range]
69
+ analyze_it "should give a string within that length range", [:range] do
43
70
  expect(subject).to(be_a(String))
44
71
  expect(range).to(include(subject.length))
45
72
  end
46
73
  end
47
74
 
48
75
  context "that is descending" do
49
- let(:range) { start .. (start - length) }
50
- stress_it "should raise ArgumentError" do
76
+ let(:range) { start..(start - length) }
77
+ analyze_it "should raise ArgumentError", [:range] do
51
78
  expect { subject }.to(raise_error(ArgumentError))
52
79
  end
53
80
  end
@@ -56,40 +83,50 @@ describe Randomized do
56
83
 
57
84
  describe "#character" do
58
85
  subject { described_class.character }
59
- stress_it "returns a string of length 1" do
86
+ it_behaves_like String, [:subject]
87
+ analyze_it "has length == 1", [:subject] do
60
88
  expect(subject.length).to(be == 1)
61
89
  end
62
90
  end
63
91
 
64
- shared_examples_for "random numbers within a range" do
65
- let(:start) { Randomized.integer(-100000 .. 100000) }
66
- let(:length) { Randomized.integer(1 .. 100000) }
67
- let(:range) { start .. (start + length) }
92
+ shared_examples_for Numeric do |type|
93
+ let(:start) { Randomized.integer(-100_000..100_000) }
94
+ let(:length) { Randomized.integer(1..100_000) }
95
+ let(:range) { start..(start + length) }
68
96
 
69
- stress_it "should be a Numeric" do
70
- expect(subject).to(be_a(Numeric))
97
+ analyze_it "should be a #{type}", [:range] do
98
+ expect(subject).to(be_a(type))
71
99
  end
72
100
 
73
- stress_it "should be within the bounds of the given range" do
101
+ analyze_it "should be within the bounds of the given range", [:range] do
74
102
  expect(range).to(include(subject))
75
103
  end
76
104
  end
77
105
 
78
106
  describe "#integer" do
79
- it_behaves_like "random numbers within a range" do
107
+ it_behaves_like Numeric, Fixnum do
80
108
  subject { Randomized.integer(range) }
81
- stress_it "is a Fixnum" do
82
- expect(subject).to(be_a(Fixnum))
83
- end
84
109
  end
85
110
  end
111
+
86
112
  describe "#number" do
87
- it_behaves_like "random numbers within a range" do
113
+ it_behaves_like Numeric, Float do
88
114
  subject { Randomized.number(range) }
115
+ end
116
+ end
89
117
 
90
- stress_it "is a Float" do
91
- expect(subject).to(be_a(Float))
92
- end
118
+ describe "#iterations" do
119
+ let(:start) { Randomized.integer(1..100_000) }
120
+ let(:length) { Randomized.integer(1..100_000) }
121
+ let(:range) { start..(start + length) }
122
+ subject { Randomized.iterations(range) }
123
+
124
+ analyze_it "should return an Enumerable", [:range] do
125
+ expect(subject).to(be_a(Enumerable))
126
+ end
127
+
128
+ analyze_it "should have a size within the expected range", [:range] do
129
+ expect(range).to(include(subject.size))
93
130
  end
94
131
  end
95
132
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flores
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Sissel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-19 00:00:00.000000000 Z
11
+ date: 2015-02-21 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |2
14
14
  Add fuzzing, randomization, and stress to your tests.
@@ -23,8 +23,10 @@ executables: []
23
23
  extensions: []
24
24
  extra_rdoc_files: []
25
25
  files:
26
+ - ".rubocop.yml"
26
27
  - Gemfile
27
28
  - Gemfile.lock
29
+ - LICENSE.txt
28
30
  - Makefile
29
31
  - examples/analyze_number.rb
30
32
  - examples/socket_acceptance_spec.rb