rubyqc 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 69a41de60f5a0b9675a0633fadaf4961e743661d
4
- data.tar.gz: 5ec783f8ba6d9f68e0a58d2c5603d7b73da8e649
3
+ metadata.gz: 2cdbaeefbc325257c82c18d84d307384ccbb88a8
4
+ data.tar.gz: 5a745da2b4e4266025c3526fe25b71f8076407bc
5
5
  SHA512:
6
- metadata.gz: fd3c8b14af326d8c19714f6172239bab8568e69d7cdb2fee46c525127532e63cc5bade28450efb0c0ec6378ac61143cfe0933d27ed2e15cff24cd5698fc03803
7
- data.tar.gz: 1884e6da6b62adaf3ecfd71918c589988c7a1878bd59b36039b79d90c0f19a9ce2f75432e3ade0ca4e1793d1d2eb1ff46b45a629f6ef2ea95469e003989fa411
6
+ metadata.gz: 7f4d722f681f47670d3819f29711a74db02f83fb5f96ce2b945588ffbedd38ec5f44742c4df44747eb8fb1ad6406906aaa1b5885ff200aba9dc15e9eaedc2fba
7
+ data.tar.gz: 95ad3bc090723bcc5511660adeb793323a206931266d3ea18f50ebbf7d47bb08d3155ef77621359ca6e24d347971ddf36b4c3929dbec68ed3b2a57dc15911a07
@@ -1,9 +1,10 @@
1
- before_install: 'git submodule update --init'
2
- script: 'ruby -r bundler/setup -S rake test'
3
1
 
2
+ language: ruby
4
3
  rvm:
5
4
  - 1.9.3
6
5
  - 2.0.0
7
6
  - ruby
8
- - rbx
7
+ - rbx-2
9
8
  - jruby
9
+
10
+ script: 'ruby -r bundler/setup -S rake test'
data/CHANGES.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # CHANGES
2
2
 
3
+ ## RubyQC 0.0.3 -- 2014-08-01
4
+
5
+ * Introduce Modifier#parallel to run in parallel.
6
+ * Introduce Proc#rubyqc.
7
+ * Changed that API.someof and API.oneof simply accept an array.
8
+
3
9
  ## RubyQC 0.0.2 -- 2014-04-18
4
10
 
5
11
  * Renamed one_of to oneof
data/Gemfile CHANGED
@@ -4,7 +4,8 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  gem 'rake'
7
- gem 'bacon'
7
+ gem 'pork'
8
+ gem 'muack'
8
9
 
9
10
  platform :rbx do
10
11
  gem 'rubysl-singleton' # used in rake
data/README.md CHANGED
@@ -80,20 +80,19 @@ it and raise our level of confidence about correctness.
80
80
 
81
81
  ### RubyQC::API.check
82
82
 
83
- Here's a quick example using [Bacon][]. We check if `Array#sort` has the
83
+ Here's a quick example using [Pork][]. We check if `Array#sort` has the
84
84
  property that the front elements of the result array would be `<=` than
85
85
  the rear elements of the result array for all arrays.
86
86
 
87
87
  ``` ruby
88
- require 'bacon'
88
+ require 'pork/auto'
89
89
  require 'rubyqc'
90
90
 
91
- Bacon.summary_on_exit
92
91
  include RubyQC::API
93
92
 
94
93
  describe Array do
95
94
  describe 'sort' do
96
- should 'Any front elements should be <= any rear elements' do
95
+ would 'Any front elements should be <= any rear elements' do
97
96
  check([Fixnum]*100).times(10) do |array|
98
97
  array.sort.each_cons(2).each{ |x, y| x.should <= y }
99
98
  end
@@ -102,7 +101,7 @@ describe Array do
102
101
  end
103
102
  ```
104
103
 
105
- [Bacon]: https://github.com/chneukirchen/bacon
104
+ [Pork]: https://github.com/godfat/pork
106
105
 
107
106
  Basically, `RubyQC::API.check` would merely take the arguments and
108
107
  generate the instances via `rubyqc` method. Here the generated array
