rubyqc 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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