hypothesis-specs 0.1.0 → 0.4.0

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
  SHA256:
3
- metadata.gz: 0c8b0daf467cfba3ff5d8713fca58165154c19dbe24a9c063337da10244a4858
4
- data.tar.gz: 5220bf53ee4d96028f54ffc0cb3513f263e06b5edb53a549a00bc3e4720ddbaf
3
+ metadata.gz: 748dfd8fb0c05573aecd17da1fb658a3d3add0ae731e16dc8f3f9274cd5db006
4
+ data.tar.gz: ffd23f44bd8fa7eaca616cc00bc497033d6c9557761c8ffacdc756d3b6bad080
5
5
  SHA512:
6
- metadata.gz: a33f06784dec07894b9d0bb3ff0bd8366c78d0a332e25c9fac5e5589b6026f7cacc22a12575c1010416116f3527e07b9603a2da96e763148b9bdaa3ca1d085b9
7
- data.tar.gz: a92b046f6384b42a6e28d836a29b6f654944fc9a8cccd6ff27ff6b8682a9d9588a7c326177aca48e6376866754fcda85c15b0734e728cc905d69fae146ac7683
6
+ metadata.gz: a1e26c552c6baaf4fcf3fa1ef3784ad911c5a06c1582b3153daf09b6f618900656ac08f2377c9fba834e5a1ecd2a2ae90d6f33a542b457fb23db30760265b058
7
+ data.tar.gz: 2fd4b38d077f32f978010612c72a613b4692f6299b4d5b66885afffe6b22180a4f834d5769f456b29f00a7eb3dc2b31246cae7a7410e2532d183aa61c5651b02
@@ -1,3 +1,33 @@
1
+ # Hypothesis for Ruby 0.4.0 (2021-01-12)
2
+
3
+ This removes hypothesis-ruby's dependence on RSpec. Now, it can be used with any Ruby test runner.
4
+
5
+ # Hypothesis for Ruby 0.3.0 (2021-01-08)
6
+
7
+ This release converts Hypothesis for Ruby to use [RuTie](https://github.com/danielpclark/rutie)
8
+ instead of the deprecated [Helix](https://github.com/tildeio/helix), restoring compatibility
9
+ with recent versions of Rust. Thanks to Alex Weisberger for taking this on!
10
+
11
+ # Hypothesis for Ruby 0.2.0 (2018-10-24)
12
+
13
+ This release adds an example database to Hypothesis for Ruby. This means that when a test fails,
14
+ it will automatically reuse the previously shown example when you rerun it, without having to
15
+ manually pass a seed.
16
+
17
+ # Hypothesis for Ruby 0.1.2 (2018-09-24)
18
+
19
+ This release makes the code useable via a direct require.
20
+ I.e. no need for rubygems or any special LOAD_PATH.
21
+
22
+ For example, if the base directory were in /opt, you'd just say:
23
+ require "/opt/hypothesis/hypothesis-ruby/lib/hypothesis"
24
+
25
+ # Hypothesis for Ruby 0.1.1 (2018-08-31)
26
+
27
+ This release fixes minor documentation issues.
28
+
29
+ Thanks to Tessa Bradbury for this contribution.
30
+
1
31
  # Hypothesis for Ruby 0.1.0 (2018-07-16)
2
32
 
3
33
  This release adds support for reporting multiple exceptions when Hypothesis
data/Cargo.toml CHANGED
@@ -1,12 +1,14 @@
1
1
  [package]
2
2
  name = "hypothesis-ruby"
3
3
  version = "0.1.0"
4
- authors = ["David R. MacIver <david@drmaciver.com>"]
4
+ authors = ["David R. MacIver <david@drmaciver.com>", "Alex Wiesberger <alex.m.weisberger@gmail.com>"]
5
5
 
6
6
  [lib]
7
+ name="hypothesis_ruby_core"
7
8
  crate-type = ["cdylib"]
8
9
 
9
10
  [dependencies]
10
- helix = '0.7.5'
11
+ rutie = {version="0.8.1"}
12
+ lazy_static = "1.4.0"
11
13
  rand = '0.3'
12
- conjecture = '0.3.0'
14
+ conjecture = '0.4.0'
@@ -1,7 +1,7 @@
1
1
  Copyright (c) 2018, David R. MacIver
2
2
 
3
3
  All code in this repository except where explicitly noted otherwise is released
4
- under the Mozilla Public License v 2.0. You can obtain a copy at http://mozilla.org/MPL/2.0/.
4
+ under the Mozilla Public License v 2.0. You can obtain a copy at https://mozilla.org/MPL/2.0/.
5
5
 
6
6
  Some code in this repository may come from other projects. Where applicable, the
7
7
  original copyright and license are noted and any modifications made are released
@@ -32,7 +32,7 @@ RSpec.describe "removing an element from a list" do
32
32
 
33
33
  values.delete_at(values.index(to_remove))
34
34
 
35
- # Will fail if the value ws duplicated in the list.
35
+ # Will fail if the value was duplicated in the list.
36
36
  expect(values.include?(to_remove)).to be false
37
37
 
38
38
  end
@@ -71,7 +71,7 @@ Right now this is really more to allow you to try it out and provide feedback th
71
71
  The more feedback we get, the sooner it will get there!
72
72
 
73
73
  Note that in order to use Hypothesis for Ruby, you will need a rust toolchain installed.
74
- Please go to [https://www.rustup.rs](https://www.rustup.rs) and follow the instructions if you do not already have one.
74
+ Please go to [https://www.rustup.rs](https://www.rustup.rs) and follow the instructions if you do not already have one. You will most likely need to compile your Ruby executable with the `--enable-shared` option. See [here](https://github.com/danielpclark/rutie#dynamic-vs-static-builds).
75
75
 
76
76
  ## Project Status
77
77
 
data/Rakefile CHANGED
@@ -1,10 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rubygems'
4
- require 'helix_runtime/build_task'
5
4
  require 'date'
6
5
  require 'open3'
7
6
 
7
+ task :build do
8
+ sh('cargo build --release')
9
+ end
10
+
8
11
  begin
9
12
  require 'rspec/core/rake_task'
10
13
  RSpec::Core::RakeTask.new(:spec)
@@ -17,10 +20,24 @@ begin
17
20
  end
18
21
 
19
22
  task test: %i[build spec minitests]
23
+ task rspec: %i[build spec]
24
+ task minitest: %i[build without_rspec] do
25
+ begin
26
+ Rake::Task['minitests'].execute
27
+ ensure
28
+ Rake::Task['with_rspec'].execute
29
+ end
30
+ end
20
31
  rescue LoadError
21
32
  end
22
33
 
23
- HelixRuntime::BuildTask.new
34
+ task :without_rspec do
35
+ sh('bundle config set without rspec')
36
+ end
37
+
38
+ task :with_rspec do
39
+ sh('bundle config unset without')
40
+ end
24
41
 
25
42
  def rubocop(fix:)
26
43
  sh "bundle exec rubocop #{'-a' if fix} lib spec minitests " \
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'hypothesis/junkdrawer'
4
- require 'hypothesis/errors'
5
- require 'hypothesis/possible'
6
- require 'hypothesis/testcase'
7
- require 'hypothesis/engine'
8
- require 'hypothesis/world'
3
+ require_relative 'hypothesis/junkdrawer'
4
+ require_relative 'hypothesis/errors'
5
+ require_relative 'hypothesis/possible'
6
+ require_relative 'hypothesis/testcase'
7
+ require_relative 'hypothesis/engine'
8
+ require_relative 'hypothesis/world'
9
9
 
10
10
  # This is the main module for using Hypothesis.
11
11
  # It is expected that you will include this in your
@@ -19,6 +19,23 @@ require 'hypothesis/world'
19
19
  module Hypothesis
20
20
  # @!visibility private
21
21
  HYPOTHESIS_LOCATION = File.dirname(__FILE__)
22
+ # rubocop:disable ClassVars
23
+ @@setup_called = false
24
+ # rubocop:enable RuleByName
25
+
26
+ def self.setup_called
27
+ @@setup_called == true
28
+ end
29
+
30
+ def self.included(*)
31
+ if setup_called == false
32
+ Rutie.new(:hypothesis_ruby_core).init(
33
+ 'Init_rutie_hypothesis_core',
34
+ __dir__
35
+ )
36
+ end
37
+ @@setup_called = true
38
+ end
22
39
 
23
40
  # @!visibility private
24
41
  def hypothesis_stable_identifier
@@ -122,7 +139,7 @@ module Hypothesis
122
139
  # of the block is a *test case*.
123
140
  # A test case has three important features:
124
141
  #
125
- # * *givens* are the result of a call to self.given, and are the
142
+ # * *givens* are the result of a call to self.any, and are the
126
143
  # values that make up the test case. These might be values such
127
144
  # as strings, integers, etc. or they might be values specific to
128
145
  # your application such as a User object.
@@ -140,12 +157,21 @@ module Hypothesis
140
157
  #
141
158
  # A call to hypothesis does the following:
142
159
  #
143
- # 1. It tries to *generate* a failing test case.
144
- # 2. If it succeeded then it will *shrink* that failing test case.
145
- # 3. Finally, it will *display* the shrunk failing test case by
160
+ # 1. It first tries to *reuse* failing test cases for previous runs.
161
+ # 2. If there were no previous failing test cases then it tries to
162
+ # *generate* new failing test cases.
163
+ # 3. If either of the first two phases found failing test cases then
164
+ # it will *shrink* those failing test cases.
165
+ # 4. Finally, it will *display* the shrunk failing test case by
146
166
  # the error from its failing assertion, modified to show the
147
167
  # givens of the test case.
148
168
  #
169
+ # Reuse uses an internal representation of the test case, so examples
170
+ # from previous runs will obey all of the usual invariants of generation.
171
+ # However, this means that if you change your test then reuse may not
172
+ # work. Test cases that have become invalid or passing will be cleaned
173
+ # up automatically.
174
+ #
149
175
  # Generation consists of randomly trying test cases until one of
150
176
  # three things has happened:
151
177
  #
@@ -170,13 +196,21 @@ module Hypothesis
170
196
  #
171
197
  # @param max_valid_test_cases [Integer] The maximum number of valid test
172
198
  # cases to run without finding a failing test case before stopping.
173
- def hypothesis(max_valid_test_cases: 200, &block)
199
+ #
200
+ # @param database [String, nil, false] A path to a directory where Hypothesis
201
+ # should store previously failing test cases. If it is nil, Hypothesis
202
+ # will use a default of .hypothesis/examples in the current directory.
203
+ # May also be set to false to disable the database functionality.
204
+ def hypothesis(max_valid_test_cases: 200, database: nil, &block)
174
205
  unless World.current_engine.nil?
175
206
  raise UsageError, 'Cannot nest hypothesis calls'
176
207
  end
208
+
177
209
  begin
178
210
  World.current_engine = Engine.new(
179
- max_examples: max_valid_test_cases
211
+ hypothesis_stable_identifier,
212
+ max_examples: max_valid_test_cases,
213
+ database: database
180
214
  )
181
215
  World.current_engine.run(&block)
182
216
  ensure
@@ -1,20 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'helix_runtime'
4
- require 'hypothesis-ruby/native'
5
- require 'rspec/expectations'
3
+ require 'rutie'
6
4
 
7
5
  module Hypothesis
8
- class Engine
9
- include RSpec::Matchers
6
+ DEFAULT_DATABASE_PATH = File.join(Dir.pwd, '.hypothesis', 'examples')
10
7
 
8
+ class Engine
11
9
  attr_reader :current_source
12
10
  attr_accessor :is_find
13
11
 
14
- def initialize(options)
12
+ def initialize(name, options)
15
13
  seed = Random.rand(2**64 - 1)
14
+
15
+ database = options.fetch(:database, nil)
16
+
17
+ database = DEFAULT_DATABASE_PATH if database.nil?
18
+
19
+ database = nil if database == false
20
+
16
21
  @core_engine = HypothesisCoreEngine.new(
17
- seed, options.fetch(:max_examples)
22
+ name, database, seed, options.fetch(:max_examples)
18
23
  )
19
24
 
20
25
  @exceptions_to_tags = Hash.new { |h, k| h[k] = h.size }
@@ -111,7 +111,7 @@ module Hypothesis
111
111
  # two names: A singular and a plural name. These are
112
112
  # simply aliases and are identical in every way, but are
113
113
  # provided to improve readability. For example
114
- # `any integer` reads better than `given integers`
114
+ # `any integer` reads better than `any integers`
115
115
  # but `arrays(of: integers)` reads better than
116
116
  # `arrays(of: integer)`.
117
117
  module Possibilities
@@ -124,7 +124,7 @@ module Hypothesis
124
124
  # built_as lets you chain multiple Possible values together,
125
125
  # by providing whatever value results from its block.
126
126
  #
127
- # For example the following provides a array plus some
127
+ # For example the following provides an array plus some
128
128
  # element from that array:
129
129
  #
130
130
  # ```ruby
@@ -135,6 +135,7 @@ module Hypothesis
135
135
  # assume ls.size > 0
136
136
  # i = any element_of(ls)
137
137
  # [ls, i]
138
+ # end
138
139
  # ```
139
140
  #
140
141
  # @return [Possible] A Possible whose possible values are
@@ -177,7 +178,7 @@ module Hypothesis
177
178
  # valid.
178
179
  # @param min_size [Integer] The smallest valid length for a
179
180
  # provided string
180
- # @param max_size [Integer] The smallest valid length for a
181
+ # @param max_size [Integer] The largest valid length for a
181
182
  # provided string
182
183
  def strings(codepoints: nil, min_size: 0, max_size: 10)
183
184
  codepoints = self.codepoints if codepoints.nil?
@@ -263,9 +264,9 @@ module Hypothesis
263
264
  alias array_of_shape arrays_of_shape
264
265
 
265
266
  # A Possible Array of variable shape.
266
- # This is used for arrays where all of the elements come from
267
- # the size may vary and the same values are possible at any position.
268
- # For example, arrays(booleans) might provide [false, true, false].
267
+ # This is used for arrays where the size may vary and the same values
268
+ # are possible at any position.
269
+ # For example, arrays(of: booleans) might provide [false, true, false].
269
270
  # @return [Possible]
270
271
  # @param of [Possible] The possible elements of the array.
271
272
  # @param min_size [Integer] The smallest valid size of a provided array
data/src/lib.rs CHANGED
@@ -1,187 +1,469 @@
1
- // "Bridging" root code that exists exclusively to provide
2
- // a ruby -> Hypothesis engine binding. Long term the code
3
- // in here is the only code that is going to stay in this
4
- // crate, and everything else is going to get factored out
5
- // into its own.
6
-
7
- #![recursion_limit = "256"]
8
- #![deny(warnings, missing_debug_implementations)]
9
-
10
- extern crate core;
11
1
  #[macro_use]
12
- extern crate helix;
13
- extern crate rand;
2
+ extern crate rutie;
3
+ #[macro_use]
4
+ extern crate lazy_static;
14
5
  extern crate conjecture;
15
6
 
16
7
  use std::mem;
17
8
 
9
+ use rutie::{AnyException, AnyObject, Boolean, Class, Float, Integer, NilClass, Object, RString, VM};
10
+
18
11
  use conjecture::data::{DataSource, Status, TestResult};
19
- use conjecture::distributions::Repeat;
12
+ use conjecture::database::{BoxedDatabase, DirectoryDatabase, NoDatabase};
20
13
  use conjecture::distributions;
14
+ use conjecture::distributions::Repeat;
21
15
  use conjecture::engine::Engine;
22
16
 
23
- ruby! {
24
- class HypothesisCoreDataSource {
25
- struct {
26
- source: Option<DataSource>,
17
+ pub struct HypothesisCoreDataSourceStruct {
18
+ source: Option<DataSource>,
19
+ }
20
+
21
+ impl HypothesisCoreDataSourceStruct {
22
+ fn new(engine: &mut HypothesisCoreEngineStruct) -> HypothesisCoreDataSourceStruct {
23
+ HypothesisCoreDataSourceStruct {
24
+ source: mem::take(&mut engine.pending),
25
+ }
26
+ }
27
+
28
+ fn start_draw(&mut self) {
29
+ if let Some(ref mut source) = self.source {
30
+ source.start_draw();
31
+ }
27
32
  }
28
33
 
29
- def initialize(helix, engine: &mut HypothesisCoreEngine){
30
- let mut result = HypothesisCoreDataSource{helix, source: None};
31
- mem::swap(&mut result.source, &mut engine.pending);
32
- return result;
34
+ fn stop_draw(&mut self) {
35
+ if let Some(ref mut source) = self.source {
36
+ source.stop_draw();
37
+ }
33
38
  }
39
+ }
40
+
41
+ wrappable_struct!(
42
+ HypothesisCoreDataSourceStruct,
43
+ HypothesisCoreDataSourceStructWrapper,
44
+ HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER
45
+ );
46
+
47
+ class!(HypothesisCoreDataSource);
48
+
49
+ methods!(
50
+ HypothesisCoreDataSource,
51
+ itself,
52
+ fn ruby_hypothesis_core_data_source_start_draw() -> NilClass {
53
+ itself
54
+ .get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER)
55
+ .start_draw();
34
56
 
35
- def start_draw(&mut self){
36
- if let &mut Some(ref mut source) = &mut self.source {
37
- source.start_draw();
38
- }
57
+ NilClass::new()
39
58
  }
59
+ fn ruby_hypothesis_core_data_source_stop_draw() -> NilClass {
60
+ itself
61
+ .get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER)
62
+ .stop_draw();
40
63
 
41
- def stop_draw(&mut self){
42
- if let &mut Some(ref mut source) = &mut self.source {
43
- source.stop_draw();
44
- }
64
+ NilClass::new()
45
65
  }
46
- }
66
+ );
47
67
 
48
- class HypothesisCoreEngine {
49
- struct {
50
- engine: Engine,
51
- pending: Option<DataSource>,
52
- interesting_examples: Vec<TestResult>,
68
+ pub struct HypothesisCoreEngineStruct {
69
+ engine: Engine,
70
+ pending: Option<DataSource>,
71
+ interesting_examples: Vec<TestResult>,
72
+ }
73
+
74
+ impl HypothesisCoreEngineStruct {
75
+ fn new(
76
+ name: String,
77
+ database_path: Option<String>,
78
+ seed: u64,
79
+ max_examples: u64,
80
+ ) -> HypothesisCoreEngineStruct {
81
+ let xs: [u32; 2] = [seed as u32, (seed >> 32) as u32];
82
+ let db: BoxedDatabase = match database_path {
83
+ None => Box::new(NoDatabase),
84
+ Some(path) => Box::new(DirectoryDatabase::new(path)),
85
+ };
86
+
87
+ HypothesisCoreEngineStruct {
88
+ engine: Engine::new(name, max_examples, &xs, db),
89
+ pending: None,
90
+ interesting_examples: Vec::new(),
91
+ }
53
92
  }
54
93
 
55
- def initialize(helix, seed: u64, max_examples: u64){
56
- let xs: [u32; 2] = [seed as u32, (seed >> 32) as u32];
57
- HypothesisCoreEngine{
58
- helix,
59
- engine: Engine::new(max_examples, &xs),
60
- pending: None,
61
- interesting_examples: Vec::new(),
62
- }
94
+ fn new_source(&mut self) -> Option<HypothesisCoreDataSourceStruct> {
95
+ match self.engine.next_source() {
96
+ None => {
97
+ self.interesting_examples = self.engine.list_minimized_examples();
98
+ None
99
+ }
100
+ Some(source) => {
101
+ self.pending = Some(source);
102
+ Some(HypothesisCoreDataSourceStruct::new(self))
103
+ }
104
+ }
63
105
  }
64
106
 
65
- def new_source(&mut self) -> Option<HypothesisCoreDataSource> {
66
- match self.engine.next_source() {
67
- None => {
68
- self.interesting_examples = self.engine.list_minimized_examples();
69
- None
70
- },
71
- Some(source) => {
72
- self.pending = Some(source);
73
- Some(HypothesisCoreDataSource::new(self))
74
- },
75
- }
107
+ fn count_failing_examples(&self) -> usize {
108
+ self.interesting_examples.len()
76
109
  }
77
110
 
78
- def count_failing_examples(&self) -> usize {
79
- self.interesting_examples.len()
111
+ fn failing_example(&mut self, i: usize) -> HypothesisCoreDataSourceStruct {
112
+ self.pending = Some(DataSource::from_vec(
113
+ self.interesting_examples[i].record.clone(),
114
+ ));
115
+ HypothesisCoreDataSourceStruct::new(self)
80
116
  }
81
117
 
82
- def failing_example(&mut self, i: usize) -> HypothesisCoreDataSource {
83
- self.pending = Some(
84
- DataSource::from_vec(self.interesting_examples[i].record.clone())
85
- );
86
- HypothesisCoreDataSource::new(self)
118
+ fn was_unsatisfiable(&mut self) -> bool {
119
+ self.engine.was_unsatisfiable()
87
120
  }
88
121
 
89
- def was_unsatisfiable(&mut self) -> bool {
90
- self.engine.was_unsatisfiable()
122
+ fn finish_overflow(&mut self, child: &mut HypothesisCoreDataSourceStruct) {
123
+ mark_child_status(&mut self.engine, child, Status::Overflow);
91
124
  }
92
125
 
93
- def finish_overflow(&mut self, child: &mut HypothesisCoreDataSource){
94
- mark_child_status(&mut self.engine, child, Status::Overflow);
126
+ fn finish_valid(&mut self, child: &mut HypothesisCoreDataSourceStruct) {
127
+ mark_child_status(&mut self.engine, child, Status::Valid);
95
128
  }
96
129
 
97
- def finish_invalid(&mut self, child: &mut HypothesisCoreDataSource){
98
- mark_child_status(&mut self.engine, child, Status::Invalid);
130
+ fn finish_invalid(&mut self, child: &mut HypothesisCoreDataSourceStruct) {
131
+ mark_child_status(&mut self.engine, child, Status::Invalid);
132
+ }
133
+
134
+ fn finish_interesting(&mut self, child: &mut HypothesisCoreDataSourceStruct, label: u64) {
135
+ mark_child_status(&mut self.engine, child, Status::Interesting(label));
136
+ }
137
+ }
138
+
139
+ wrappable_struct!(
140
+ HypothesisCoreEngineStruct,
141
+ HypothesisCoreEngineStructWrapper,
142
+ HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER
143
+ );
144
+
145
+ class!(HypothesisCoreEngine);
146
+
147
+ methods!(
148
+ HypothesisCoreEngine,
149
+ itself,
150
+ fn ruby_hypothesis_core_engine_new(
151
+ name: RString,
152
+ database_path: RString,
153
+ seed: Integer,
154
+ max_example: Integer
155
+ ) -> AnyObject {
156
+ let core_engine = HypothesisCoreEngineStruct::new(
157
+ safe_access(name).to_string(),
158
+ database_path.ok().map(|p| p.to_string()),
159
+ safe_access(seed).to_u64(),
160
+ safe_access(max_example).to_u64(),
161
+ );
162
+
163
+ Class::from_existing("HypothesisCoreEngine")
164
+ .wrap_data(core_engine, &*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER)
165
+ }
166
+ fn ruby_hypothesis_core_engine_new_source() -> AnyObject {
167
+ match itself
168
+ .get_data_mut(&*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER)
169
+ .new_source()
170
+ {
171
+ Some(ds) => Class::from_existing("HypothesisCoreDataSource")
172
+ .wrap_data(ds, &*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER),
173
+ None => NilClass::new().into(),
174
+ }
175
+ }
176
+ fn ruby_hypothesis_core_engine_finish_overflow(child: AnyObject) -> NilClass {
177
+ let core_engine = itself.get_data_mut(&*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER);
178
+ let mut rdata_source = safe_access(child);
179
+ let data_source = rdata_source.get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER);
180
+
181
+ core_engine.finish_overflow(data_source);
182
+
183
+ NilClass::new()
184
+ }
185
+ fn ruby_hypothesis_core_engine_finish_valid(child: AnyObject) -> NilClass {
186
+ let core_engine = itself.get_data_mut(&*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER);
187
+ let mut rdata_source = safe_access(child);
188
+ let data_source = rdata_source.get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER);
189
+
190
+ core_engine.finish_valid(data_source);
191
+
192
+ NilClass::new()
193
+ }
194
+ fn ruby_hypothesis_core_engine_finish_invalid(child: AnyObject) -> NilClass {
195
+ let core_engine = itself.get_data_mut(&*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER);
196
+ let mut rdata_source = safe_access(child);
197
+ let data_source = rdata_source.get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER);
198
+
199
+ core_engine.finish_invalid(data_source);
200
+
201
+ NilClass::new()
99
202
  }
203
+ fn ruby_hypothesis_core_engine_finish_interesting(
204
+ child: AnyObject,
205
+ label: Integer
206
+ ) -> NilClass {
207
+ let core_engine = itself.get_data_mut(&*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER);
208
+ let mut rdata_source = safe_access(child);
209
+ let data_source = rdata_source.get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER);
100
210
 
101
- def finish_interesting(&mut self, child: &mut HypothesisCoreDataSource, label: u64){
102
- mark_child_status(&mut self.engine, child, Status::Interesting(label));
211
+ core_engine.finish_interesting(data_source, safe_access(label).to_u64());
212
+
213
+ NilClass::new()
103
214
  }
215
+ fn ruby_hypothesis_core_engine_count_failing_examples() -> Integer {
216
+ let core_engine = itself.get_data(&*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER);
104
217
 
105
- def finish_valid(&mut self, child: &mut HypothesisCoreDataSource){
106
- mark_child_status(&mut self.engine, child, Status::Valid);
218
+ Integer::new(core_engine.count_failing_examples() as i64)
107
219
  }
108
- }
220
+ fn ruby_hypothesis_core_failing_example(i: Integer) -> AnyObject {
221
+ let core_engine = itself.get_data_mut(&*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER);
222
+ let int = safe_access(i).to_u64() as usize;
223
+
224
+ let data_source = core_engine.failing_example(int);
109
225
 
110
- class HypothesisCoreBitPossible{
111
- struct {
112
- n_bits: u64,
226
+ Class::from_existing("HypothesisCoreDataSource")
227
+ .wrap_data(data_source, &*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER)
113
228
  }
229
+ fn ruby_hypothesis_core_engine_was_unsatisfiable() -> Boolean {
230
+ let core_engine = itself.get_data_mut(&*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER);
114
231
 
115
- def initialize(helix, n_bits: u64){
116
- return HypothesisCoreBitPossible{helix, n_bits: n_bits};
232
+ Boolean::new(core_engine.was_unsatisfiable())
117
233
  }
234
+ );
118
235
 
119
- def provide(&mut self, data: &mut HypothesisCoreDataSource) -> Option<u64>{
120
- match &mut data.source {
121
- &mut None => None,
122
- &mut Some(ref mut source) => source.bits(self.n_bits).ok(),
123
- }
236
+ pub struct HypothesisCoreIntegersStruct {
237
+ bitlengths: distributions::Sampler,
238
+ }
239
+
240
+ impl HypothesisCoreIntegersStruct {
241
+ fn new() -> HypothesisCoreIntegersStruct {
242
+ HypothesisCoreIntegersStruct {
243
+ bitlengths: distributions::good_bitlengths(),
244
+ }
124
245
  }
125
- }
126
246
 
127
- class HypothesisCoreRepeatValues{
128
- struct {
129
- repeat: Repeat,
247
+ fn provide(&mut self, data: &mut HypothesisCoreDataSourceStruct) -> Option<i64> {
248
+ data.source.as_mut().and_then(|ref mut source| {
249
+ distributions::integer_from_bitlengths(source, &self.bitlengths).ok()
250
+ })
130
251
  }
252
+ }
131
253
 
132
- def initialize(helix, min_count: u64, max_count: u64, expected_count: f64){
133
- return HypothesisCoreRepeatValues{
134
- helix, repeat: Repeat::new(min_count, max_count, expected_count)
135
- }
254
+ wrappable_struct!(
255
+ HypothesisCoreIntegersStruct,
256
+ HypothesisCoreIntegersStructWrapper,
257
+ HYPOTHESIS_CORE_INTEGERS_STRUCT_WRAPPER
258
+ );
259
+
260
+ class!(HypothesisCoreIntegers);
261
+
262
+ methods!(
263
+ HypothesisCoreIntegers,
264
+ itself,
265
+ fn ruby_hypothesis_core_integers_new() -> AnyObject {
266
+ let core_integers = HypothesisCoreIntegersStruct::new();
267
+
268
+ Class::from_existing("HypothesisCoreIntegers")
269
+ .wrap_data(core_integers, &*HYPOTHESIS_CORE_INTEGERS_STRUCT_WRAPPER)
136
270
  }
271
+ fn ruby_hypothesis_core_integers_provide(data: AnyObject) -> AnyObject {
272
+ let core_integers = itself.get_data_mut(&*HYPOTHESIS_CORE_INTEGERS_STRUCT_WRAPPER);
273
+ let mut rdata = safe_access(data);
274
+ let data_source = rdata.get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER);
137
275
 
138
- def _should_continue(&mut self, data: &mut HypothesisCoreDataSource) -> Option<bool>{
139
- return data.source.as_mut().and_then(|ref mut source| {
140
- self.repeat.should_continue(source).ok()
141
- })
276
+ match core_integers.provide(data_source) {
277
+ Some(i) => Integer::new(i).into(),
278
+ None => NilClass::new().into(),
279
+ }
142
280
  }
281
+ );
282
+
283
+ pub struct HypothesisCoreRepeatValuesStruct {
284
+ repeat: Repeat,
285
+ }
143
286
 
144
- def reject(&mut self){
145
- self.repeat.reject();
287
+ impl HypothesisCoreRepeatValuesStruct {
288
+ fn new(
289
+ min_count: u64,
290
+ max_count: u64,
291
+ expected_count: f64,
292
+ ) -> HypothesisCoreRepeatValuesStruct {
293
+ HypothesisCoreRepeatValuesStruct {
294
+ repeat: Repeat::new(min_count, max_count, expected_count),
295
+ }
146
296
  }
147
- }
148
297
 
149
- class HypothesisCoreIntegers{
150
- struct {
151
- bitlengths: distributions::Sampler,
298
+ fn _should_continue(&mut self, data: &mut HypothesisCoreDataSourceStruct) -> Option<bool> {
299
+ return data
300
+ .source
301
+ .as_mut()
302
+ .and_then(|ref mut source| self.repeat.should_continue(source).ok());
152
303
  }
153
- def initialize(helix){
154
- return HypothesisCoreIntegers{helix,bitlengths: distributions::good_bitlengths()};
304
+
305
+ fn reject(&mut self) {
306
+ self.repeat.reject();
155
307
  }
156
- def provide(&mut self, data: &mut HypothesisCoreDataSource) -> Option<i64>{
157
- data.source.as_mut().and_then(|ref mut source| {
158
- distributions::integer_from_bitlengths(source, &self.bitlengths).ok()
159
- })
308
+ }
309
+
310
+ wrappable_struct!(
311
+ HypothesisCoreRepeatValuesStruct,
312
+ HypothesisCoreRepeatValuesStructWrapper,
313
+ HYPOTHESIS_CORE_REPEAT_VALUES_STRUCT_WRAPPER
314
+ );
315
+
316
+ class!(HypothesisCoreRepeatValues);
317
+
318
+ methods!(
319
+ HypothesisCoreRepeatValues,
320
+ itself,
321
+ fn ruby_hypothesis_core_repeat_values_new(
322
+ min_count: Integer,
323
+ max_count: Integer,
324
+ expected_count: Float
325
+ ) -> AnyObject {
326
+ let repeat_values = HypothesisCoreRepeatValuesStruct::new(
327
+ safe_access(min_count).to_u64(),
328
+ safe_access(max_count).to_u64(),
329
+ safe_access(expected_count).to_f64(),
330
+ );
331
+
332
+ Class::from_existing("HypothesisCoreRepeatValues").wrap_data(
333
+ repeat_values,
334
+ &*HYPOTHESIS_CORE_REPEAT_VALUES_STRUCT_WRAPPER,
335
+ )
160
336
  }
161
- }
337
+ fn ruby_hypothesis_core_repeat_values_should_continue(data: AnyObject) -> AnyObject {
338
+ let mut rdata = safe_access(data);
339
+ let mut data_source = rdata.get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER);
162
340
 
163
- class HypothesisCoreBoundedIntegers{
164
- struct {
165
- max_value: u64,
341
+ let should_continue = itself
342
+ .get_data_mut(&*HYPOTHESIS_CORE_REPEAT_VALUES_STRUCT_WRAPPER)
343
+ ._should_continue(data_source);
344
+
345
+ match should_continue {
346
+ Some(b) => Boolean::new(b).into(),
347
+ None => NilClass::new().into(),
348
+ }
166
349
  }
167
- def initialize(helix, max_value: u64){
168
- return HypothesisCoreBoundedIntegers{helix, max_value: max_value};
350
+ fn ruby_hypothesis_core_repeat_values_reject() -> NilClass {
351
+ let repeat_values = itself.get_data_mut(&*HYPOTHESIS_CORE_REPEAT_VALUES_STRUCT_WRAPPER);
352
+
353
+ repeat_values.reject();
354
+
355
+ NilClass::new()
169
356
  }
357
+ );
358
+
359
+ pub struct HypothesisCoreBoundedIntegersStruct {
360
+ max_value: u64,
361
+ }
170
362
 
171
- def provide(&mut self, data: &mut HypothesisCoreDataSource) -> Option<u64>{
172
- data.source.as_mut().and_then(|ref mut source| {
173
- distributions::bounded_int(source, self.max_value).ok()
174
- })
363
+ impl HypothesisCoreBoundedIntegersStruct {
364
+ fn provide(&mut self, data: &mut HypothesisCoreDataSourceStruct) -> Option<u64> {
365
+ data.source
366
+ .as_mut()
367
+ .and_then(|ref mut source| distributions::bounded_int(source, self.max_value).ok())
175
368
  }
176
- }
177
369
  }
178
370
 
179
- fn mark_child_status(engine: &mut Engine, child: &mut HypothesisCoreDataSource, status: Status) {
180
- let mut replacement = None;
181
- mem::swap(&mut replacement, &mut child.source);
371
+ wrappable_struct!(
372
+ HypothesisCoreBoundedIntegersStruct,
373
+ HypothesisCoreBoundedIntegersStructWrapper,
374
+ HYPOTHESIS_CORE_BOUNDED_INTEGERS_STRUCT_WRAPPER
375
+ );
376
+
377
+ class!(HypothesisCoreBoundedIntegers);
378
+
379
+ methods!(
380
+ HypothesisCoreBoundedIntegers,
381
+ itself,
382
+ fn ruby_hypothesis_core_bounded_integers_new(max_value: Integer) -> AnyObject {
383
+ let bounded_integers = HypothesisCoreBoundedIntegersStruct {
384
+ max_value: safe_access(max_value).to_u64(),
385
+ };
182
386
 
183
- match replacement {
184
- Some(source) => engine.mark_finished(source, status),
185
- None => (),
387
+ Class::from_existing("HypothesisCoreBoundedIntegers").wrap_data(
388
+ bounded_integers,
389
+ &*HYPOTHESIS_CORE_BOUNDED_INTEGERS_STRUCT_WRAPPER,
390
+ )
186
391
  }
392
+ fn ruby_hypothesis_core_bounded_integers_provide(data: AnyObject) -> AnyObject {
393
+ let mut rdata = safe_access(data);
394
+ let data_source = rdata.get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER);
395
+ let bounded_integers =
396
+ itself.get_data_mut(&*HYPOTHESIS_CORE_BOUNDED_INTEGERS_STRUCT_WRAPPER);
397
+
398
+ match bounded_integers.provide(data_source) {
399
+ Some(i) => Integer::from(i).into(),
400
+ None => NilClass::new().into(),
401
+ }
402
+ }
403
+ );
404
+
405
+ #[allow(non_snake_case)]
406
+ #[no_mangle]
407
+ pub extern "C" fn Init_rutie_hypothesis_core() {
408
+ Class::new("HypothesisCoreEngine", None).define(|klass| {
409
+ klass.def_self("new", ruby_hypothesis_core_engine_new);
410
+ klass.def("new_source", ruby_hypothesis_core_engine_new_source);
411
+ klass.def(
412
+ "count_failing_examples",
413
+ ruby_hypothesis_core_engine_count_failing_examples,
414
+ );
415
+ klass.def("failing_example", ruby_hypothesis_core_failing_example);
416
+ klass.def(
417
+ "was_unsatisfiable",
418
+ ruby_hypothesis_core_engine_was_unsatisfiable,
419
+ );
420
+ klass.def(
421
+ "finish_overflow",
422
+ ruby_hypothesis_core_engine_finish_overflow,
423
+ );
424
+ klass.def("finish_valid", ruby_hypothesis_core_engine_finish_valid);
425
+ klass.def("finish_invalid", ruby_hypothesis_core_engine_finish_invalid);
426
+ klass.def(
427
+ "finish_interesting",
428
+ ruby_hypothesis_core_engine_finish_interesting,
429
+ );
430
+ });
431
+
432
+ Class::new("HypothesisCoreDataSource", None).define(|klass| {
433
+ klass.def("start_draw", ruby_hypothesis_core_data_source_start_draw);
434
+ klass.def("stop_draw", ruby_hypothesis_core_data_source_stop_draw);
435
+ });
436
+
437
+ Class::new("HypothesisCoreIntegers", None).define(|klass| {
438
+ klass.def_self("new", ruby_hypothesis_core_integers_new);
439
+ klass.def("provide", ruby_hypothesis_core_integers_provide);
440
+ });
441
+
442
+ Class::new("HypothesisCoreRepeatValues", None).define(|klass| {
443
+ klass.def_self("new", ruby_hypothesis_core_repeat_values_new);
444
+ klass.def(
445
+ "_should_continue",
446
+ ruby_hypothesis_core_repeat_values_should_continue,
447
+ );
448
+ klass.def("reject", ruby_hypothesis_core_repeat_values_reject);
449
+ });
450
+
451
+ Class::new("HypothesisCoreBoundedIntegers", None).define(|klass| {
452
+ klass.def_self("new", ruby_hypothesis_core_bounded_integers_new);
453
+ klass.def("provide", ruby_hypothesis_core_bounded_integers_provide);
454
+ });
455
+ }
456
+
457
+ fn mark_child_status(
458
+ engine: &mut Engine,
459
+ child: &mut HypothesisCoreDataSourceStruct,
460
+ status: Status,
461
+ ) {
462
+ if let Some(source) = mem::take(&mut child.source) {
463
+ engine.mark_finished(source, status)
464
+ }
465
+ }
466
+
467
+ fn safe_access<T>(value: Result<T, AnyException>) -> T {
468
+ value.map_err(VM::raise_ex).unwrap()
187
469
  }
metadata CHANGED
@@ -1,29 +1,30 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hypothesis-specs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David R. Maciver
8
+ - Alex Weisberger
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2018-07-16 00:00:00.000000000 Z
12
+ date: 2021-01-12 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
- name: helix_runtime
15
+ name: rutie
15
16
  requirement: !ruby/object:Gem::Requirement
16
17
  requirements:
17
18
  - - "~>"
18
19
  - !ruby/object:Gem::Version
19
- version: 0.7.0
20
+ version: 0.0.3
20
21
  type: :runtime
21
22
  prerelease: false
22
23
  version_requirements: !ruby/object:Gem::Requirement
23
24
  requirements:
24
25
  - - "~>"
25
26
  - !ruby/object:Gem::Version
26
- version: 0.7.0
27
+ version: 0.0.3
27
28
  - !ruby/object:Gem::Dependency
28
29
  name: rake
29
30
  requirement: !ruby/object:Gem::Requirement
@@ -88,8 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
89
  - !ruby/object:Gem::Version
89
90
  version: '0'
90
91
  requirements: []
91
- rubyforge_project:
92
- rubygems_version: 2.7.6
92
+ rubygems_version: 3.2.5
93
93
  signing_key:
94
94
  specification_version: 4
95
95
  summary: Hypothesis is a powerful, flexible, and easy to use library for property-based