@@ -143,7 +142,7 @@ Here's an example for checking compare_by_identity:
143
142
  ``` ruby
144
143
  describe Hash do
145
144
  describe 'compare_by_identity' do
146
- should 'Treat diff arr with the same contents diff when set' do
145
+ would 'Treat diff arr with the same contents diff when set' do
147
146
  arr = [0]
148
147
  forall(booleans, [arr, [0]], [arr, [1]]) do |flag, a, b|
149
148
  h = {}
@@ -238,11 +237,11 @@ class User < Struct.new(:id, :name)
238
237
  end
239
238
 
240
239
  describe 'User.rubyqc' do
241
- should 'Generate random users' do
240
+ would 'Generate random users' do
242
241
  check(User) do |user|
243
- user .should.kind_of User
244
- user.id .should.kind_of Fixnum
245
- user.name.should.kind_of String
242
+ user .should.kind_of? User
243
+ user.id .should.kind_of? Fixnum
244
+ user.name.should.kind_of? String
246
245
  end
247
246
  end
248
247
  end
@@ -1,3 +1,16 @@
1
1
 
2
2
  require 'rubyqc/api'
3
3
  require 'rubyqc/prelude'
4
+
5
+ module RubyQC
6
+ singleton_class.module_eval do
7
+ attr_writer :default_times, :default_parallel
8
+ def default_times
9
+ @default_times || 10
10
+ end
11
+
12
+ def default_parallel
13
+ @default_parallel || 1
14
+ end
15
+ end
16
+ end
@@ -34,11 +34,11 @@ module RubyQC
34
34
  end
35
35
  end
36
36
 
37
- def someof num, *args
37
+ def someof num, args
38
38
  SomeOf.new(num, args)
39
39
  end
40
40
 
41
- def oneof *args
41
+ def oneof args
42
42
  OneOf.new(args)
43
43
  end
44
44
  end
@@ -0,0 +1,11 @@
1
+
2
+ module RubyQC
3
+ class Error < RuntimeError
4
+ attr_reader :times, :errors
5
+ def initialize times, errors
6
+ @times, @errors = times, errors
7
+ super("RubyQC::Error: #{errors.size} errors out of #{times}:" \
8
+ " #{errors.inspect}")
9
+ end
10
+ end
11
+ end
@@ -1,21 +1,65 @@
1
1
 
2
+ require 'rubyqc/error'
3
+
2
4
  module RubyQC
3
- class Modifier
5
+ class Modifier < Struct.new(:args, :errors, :cases, :threads)
4
6
  def initialize args, &block
5
- @args = args
6
- @times = 10
7
+ super(args, [], RubyQC.default_times, RubyQC.default_parallel)
7
8
  run(&block)
8
9
  end
9
10
 
10
11
  def times t, &block
11
- @times = t
12
+ raise ArgumentError.new(
13
+ "Must run at least once, but got: #{t}") if t <= 0
14
+ self.cases = t
15
+ run(&block)
16
+ end
17
+
18
+ def parallel t, &block
19
+ raise ArgumentError.new(
20
+ "Must have at least 1 thread, but got: #{t}") if t <= 0
21
+ self.threads = t
12
22
  run(&block)
13
23
  end
14
24
 
15
- def run
16
- @times.times{
17
- yield(*@args.map(&:rubyqc))
18
- } if block_given?
25
+ private
26
+ def mutex
27
+ @mutex ||= Mutex.new
28
+ end
29
+
30
+ def run &block
31
+ if !block_given?
32
+ # waiting for block to be given
33
+ elsif threads == 1
34
+ run_thread(cases, &block)
35
+ else
36
+ divided = cases / threads
37
+ mod = cases % threads
38
+
39
+ ts = (threads - 1).times.map{
40
+ Thread.new{ run_thread(divided, &block) }
41
+ } + [Thread.new{ run_thread(divided + mod, &block) }]
42
+ ts.each(&:join)
43
+
44
+ raise Error.new(cases, errors) unless errors.empty?
45
+ end
46
+
47
+ self
48
+ end
49
+
50
+ def run_thread t
51
+ t.times do
52
+ if Thread.current == Thread.main
53
+ # we raise errors immediately if we're not running in parallels
54
+ yield(*args.map(&:rubyqc))
55
+ else
56
+ begin
57
+ yield(*args.map(&:rubyqc))
58
+ rescue Exception => e
59
+ mutex.synchronize{ errors << e }
60
+ end
61
+ end
62
+ end
19
63
  end
20
64
  end
21
65
  end
@@ -263,6 +263,12 @@ class Range
263
263
  end
264
264
  end
265
265
 
266
+ class Proc
267
+ def rubyqc
268
+ call
269
+ end
270
+ end
271
+
266
272
  # TODO
267
273
  class Regexp
268
274
  def rubyqc
@@ -1,21 +1,15 @@
1
1
 
2
- require 'bacon'
2
+ require 'pork/auto'
3
+ require 'muack'
3
4
  require 'rubyqc'
4
5
 
5
- Bacon.summary_on_exit
6
- include RubyQC::API
6
+ # enough of NameError: method `old_init' not defined in SortedSet
7
+ require 'set'
8
+ Set.new
7
9
 
