gen-test 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 84646aec5140b201837409f37dc51fd298c8fb5aff1c0c5d7026068c2aa7ebbd
4
+ data.tar.gz: ed3b318092f96b74707c9426c9f59536e47071bc1ec68de5d1deeef7d25125bd
5
+ SHA512:
6
+ metadata.gz: e9b4811b8ff6bdda4268092759793053f7d1af6a74ba1ddfeff540917f8b3b92639fd32c3d77ca32e03f38efaa7df1f77c609eb564ca67b978673b2480906a6f
7
+ data.tar.gz: e4ff31c90d8dffd0398ab0a965c222084f1751e6ede57c8202d351bdab69ba52baeda73394f57d36a9a299df00180a6a9a144dfc25515cc0a3c2338779f56906
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+ .rakeTasks
13
+ *.iml
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in gen-test.gemspec
4
+ gemspec
@@ -0,0 +1,45 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ gen-test (0.1.0)
5
+ faker (~> 1.9.6)
6
+ regexp-examples (~> 1.5.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ concurrent-ruby (1.1.5)
12
+ diff-lcs (1.3)
13
+ faker (1.9.6)
14
+ i18n (>= 0.7)
15
+ i18n (1.6.0)
16
+ concurrent-ruby (~> 1.0)
17
+ rake (10.5.0)
18
+ regexp-examples (1.5.0)
19
+ rspec (3.8.0)
20
+ rspec-core (~> 3.8.0)
21
+ rspec-expectations (~> 3.8.0)
22
+ rspec-mocks (~> 3.8.0)
23
+ rspec-core (3.8.2)
24
+ rspec-support (~> 3.8.0)
25
+ rspec-expectations (3.8.4)
26
+ diff-lcs (>= 1.2.0, < 2.0)
27
+ rspec-support (~> 3.8.0)
28
+ rspec-mocks (3.8.1)
29
+ diff-lcs (>= 1.2.0, < 2.0)
30
+ rspec-support (~> 3.8.0)
31
+ rspec-support (3.8.2)
32
+ yard (0.9.24)
33
+
34
+ PLATFORMS
35
+ ruby
36
+
37
+ DEPENDENCIES
38
+ bundler (~> 2.0)
39
+ gen-test!
40
+ rake (~> 10.0)
41
+ rspec (~> 3.0)
42
+ yard (~> 0.9.24)
43
+
44
+ BUNDLED WITH
45
+ 2.1.4
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Delon Newman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,53 @@
1
+ Gen::Test
2
+ =========
3
+
4
+ Generative, property based testing for Ruby
5
+
6
+ Synopsis
7
+ ========
8
+
9
+ ```ruby
10
+ AddOne = lambda { |x| x + 1 }
11
+
12
+ class AddOneTest < Minitest::Test
13
+ include Gen::Test
14
+
15
+ def test_incremented_for_all_integers
16
+ for_all Integer do |int|
17
+ inc = AddOne[int]
18
+ assert_equal(inc, int + 1)
19
+ end
20
+ end
21
+ end
22
+ ```
23
+
24
+ Why?
25
+ ====
26
+
27
+ Generative testing has much value for unit, acceptance and integration testing over TDD and BDD, while it's
28
+ value doesn't come for free.
29
+ [Others](https://www.youtube.com/watch?v=r5i_OiZw6Sw) [argue](http://www.quviq.com/products/quickcheck-for-c/)
30
+ this point well.
31
+
32
+ There seemed to be a need simple, extensible, implementation for Ruby, that wasn't a DSL or a framework. This
33
+ module is still very incomplete, but it's proven useful.
34
+
35
+ Install
36
+ =======
37
+
38
+ > gem install gen-test
39
+
40
+ or, add
41
+
42
+ gem 'gen-test'
43
+
44
+ to your Gemfile.
45
+
46
+ See Also
47
+ ========
48
+
49
+ - For Clojure [test.check](https://github.com/clojure/test.check)
50
+ - For Haskell (the original version) [QuickCheck](https://hackage.haskell.org/package/QuickCheck)
51
+ - For Erlang (the most complete version) [QuickCheck](http://www.quviq.com/products/erlang-quickcheck/)
52
+
53
+ - There's quite a few different versions for [Ruby](https://rubygems.org/search?utf8=%E2%9C%93&query=quickcheck)
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,38 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "gen/test/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "gen-test"
7
+ spec.version = Gen::Test::VERSION
8
+ spec.authors = ["Delon Newman"]
9
+ spec.email = ["contact@delonnewman.name"]
10
+
11
+ spec.summary = %q{Generative / Property testing}
12
+ spec.description = spec.summary
13
+ spec.homepage = "https://github.com/delonnewman/gen-test"
14
+ spec.license = "MIT"
15
+
16
+ spec.metadata["allowed_push_host"] = 'https://rubygems.org'
17
+
18
+ spec.metadata["homepage_uri"] = spec.homepage
19
+ spec.metadata["source_code_uri"] = spec.homepage
20
+ spec.metadata["changelog_uri"] = "#{spec.homepage}#changelog"
21
+
22
+ # Specify which files should be added to the gem when it is released.
23
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
25
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ end
27
+ spec.bindir = "exe"
28
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ["lib"]
30
+
31
+ spec.add_runtime_dependency "faker", "~> 1.9.6"
32
+ spec.add_runtime_dependency "regexp-examples", "~> 1.5.0"
33
+
34
+ spec.add_development_dependency "bundler", "~> 2.0"
35
+ spec.add_development_dependency "rake", "~> 10.0"
36
+ spec.add_development_dependency "rspec", "~> 3.0"
37
+ spec.add_development_dependency "yard", "~> 0.9.24"
38
+ end
@@ -0,0 +1,222 @@
1
+ require 'date'
2
+ require 'faker'
3
+ require 'regexp-examples'
4
+
5
+ # Some extentions to the core Object class
6
+ class Object
7
+ # Return self
8
+ def generate(*_args)
9
+ self
10
+ end
11
+ end
12
+
13
+ # Some extentions to the core String class
14
+ class String
15
+ # Randomly generate a String
16
+ #
17
+ # @see Faker::String
18
+ # @return [String]
19
+ # TODO: add filtering
20
+ def self.generate(*_args)
21
+ Faker::String.random
22
+ end
23
+ end
24
+
25
+ # Some extentions to the core Symbol class
26
+ class Symbol
27
+
28
+ # Randomly generate a Symbol
29
+ #
30
+ # @see String#generate
31
+ # @return [Symbol]
32
+ def self.generate(*_args)
33
+ String.generate.to_sym
34
+ end
35
+ end
36
+
37
+ # Some extentions to the core Float class
38
+ class Float
39
+
40
+ # Randomly generate a Float instance
41
+ #
42
+ # @return [Float]
43
+ def self.generate(*_args)
44
+ Random.rand(10e10)
45
+ end
46
+ end
47
+
48
+ # Some extentions to the core Integer class
49
+ class Integer
50
+ # Randomly generate an Integer
51
+ #
52
+ # @return [Integer]
53
+ def self.generate(min: nil, max: nil, bit_length: nil)
54
+ i = Random.rand(10e10).to_i
55
+ if !min.nil? or !max.nil? or !bit_length.nil?
56
+ while i > max or i < min or i.bit_length > bit_length
57
+ i = Random.rand(10e10).to_i
58
+ end
59
+ end
60
+
61
+ if Random.rand < 0.5
62
+ i
63
+ else
64
+ i * -1
65
+ end
66
+ end
67
+ end
68
+
69
+ # Some extentions to the core FalseClass
70
+ class FalseClass
71
+ # Return false
72
+ def self.generate(*_args)
73
+ false
74
+ end
75
+ end
76
+
77
+ # Some extentions to the core TrueClass
78
+ class TrueClass
79
+ # Return true
80
+ def self.generate(*_args)
81
+ true
82
+ end
83
+ end
84
+
85
+ # Some extentions to the core NilClass
86
+ class NilClass
87
+ # Return nil
88
+ def self.generate(*_args)
89
+ nil
90
+ end
91
+ end
92
+
93
+ # Some extentions to the core Array class
94
+ class Array
95
+ DEFAULT_GENERATIVE_TYPES = [
96
+ Integer,
97
+ String,
98
+ Float,
99
+ FalseClass,
100
+ TrueClass,
101
+ NilClass
102
+ ]
103
+
104
+ # Randomly generate an Array
105
+ def self.generate(min: 0, max: 30, type: nil)
106
+ (0..Faker::Number.between(min, max)).map do
107
+ if type.nil?
108
+ DEFAULT_GENERATIVE_TYPES.sample.generate
109
+ else
110
+ type.generate
111
+ end
112
+ end
113
+ end
114
+
115
+ # Randomly generate an Array from an Array instance, use the values of the array as generators.
116
+ #
117
+ # @example
118
+ # [Integer, Float, String].generate => [2341234, 2.24, "asdfawqsafdrawdsfasds"]
119
+ #
120
+ # @return [Array]
121
+ def generate
122
+ map(&:generate)
123
+ end
124
+ end
125
+
126
+ # Some extentions to the core Set class
127
+ class Set
128
+ # Randomly generate a Set
129
+ def self.generate(*args)
130
+ new(Array.generate(*args))
131
+ end
132
+
133
+ # Randomly select an element of the Set
134
+ def generate(*_args)
135
+ to_a.sample
136
+ end
137
+ end
138
+
139
+ # Some extentions to the core Hash class
140
+ class Hash
141
+ DEFAULT_GENERATIVE_KEY_TYPES = [
142
+ Symbol,
143
+ String,
144
+ Integer
145
+ ]
146
+
147
+ DEFAULT_GENERATIVE_VALUE_TYPES = [
148
+ Integer,
149
+ String,
150
+ Float,
151
+ FalseClass,
152
+ TrueClass,
153
+ NilClass
154
+ ]
155
+
156
+ # Randomly generate a Hash
157
+ def self.generate(min: 0, max: 30, key_type: nil, value_type: nil)
158
+ (0..Faker::Number.between(min, max)).reduce({}) do |h, _|
159
+ kt = key_type || DEFAULT_GENERATIVE_KEY_TYPES.sample
160
+ vt = value_type || DEFAULT_GENERATIVE_VALUE_TYPES.sample
161
+ h.merge(kt.generate => vt.generate)
162
+ end
163
+ end
164
+
165
+ def generate(*_args)
166
+ transform_values(&:generate)
167
+ end
168
+ end
169
+
170
+ # Some extentions to the core Range class
171
+ class Range
172
+ # Randomly generate a value within the range
173
+ def generate(*_args)
174
+ if first.is_a? Numeric and last.is_a? Numeric
175
+ Faker::Number.between(first, last)
176
+ else
177
+ to_a.sample
178
+ end
179
+ end
180
+ end
181
+
182
+ class Regexp
183
+ def generate
184
+ random_example
185
+ end
186
+ end
187
+
188
+ class DateTime
189
+ def self.generate(*args)
190
+ if args.empty?
191
+ Time.at(Faker::Number.between(0, Time.now.to_i))
192
+ else
193
+ Faker::Time.between(*args)
194
+ end.to_datetime
195
+ end
196
+ end
197
+
198
+ class Date
199
+ def self.generate(*args)
200
+ if args.empty?
201
+ Time.at(Faker::Number.between(0, Time.now.to_i))
202
+ else
203
+ Faker::Date.between(*args)
204
+ end.to_date
205
+ end
206
+ end
207
+
208
+ class Time
209
+ def self.generate(*args)
210
+ if args.empty?
211
+ Time.at(Faker::Number.between(0, Time.now.to_i))
212
+ else
213
+ Faker::Time.between(*args)
214
+ end.to_time
215
+ end
216
+ end
217
+
218
+ class Proc
219
+ def generate(*args)
220
+ call(*args)
221
+ end
222
+ end
@@ -0,0 +1,49 @@
1
+ module Gen
2
+ class Generator
3
+ def initialize(gen = nil, &blk)
4
+ @gen = gen || blk or raise "A proc or a block is required"
5
+ end
6
+
7
+ def generate
8
+ @gen.call
9
+ end
10
+ alias call generate
11
+ end
12
+
13
+ def generator?(val)
14
+ val.respond_to?(:generate)
15
+ end
16
+
17
+ def sample(gen, n = 10)
18
+ (0..n).map { generate(gen) }
19
+ end
20
+
21
+ def where(gen, pred, max_tries = 10)
22
+ Generator.new do
23
+ tries = 0
24
+ until (val = generate(gen)) and pred.call(val)
25
+ tries += 1
26
+ if tries >= max_tries
27
+ raise "We've tried generating a value from #{gen.inspect} with #{pred.inspect} #{max_tries} times and failed"
28
+ end
29
+ end
30
+ val
31
+ end
32
+ end
33
+
34
+ def one_of(generators)
35
+ generate(generators.to_a.sample)
36
+ end
37
+
38
+ def generate(generator)
39
+ if generator.respond_to?(:call)
40
+ generator.call
41
+ elsif generator.respond_to?(:generate)
42
+ generator.generate
43
+ else
44
+ generator
45
+ end
46
+ end
47
+
48
+ module_function :generator?, :sample, :generate, :where, :one_of
49
+ end
@@ -0,0 +1,48 @@
1
+ require_relative '../gen'
2
+ require_relative '../ext_core'
3
+
4
+ module Gen
5
+ module Test
6
+ LOWER_BOUND = ENV.fetch('TEST_LOWER_BOUND', 10).to_i
7
+ UPPER_BOUND = ENV.fetch('TEST_UPPER_BOUND', 20).to_i
8
+
9
+ def self.included(base)
10
+ base.include(Gen)
11
+ end
12
+
13
+ def for_all(*generators)
14
+ for_n([LOWER_BOUND, UPPER_BOUND], *generators, &Proc.new)
15
+ end
16
+
17
+ def for_any(*generators)
18
+ for_n(1, *generators, &Proc.new)
19
+ end
20
+ alias for_one for_any
21
+
22
+ def for_n(n, *generators)
23
+ if block_given?
24
+ n = Faker::Number.between(n.first, n.last) if n.respond_to?(:first) and n.respond_to?(:last)
25
+ n.times do
26
+ yield(*generators.map(&Gen.method(:generate)))
27
+ end
28
+ else
29
+ raise 'A block is expected with a property definition'
30
+ end
31
+ end
32
+
33
+ def for_each(*collections)
34
+ unless collections.empty?
35
+ size = collections.first.size
36
+ raise "All collections must be the same size" unless collections.all? { |c| c.size == size }
37
+ zipped = collections.first.zip(*collections.drop(1))
38
+ if block_given?
39
+ zipped.each do |generators|
40
+ yield(*generators.map { |g| Gen.generate(g) })
41
+ end
42
+ else
43
+ raise 'A block is expected with a property definition'
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,5 @@
1
+ module Gen
2
+ module Test
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gen-test
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Delon Newman
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-01-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faker
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.9.6
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.9.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: regexp-examples
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.5.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.5.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: yard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.9.24
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.9.24
97
+ description: Generative / Property testing
98
+ email:
99
+ - contact@delonnewman.name
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - Gemfile
107
+ - Gemfile.lock
108
+ - LICENSE.txt
109
+ - README.md
110
+ - Rakefile
111
+ - gen-test.gemspec
112
+ - lib/ext_core.rb
113
+ - lib/gen.rb
114
+ - lib/gen/test.rb
115
+ - lib/gen/test/version.rb
116
+ homepage: https://github.com/delonnewman/gen-test
117
+ licenses:
118
+ - MIT
119
+ metadata:
120
+ allowed_push_host: https://rubygems.org
121
+ homepage_uri: https://github.com/delonnewman/gen-test
122
+ source_code_uri: https://github.com/delonnewman/gen-test
123
+ changelog_uri: https://github.com/delonnewman/gen-test#changelog
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubygems_version: 3.0.6
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: Generative / Property testing
143
+ test_files: []