8
- module Kernel
9
- def eq? rhs
10
- self == rhs
11
- end
12
- end
10
+ Pork::Executor.__send__(:include, RubyQC::API, Muack::API)
13
11
 
14
- class Should
15
- def self.rubyqc
16
- new(Class.rubyqc.rubyqc)
17
- end
18
- end
12
+ RubyQC.default_parallel = 4
19
13
 
20
14
  def verify_generated generated, spec
21
15
  if spec.empty?
@@ -60,8 +54,8 @@ end
60
54
 
61
55
  def verify_other generated, spec
62
56
  if spec.kind_of?(Class)
63
- generated.should.kind_of spec
57
+ generated.should.kind_of? spec
64
58
  else
65
- generated.should.eq spec
59
+ generated.should.eq spec
66
60
  end
67
61
  end
@@ -1,4 +1,4 @@
1
1
 
2
2
  module RubyQC
3
- VERSION = '0.0.2'
3
+ VERSION = '0.0.3'
4
4
  end
@@ -1,14 +1,14 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: rubyqc 0.0.2 ruby lib
2
+ # stub: rubyqc 0.0.3 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "rubyqc"
6
- s.version = "0.0.2"
6
+ s.version = "0.0.3"
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib"]
10
10
  s.authors = ["Lin Jen-Shin (godfat)"]
11
- s.date = "2014-04-18"
11
+ s.date = "2014-08-01"
12
12
  s.description = "RubyQC -- A conceptual [QuickCheck][] library for Ruby.\n\nIt's not a faithful port since Hsakell is totally different than Ruby.\nHowever it's still benefit to use some of the ideas behind QuickCheck,\nand we could also use RubyQC for generating arbitrary objects.\n\n[QuickCheck]: http://en.wikipedia.org/wiki/QuickCheck"
13
13
  s.email = ["godfat (XD) godfat.org"]
14
14
  s.files = [
@@ -23,6 +23,7 @@ Gem::Specification.new do |s|
23
23
  "lib/rubyqc.rb",
24
24
  "lib/rubyqc/all.rb",
25
25
  "lib/rubyqc/api.rb",
26
+ "lib/rubyqc/error.rb",
26
27
  "lib/rubyqc/modifier.rb",
27
28
  "lib/rubyqc/prelude.rb",
28
29
  "lib/rubyqc/stdlib.rb",
@@ -39,14 +40,16 @@ Gem::Specification.new do |s|
39
40
  "task/README.md",
40
41
  "task/gemgem.rb",
41
42
  "test/test_api.rb",
42
- "test/test_kind_of.rb",
43
+ "test/test_modifier.rb",
44
+ "test/test_prelude.rb",
43
45
  "test/test_readme.rb"]
44
46
  s.homepage = "https://github.com/godfat/rubyqc"
45
47
  s.licenses = ["Apache License 2.0"]
46
- s.rubygems_version = "2.2.2"
48
+ s.rubygems_version = "2.4.1"
47
49
  s.summary = "RubyQC -- A conceptual [QuickCheck][] library for Ruby."
48
50
  s.test_files = [
49
51
  "test/test_api.rb",
50
- "test/test_kind_of.rb",
52
+ "test/test_modifier.rb",
53
+ "test/test_prelude.rb",
51
54
  "test/test_readme.rb"]
52
55
  end
@@ -34,7 +34,7 @@ module Gemgem
34
34
  s.executables = bin_files
35
35
  end
36
36
  spec_create.call(spec)
37
- spec.homepage = "https://github.com/godfat/#{spec.name}"
37
+ spec.homepage ||= "https://github.com/godfat/#{spec.name}"
38
38
  self.spec = spec
39
39
  end
40
40
 
@@ -227,10 +227,6 @@ end # of gem namespace
227
227
  desc 'Run tests'
228
228
  task :test do
229
229
  next if Gemgem.test_files.empty?
230
-
231
- require 'bacon'
232
- Bacon.extend(Bacon::TestUnitOutput)
233
- Bacon.summary_on_exit
234
230
  Gemgem.test_files.each{ |file| require "#{Gemgem.dir}/#{file[0..-4]}" }
235
231
  end
236
232
 
@@ -3,12 +3,12 @@ require 'rubyqc/test'
3
3
  require 'rubyqc/all'
4
4
 
5
5
  describe RubyQC::API do
6
- should 'oneof' do
6
+ would 'oneof' do
7
7
  check([Class]*5) do |klasses|
8
- klasses -= [Should] # bacon's Should won't work...
9
- check(oneof(*klasses)) do |obj|
8
+ # klasses -= [Pork::Should] # bacon's Should won't work...
9
+ check(oneof(klasses)) do |obj|
10
10
  begin
11
- klasses.find{ |klass| obj.kind_of?(klass) }.should.not.nil
11
+ klasses.find{ |klass| obj.kind_of?(klass) }.should.not.nil?
12
12
  rescue => e
13
13
  warn "Cannot find #{obj} in #{klasses}: #{e}"
14
14
  raise
@@ -17,38 +17,49 @@ describe RubyQC::API do
17
17
  end
18
18
  end
19
19
 
20
+ would 'someof' do
21
+ check(2..5, 6..10) do |n, m|
22
+ check([Fixnum]*m) do |numbers|
23
+ check(someof(n, numbers)) do |nums|
24
+ nums.size.should.eq n
25
+ nums.should.all?{ |nn| numbers.should.include? nn }
26
+ end
27
+ end
28
+ end
29
+ end
30
+
20
31
  describe 'forall' do
21
- should 'hard code' do
32
+ would 'hard code' do
22
33
  times = 0
23
34
  forall([1,2], [3,4], [5,6]) do |a, b, c|
24
35
  times += 1
25
- [1,2].should.include a
26
- [3,4].should.include b
27
- [5,6].should.include c
36
+ [1,2].should.include? a
37
+ [3,4].should.include? b
38
+ [5,6].should.include? c
28
39
  end
29
40
  times.should.eq 2**3
30
41
  end
31
42
 
32
- should 'check' do
43
+ would 'check' do
33
44
  check([Fixnum, Fixnum], [Fixnum, Fixnum], [Fixnum, Fixnum]) do |a, b, c|
34
45
  times = 0
35
46
  forall(a, b, c) do |aa, bb, cc|
36
47
  times += 1
37
- a.should.include aa
38
- b.should.include bb
39
- c.should.include cc
48
+ a.should.include? aa
49
+ b.should.include? bb
50
+ c.should.include? cc
40
51
  end
41
52
  times.should.eq 2**3
42
53
  end
43
54
  end
44
55
 
45
- should 'check check' do
56
+ would 'check check' do
46
57
  check(1..5, 1..5) do |n, m|
47
58
  check([[Fixnum]*n.abs]*m.abs) do |a|
48
59
  times = 0
49
60
  forall(*a) do |*aa|
50
61
  times += 1
51
- a.zip(aa).each{ |(b, bb)| b.should.include bb }
62
+ a.zip(aa).each{ |(b, bb)| b.should.include? bb }
52
63
  end
53
64
  times.should.eq n**m
54
65
  end
@@ -0,0 +1,66 @@
1
+
2
+ require 'rubyqc/test'
3
+
4
+ describe RubyQC::Modifier do
5
+ would 'times' do
6
+ check(2..10) do |times|
7
+ t = 0
8
+ m = Mutex.new
9
+ check.times(times){ m.synchronize{ t += 1 } }
10
+ t.should.eq times
11
+ end
12
+ end
13
+
14
+ describe 'parallel' do
15
+ would 'have correct times' do
16
+ check(5..11, 2..4).parallel(1) do |times, parallel|
17
+ mutex = Mutex.new
18
+ array = []
19
+ mock(Thread).new.times(parallel)
20
+
21
+ check.times(times).parallel(parallel) do
22
+ mutex.synchronize{ array << true }
23
+ end
24
+
25
+ Muack.verify.should.eq true
26
+ array.size.should.eq times
27
+ end
28
+ end
29
+
30
+ would 'raise error immediately if not running in parallels' do
31
+ begin
32
+ t = -1
33
+ check.times(10).parallel(1) do
34
+ t += 1
35
+ raise 'boom'
36
+ end
37
+ rescue => e
38
+ t .should.eq 0
39
+ e.class.should.eq RuntimeError
40
+ end
41
+ end
42
+
43
+ would 'capture errors and report if we are running in parallels' do
44
+ check(4..8) do |parallel|
45
+ check(1..parallel) do |errors|
46
+ t = -1
47
+ m = Mutex.new
48
+ begin
49
+ check.times(10).parallel(parallel) do
50
+ m.synchronize do
51
+ t += 1
52
+ raise t.to_s if t < errors
53
+ end
54
+ end
55
+ rescue RubyQC::Error => e
56
+ e.times .should.eq RubyQC.default_times
57
+ e.errors.size.should.eq errors
58
+ e.errors.map(&:message).sort.each.with_index do |msg, index|
59
+ msg.should.eq index.to_s
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,34 @@
1
+
2
+ require 'rubyqc/test'
3
+
4
+ describe 'prelude' do
5
+ would 'lambda' do
6
+ i = 0
7
+ k = 0
8
+ check(lambda{ i += 1 }).parallel(1) do |j|
9
+ k += 1
10
+ i.should.eq j
11
+ i.should.eq k
12
+ end
13
+ end
14
+
15
+ describe 'kind_of' do
16
+ [Fixnum, Bignum, Array, Integer, Class].each do |klass|
17
+ would klass.name do
18
+ check(klass){ |obj| obj.should.kind_of?(klass) }
19
+ end
20
+ end
21
+
22
+ [[], [Fixnum], [Fixnum, Array],
23
+ {}, {:a => 0}, {'b' => 1}, {2 => Integer},
24
+ {nil => [Fixnum]}, {true => {false => [Bignum]}}
25
+ ].each do |spec|
26
+
27
+ would spec.inspect do
28
+ check(spec) do |generated|
29
+ verify_generated(generated, spec)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -3,7 +3,7 @@ require 'rubyqc/test'
3
3
 
4
4
  describe Array do
5
5
  describe 'sort' do
6
- should 'Any front elements should be <= any rear elements' do
6
+ would 'Any front elements should be <= any rear elements' do
7
7
  check([Fixnum]*100).times(10) do |array|
8
8
  array.sort.each_cons(2).each{ |x, y| x.should <= y }
9
9
  end
@@ -13,7 +13,7 @@ end
13
13
 
14
14
  describe Hash do
15
15
  describe 'compare_by_identity' do
16
- should 'Treat diff arr with the same contents diff when set' do
16
+ would 'Treat diff arr with the same contents diff when set' do
17
17
  arr = [0]
18
18
  forall(booleans, [arr, [0]], [arr, [1]]) do |flag, a, b|
19
19
  h = {}
@@ -37,11 +37,11 @@ class User < Struct.new(:id, :name)
37
37
  end
38
38
 
39
39
  describe 'User.rubyqc' do
40
- should 'Generate random users' do
40
+ would 'Generate random users' do
41
41
  check(User) do |user|
42
- user .should.kind_of User
43
- user.id .should.kind_of Fixnum
44
- user.name.should.kind_of String
42
+ user .should.kind_of? User
43
+ user.id .should.kind_of? Fixnum
44
+ user.name.should.kind_of? String
45
45
  end
46
46
  end
47
47
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubyqc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lin Jen-Shin (godfat)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-18 00:00:00.000000000 Z
11
+ date: 2014-08-01 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |-
14
14
  RubyQC -- A conceptual [QuickCheck][] library for Ruby.
@@ -35,6 +35,7 @@ files:
35
35
  - lib/rubyqc.rb
36
36
  - lib/rubyqc/all.rb
37
37
  - lib/rubyqc/api.rb
38
+ - lib/rubyqc/error.rb
38
39
  - lib/rubyqc/modifier.rb
39
40
  - lib/rubyqc/prelude.rb
40
41
  - lib/rubyqc/stdlib.rb
@@ -51,7 +52,8 @@ files:
51
52
  - task/README.md
52
53
  - task/gemgem.rb
53
54
  - test/test_api.rb
54
- - test/test_kind_of.rb
55
+ - test/test_modifier.rb
56
+ - test/test_prelude.rb
55
57
  - test/test_readme.rb
56
58
  homepage: https://github.com/godfat/rubyqc
57
59
  licenses:
@@ -73,11 +75,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
75
  version: '0'
74
76
  requirements: []
75
77
  rubyforge_project:
76
- rubygems_version: 2.2.2
78
+ rubygems_version: 2.4.1
77
79
  signing_key:
78
80
  specification_version: 4
79
81
  summary: RubyQC -- A conceptual [QuickCheck][] library for Ruby.
80
82
  test_files:
81
83
  - test/test_api.rb
82
- - test/test_kind_of.rb
84
+ - test/test_modifier.rb
85
+ - test/test_prelude.rb
83
86
  - test/test_readme.rb
@@ -1,22 +0,0 @@
1
-
2
- require 'rubyqc/test'
3
-
4
- describe 'kind_of' do
5
- [Fixnum, Bignum, Array, Integer, Class].each do |klass|
6
- should klass.name do
7
- check(klass){ |obj| obj.should.kind_of(klass) }
8
- end
9
- end
10
-
11
- [[], [Fixnum], [Fixnum, Array],
12
- {}, {:a => 0}, {'b' => 1}, {2 => Integer},
13
- {nil => [Fixnum]}, {true => {false => [Bignum]}}
14
- ].each do |spec|
15
-
16
- should spec.inspect do
17
- check(spec) do |generated|
18
- verify_generated(generated, spec)
19
- end
20
- end
21
- end
22
- end