hypothesis-specs 0.2.0 → 0.6.1
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 +4 -4
- data/CHANGELOG.md +38 -0
- data/Cargo.toml +5 -3
- data/LICENSE.txt +1 -1
- data/README.markdown +2 -2
- data/Rakefile +19 -2
- data/lib/hypothesis.rb +47 -1
- data/lib/hypothesis/engine.rb +6 -8
- data/src/lib.rs +428 -126
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a79509b16d94eae8514d1601878d3fb5a1ba1885f385ae7caf27673874508a51
|
4
|
+
data.tar.gz: ebc2a3661f7a1d9b82c839faed66006de0f95357e4615645788cbe3fd074674d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dba3693d2d2ad38d5efa17ffecf2c70148b6cc1a5e5e2c8e7c89673a42efb183bd1fb374f2129cd81cffe974da90514a8f44d73e4c46602596e4910d98bc3340
|
7
|
+
data.tar.gz: 7dd4894162024a4bfc45df2de1b2aa72803d835f5e4f90f87b8cf5397e88ac48d9e6806440622f5f89b4a4cb9eea60429568404b7c965a099733c5d8d008e2a3
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,41 @@
|
|
1
|
+
# Hypothesis for Ruby 0.6.1 (2021-02-01)
|
2
|
+
|
3
|
+
This patch contains minor performance improvements for `HypothesisCoreIntegers` class instantiation.
|
4
|
+
|
5
|
+
# Hypothesis for Ruby 0.6.0 (2021-01-27)
|
6
|
+
|
7
|
+
Adds support for skipping shrinking. While shrinking is extremely helpful and important in general, it has the potential to be quite time consuming. It can be useful to observe a raw failure before choosing to allow the engine to try to shrink. [hypothesis-python](https://hypothesis.readthedocs.io/en/latest/settings.html#phases) already provides the ability to skip shrinking, so there is precedent for this being useful. While `hypothesis-ruby` does not have the concept of other "Phases" yet, we can still start off the API by using this concept.
|
8
|
+
|
9
|
+
Usage:
|
10
|
+
|
11
|
+
```
|
12
|
+
hypothesis(phases: Phase.excluding(:shrink)) do
|
13
|
+
# Failures here will be displayed directly and shrinking will be avoided
|
14
|
+
end
|
15
|
+
```
|
16
|
+
|
17
|
+
# Hypothesis for Ruby 0.5.0 (2021-01-25)
|
18
|
+
|
19
|
+
Adds support for skipping shrinking. While shrinking is extremely helpful and important in general, it has the potential to be quite time consuming. It can be useful to observe a raw failure before choosing to allow the engine to try to shrink. [hypothesis-python](https://hypothesis.readthedocs.io/en/latest/settings.html#phases) already provides the ability to skip shrinking, so there is precedent for this being useful. While `hypothesis-ruby` does not have the concept of other "Phases" yet, we can still start off the API by using this concept.
|
20
|
+
|
21
|
+
Usage:
|
22
|
+
|
23
|
+
```
|
24
|
+
hypothesis(phases: Phase.excluding(:shrink)) do
|
25
|
+
# Failures here will be displayed directly and shrinking will be avoided
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
# Hypothesis for Ruby 0.4.0 (2021-01-12)
|
30
|
+
|
31
|
+
This removes hypothesis-ruby's dependence on RSpec. Now, it can be used with any Ruby test runner.
|
32
|
+
|
33
|
+
# Hypothesis for Ruby 0.3.0 (2021-01-08)
|
34
|
+
|
35
|
+
This release converts Hypothesis for Ruby to use [RuTie](https://github.com/danielpclark/rutie)
|
36
|
+
instead of the deprecated [Helix](https://github.com/tildeio/helix), restoring compatibility
|
37
|
+
with recent versions of Rust. Thanks to Alex Weisberger for taking this on!
|
38
|
+
|
1
39
|
# Hypothesis for Ruby 0.2.0 (2018-10-24)
|
2
40
|
|
3
41
|
This release adds an example database to Hypothesis for Ruby. This means that when a test fails,
|
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 Weisberger <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
|
-
|
11
|
+
rutie = {version="0.8.1"}
|
12
|
+
lazy_static = "1.4.0"
|
11
13
|
rand = '0.3'
|
12
|
-
conjecture = '0.
|
14
|
+
conjecture = '0.7.0'
|
data/LICENSE.txt
CHANGED
@@ -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
|
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
|
data/README.markdown
CHANGED
@@ -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
|
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
|
-
|
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 " \
|
data/lib/hypothesis.rb
CHANGED
@@ -7,6 +7,28 @@ require_relative 'hypothesis/testcase'
|
|
7
7
|
require_relative 'hypothesis/engine'
|
8
8
|
require_relative 'hypothesis/world'
|
9
9
|
|
10
|
+
module Phase
|
11
|
+
SHRINK = :shrink
|
12
|
+
|
13
|
+
module_function
|
14
|
+
|
15
|
+
def all
|
16
|
+
[SHRINK]
|
17
|
+
end
|
18
|
+
|
19
|
+
def excluding(*phases)
|
20
|
+
unknown_phases = phases.reject { |phase| Phase.all.include?(phase) }
|
21
|
+
unless unknown_phases.empty?
|
22
|
+
raise(
|
23
|
+
ArgumentError,
|
24
|
+
"Attempting to exclude unknown phases: #{unknown_phases}"
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
all - phases
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
10
32
|
# This is the main module for using Hypothesis.
|
11
33
|
# It is expected that you will include this in your
|
12
34
|
# tests, but its methods are also available on the
|
@@ -19,6 +41,23 @@ require_relative 'hypothesis/world'
|
|
19
41
|
module Hypothesis
|
20
42
|
# @!visibility private
|
21
43
|
HYPOTHESIS_LOCATION = File.dirname(__FILE__)
|
44
|
+
# rubocop:disable ClassVars
|
45
|
+
@@setup_called = false
|
46
|
+
# rubocop:enable RuleByName
|
47
|
+
|
48
|
+
def self.setup_called
|
49
|
+
@@setup_called == true
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.included(*)
|
53
|
+
if setup_called == false
|
54
|
+
Rutie.new(:hypothesis_ruby_core).init(
|
55
|
+
'Init_rutie_hypothesis_core',
|
56
|
+
__dir__
|
57
|
+
)
|
58
|
+
end
|
59
|
+
@@setup_called = true
|
60
|
+
end
|
22
61
|
|
23
62
|
# @!visibility private
|
24
63
|
def hypothesis_stable_identifier
|
@@ -184,14 +223,21 @@ module Hypothesis
|
|
184
223
|
# should store previously failing test cases. If it is nil, Hypothesis
|
185
224
|
# will use a default of .hypothesis/examples in the current directory.
|
186
225
|
# May also be set to false to disable the database functionality.
|
187
|
-
def hypothesis(
|
226
|
+
def hypothesis(
|
227
|
+
max_valid_test_cases: 200,
|
228
|
+
phases: Phase.all,
|
229
|
+
database: nil,
|
230
|
+
&block
|
231
|
+
)
|
188
232
|
unless World.current_engine.nil?
|
189
233
|
raise UsageError, 'Cannot nest hypothesis calls'
|
190
234
|
end
|
235
|
+
|
191
236
|
begin
|
192
237
|
World.current_engine = Engine.new(
|
193
238
|
hypothesis_stable_identifier,
|
194
239
|
max_examples: max_valid_test_cases,
|
240
|
+
phases: phases,
|
195
241
|
database: database
|
196
242
|
)
|
197
243
|
World.current_engine.run(&block)
|
data/lib/hypothesis/engine.rb
CHANGED
@@ -1,17 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
|
5
|
-
require_relative '../hypothesis-ruby/native'
|
6
|
-
|
7
|
-
require 'rspec/expectations'
|
3
|
+
require 'rutie'
|
8
4
|
|
9
5
|
module Hypothesis
|
10
6
|
DEFAULT_DATABASE_PATH = File.join(Dir.pwd, '.hypothesis', 'examples')
|
11
7
|
|
12
8
|
class Engine
|
13
|
-
include RSpec::Matchers
|
14
|
-
|
15
9
|
attr_reader :current_source
|
16
10
|
attr_accessor :is_find
|
17
11
|
|
@@ -25,7 +19,11 @@ module Hypothesis
|
|
25
19
|
database = nil if database == false
|
26
20
|
|
27
21
|
@core_engine = HypothesisCoreEngine.new(
|
28
|
-
name,
|
22
|
+
name,
|
23
|
+
database,
|
24
|
+
seed,
|
25
|
+
options.fetch(:max_examples),
|
26
|
+
options.fetch(:phases)
|
29
27
|
)
|
30
28
|
|
31
29
|
@exceptions_to_tags = Hash.new { |h, k| h[k] = h.size }
|
data/src/lib.rs
CHANGED
@@ -1,190 +1,492 @@
|
|
1
|
-
// "Bridging" root code that exists exclusively to provide
|
2
|
-
// a ruby -> Hypothesis engine binding.
|
3
|
-
|
4
|
-
#![recursion_limit = "256"]
|
5
|
-
#![deny(warnings, missing_debug_implementations)]
|
6
|
-
|
7
|
-
extern crate core;
|
8
1
|
#[macro_use]
|
9
|
-
extern crate
|
10
|
-
|
2
|
+
extern crate rutie;
|
3
|
+
#[macro_use]
|
4
|
+
extern crate lazy_static;
|
11
5
|
extern crate conjecture;
|
12
6
|
|
7
|
+
use std::convert::TryFrom;
|
13
8
|
use std::mem;
|
14
9
|
|
10
|
+
use rutie::{
|
11
|
+
AnyException, AnyObject, Array, Boolean, Class, Exception, Float, Integer, NilClass, Object,
|
12
|
+
RString, Symbol, VM,
|
13
|
+
};
|
14
|
+
|
15
15
|
use conjecture::data::{DataSource, Status, TestResult};
|
16
|
-
use conjecture::
|
16
|
+
use conjecture::database::{BoxedDatabase, DirectoryDatabase, NoDatabase};
|
17
17
|
use conjecture::distributions;
|
18
|
-
use conjecture::
|
19
|
-
use conjecture::
|
18
|
+
use conjecture::distributions::Repeat;
|
19
|
+
use conjecture::engine::{Engine, Phase};
|
20
|
+
|
21
|
+
pub struct HypothesisCoreDataSourceStruct {
|
22
|
+
source: Option<DataSource>,
|
23
|
+
}
|
20
24
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
+
impl HypothesisCoreDataSourceStruct {
|
26
|
+
fn new(engine: &mut HypothesisCoreEngineStruct) -> HypothesisCoreDataSourceStruct {
|
27
|
+
HypothesisCoreDataSourceStruct {
|
28
|
+
source: mem::take(&mut engine.pending),
|
29
|
+
}
|
25
30
|
}
|
26
31
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
32
|
+
fn start_draw(&mut self) {
|
33
|
+
if let Some(ref mut source) = self.source {
|
34
|
+
source.start_draw();
|
35
|
+
}
|
31
36
|
}
|
32
37
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
38
|
+
fn stop_draw(&mut self) {
|
39
|
+
if let Some(ref mut source) = self.source {
|
40
|
+
source.stop_draw();
|
41
|
+
}
|
37
42
|
}
|
43
|
+
}
|
38
44
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
45
|
+
wrappable_struct!(
|
46
|
+
HypothesisCoreDataSourceStruct,
|
47
|
+
HypothesisCoreDataSourceStructWrapper,
|
48
|
+
HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER
|
49
|
+
);
|
50
|
+
|
51
|
+
class!(HypothesisCoreDataSource);
|
52
|
+
|
53
|
+
#[rustfmt::skip]
|
54
|
+
methods!(
|
55
|
+
HypothesisCoreDataSource,
|
56
|
+
itself,
|
57
|
+
fn ruby_hypothesis_core_data_source_start_draw() -> NilClass {
|
58
|
+
itself
|
59
|
+
.get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER)
|
60
|
+
.start_draw();
|
61
|
+
|
62
|
+
NilClass::new()
|
43
63
|
}
|
44
|
-
|
64
|
+
fn ruby_hypothesis_core_data_source_stop_draw() -> NilClass {
|
65
|
+
itself
|
66
|
+
.get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER)
|
67
|
+
.stop_draw();
|
45
68
|
|
46
|
-
|
47
|
-
struct {
|
48
|
-
engine: Engine,
|
49
|
-
pending: Option<DataSource>,
|
50
|
-
interesting_examples: Vec<TestResult>,
|
69
|
+
NilClass::new()
|
51
70
|
}
|
71
|
+
);
|
72
|
+
|
73
|
+
pub struct HypothesisCoreEngineStruct {
|
74
|
+
engine: Engine,
|
75
|
+
pending: Option<DataSource>,
|
76
|
+
interesting_examples: Vec<TestResult>,
|
77
|
+
}
|
52
78
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
79
|
+
impl HypothesisCoreEngineStruct {
|
80
|
+
fn new(
|
81
|
+
name: String,
|
82
|
+
database_path: Option<String>,
|
83
|
+
seed: u64,
|
84
|
+
max_examples: u64,
|
85
|
+
phases: Vec<Phase>,
|
86
|
+
) -> HypothesisCoreEngineStruct {
|
87
|
+
let xs: [u32; 2] = [seed as u32, (seed >> 32) as u32];
|
88
|
+
let db: BoxedDatabase = match database_path {
|
89
|
+
None => Box::new(NoDatabase),
|
90
|
+
Some(path) => Box::new(DirectoryDatabase::new(path)),
|
91
|
+
};
|
59
92
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
}
|
93
|
+
HypothesisCoreEngineStruct {
|
94
|
+
engine: Engine::new(name, max_examples, phases, &xs, db),
|
95
|
+
pending: None,
|
96
|
+
interesting_examples: Vec::new(),
|
97
|
+
}
|
66
98
|
}
|
67
99
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
100
|
+
fn new_source(&mut self) -> Option<HypothesisCoreDataSourceStruct> {
|
101
|
+
match self.engine.next_source() {
|
102
|
+
None => {
|
103
|
+
self.interesting_examples = self.engine.list_minimized_examples();
|
104
|
+
None
|
105
|
+
}
|
106
|
+
Some(source) => {
|
107
|
+
self.pending = Some(source);
|
108
|
+
Some(HypothesisCoreDataSourceStruct::new(self))
|
109
|
+
}
|
110
|
+
}
|
79
111
|
}
|
80
112
|
|
81
|
-
|
82
|
-
|
113
|
+
fn count_failing_examples(&self) -> usize {
|
114
|
+
self.interesting_examples.len()
|
83
115
|
}
|
84
116
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
117
|
+
fn failing_example(&mut self, i: usize) -> HypothesisCoreDataSourceStruct {
|
118
|
+
self.pending = Some(DataSource::from_vec(
|
119
|
+
self.interesting_examples[i].record.clone(),
|
120
|
+
));
|
121
|
+
HypothesisCoreDataSourceStruct::new(self)
|
90
122
|
}
|
91
123
|
|
92
|
-
|
93
|
-
|
124
|
+
fn was_unsatisfiable(&mut self) -> bool {
|
125
|
+
self.engine.was_unsatisfiable()
|
94
126
|
}
|
95
127
|
|
96
|
-
|
97
|
-
|
128
|
+
fn finish_overflow(&mut self, child: &mut HypothesisCoreDataSourceStruct) {
|
129
|
+
mark_child_status(&mut self.engine, child, Status::Overflow);
|
98
130
|
}
|
99
131
|
|
100
|
-
|
101
|
-
|
132
|
+
fn finish_valid(&mut self, child: &mut HypothesisCoreDataSourceStruct) {
|
133
|
+
mark_child_status(&mut self.engine, child, Status::Valid);
|
102
134
|
}
|
103
135
|
|
104
|
-
|
105
|
-
|
136
|
+
fn finish_invalid(&mut self, child: &mut HypothesisCoreDataSourceStruct) {
|
137
|
+
mark_child_status(&mut self.engine, child, Status::Invalid);
|
106
138
|
}
|
107
139
|
|
108
|
-
|
109
|
-
|
140
|
+
fn finish_interesting(&mut self, child: &mut HypothesisCoreDataSourceStruct, label: u64) {
|
141
|
+
mark_child_status(&mut self.engine, child, Status::Interesting(label));
|
110
142
|
}
|
111
|
-
|
143
|
+
}
|
144
|
+
|
145
|
+
wrappable_struct!(
|
146
|
+
HypothesisCoreEngineStruct,
|
147
|
+
HypothesisCoreEngineStructWrapper,
|
148
|
+
HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER
|
149
|
+
);
|
150
|
+
|
151
|
+
class!(HypothesisCoreEngine);
|
152
|
+
|
153
|
+
#[rustfmt::skip]
|
154
|
+
methods!(
|
155
|
+
HypothesisCoreEngine,
|
156
|
+
itself,
|
157
|
+
fn ruby_hypothesis_core_engine_new(
|
158
|
+
name: RString,
|
159
|
+
database_path: RString,
|
160
|
+
seed: Integer,
|
161
|
+
max_example: Integer,
|
162
|
+
phases: Array
|
163
|
+
) -> AnyObject {
|
164
|
+
let rust_phases = safe_access(phases)
|
165
|
+
.into_iter()
|
166
|
+
.map(|ruby_phase| {
|
167
|
+
let phase_sym = safe_access(ruby_phase.try_convert_to::<Symbol>());
|
168
|
+
let phase = Phase::try_from(phase_sym.to_str())
|
169
|
+
.map_err(|e| AnyException::new("ArgumentError", Some(&e)));
|
112
170
|
|
113
|
-
|
114
|
-
|
115
|
-
|
171
|
+
safe_access(phase)
|
172
|
+
})
|
173
|
+
.collect();
|
174
|
+
|
175
|
+
let core_engine = HypothesisCoreEngineStruct::new(
|
176
|
+
safe_access(name).to_string(),
|
177
|
+
database_path.ok().map(|p| p.to_string()),
|
178
|
+
safe_access(seed).to_u64(),
|
179
|
+
safe_access(max_example).to_u64(),
|
180
|
+
rust_phases,
|
181
|
+
);
|
182
|
+
|
183
|
+
Class::from_existing("HypothesisCoreEngine")
|
184
|
+
.wrap_data(core_engine, &*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER)
|
185
|
+
}
|
186
|
+
fn ruby_hypothesis_core_engine_new_source() -> AnyObject {
|
187
|
+
match itself
|
188
|
+
.get_data_mut(&*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER)
|
189
|
+
.new_source()
|
190
|
+
{
|
191
|
+
Some(ds) => Class::from_existing("HypothesisCoreDataSource")
|
192
|
+
.wrap_data(ds, &*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER),
|
193
|
+
None => NilClass::new().into(),
|
194
|
+
}
|
116
195
|
}
|
196
|
+
fn ruby_hypothesis_core_engine_finish_overflow(child: AnyObject) -> NilClass {
|
197
|
+
let core_engine = itself.get_data_mut(&*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER);
|
198
|
+
let mut rdata_source = safe_access(child);
|
199
|
+
let data_source = rdata_source.get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER);
|
117
200
|
|
118
|
-
|
119
|
-
|
201
|
+
core_engine.finish_overflow(data_source);
|
202
|
+
|
203
|
+
NilClass::new()
|
120
204
|
}
|
205
|
+
fn ruby_hypothesis_core_engine_finish_valid(child: AnyObject) -> NilClass {
|
206
|
+
let core_engine = itself.get_data_mut(&*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER);
|
207
|
+
let mut rdata_source = safe_access(child);
|
208
|
+
let data_source = rdata_source.get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER);
|
209
|
+
|
210
|
+
core_engine.finish_valid(data_source);
|
121
211
|
|
122
|
-
|
123
|
-
match &mut data.source {
|
124
|
-
&mut None => None,
|
125
|
-
&mut Some(ref mut source) => source.bits(self.n_bits).ok(),
|
126
|
-
}
|
212
|
+
NilClass::new()
|
127
213
|
}
|
128
|
-
|
214
|
+
fn ruby_hypothesis_core_engine_finish_invalid(child: AnyObject) -> NilClass {
|
215
|
+
let core_engine = itself.get_data_mut(&*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER);
|
216
|
+
let mut rdata_source = safe_access(child);
|
217
|
+
let data_source = rdata_source.get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER);
|
129
218
|
|
130
|
-
|
131
|
-
|
132
|
-
|
219
|
+
core_engine.finish_invalid(data_source);
|
220
|
+
|
221
|
+
NilClass::new()
|
133
222
|
}
|
223
|
+
fn ruby_hypothesis_core_engine_finish_interesting(
|
224
|
+
child: AnyObject,
|
225
|
+
label: Integer
|
226
|
+
) -> NilClass {
|
227
|
+
let core_engine = itself.get_data_mut(&*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER);
|
228
|
+
let mut rdata_source = safe_access(child);
|
229
|
+
let data_source = rdata_source.get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER);
|
230
|
+
|
231
|
+
core_engine.finish_interesting(data_source, safe_access(label).to_u64());
|
134
232
|
|
135
|
-
|
136
|
-
return HypothesisCoreRepeatValues{
|
137
|
-
helix, repeat: Repeat::new(min_count, max_count, expected_count)
|
138
|
-
}
|
233
|
+
NilClass::new()
|
139
234
|
}
|
235
|
+
fn ruby_hypothesis_core_engine_count_failing_examples() -> Integer {
|
236
|
+
let core_engine = itself.get_data(&*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER);
|
140
237
|
|
141
|
-
|
142
|
-
return data.source.as_mut().and_then(|ref mut source| {
|
143
|
-
self.repeat.should_continue(source).ok()
|
144
|
-
})
|
238
|
+
Integer::new(core_engine.count_failing_examples() as i64)
|
145
239
|
}
|
240
|
+
fn ruby_hypothesis_core_failing_example(i: Integer) -> AnyObject {
|
241
|
+
let core_engine = itself.get_data_mut(&*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER);
|
242
|
+
let int = safe_access(i).to_u64() as usize;
|
146
243
|
|
147
|
-
|
148
|
-
|
244
|
+
let data_source = core_engine.failing_example(int);
|
245
|
+
|
246
|
+
Class::from_existing("HypothesisCoreDataSource")
|
247
|
+
.wrap_data(data_source, &*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER)
|
149
248
|
}
|
150
|
-
|
249
|
+
fn ruby_hypothesis_core_engine_was_unsatisfiable() -> Boolean {
|
250
|
+
let core_engine = itself.get_data_mut(&*HYPOTHESIS_CORE_ENGINE_STRUCT_WRAPPER);
|
151
251
|
|
152
|
-
|
153
|
-
struct {
|
154
|
-
bitlengths: distributions::Sampler,
|
252
|
+
Boolean::new(core_engine.was_unsatisfiable())
|
155
253
|
}
|
156
|
-
|
157
|
-
|
254
|
+
);
|
255
|
+
|
256
|
+
pub struct HypothesisCoreIntegersStruct {
|
257
|
+
bitlengths: distributions::Sampler,
|
258
|
+
}
|
259
|
+
|
260
|
+
impl HypothesisCoreIntegersStruct {
|
261
|
+
fn new() -> HypothesisCoreIntegersStruct {
|
262
|
+
HypothesisCoreIntegersStruct {
|
263
|
+
bitlengths: distributions::good_bitlengths(),
|
264
|
+
}
|
158
265
|
}
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
266
|
+
|
267
|
+
fn provide(&mut self, data: &mut HypothesisCoreDataSourceStruct) -> Option<i64> {
|
268
|
+
data.source.as_mut().and_then(|ref mut source| {
|
269
|
+
distributions::integer_from_bitlengths(source, &self.bitlengths).ok()
|
270
|
+
})
|
163
271
|
}
|
164
|
-
|
272
|
+
}
|
273
|
+
|
274
|
+
wrappable_struct!(
|
275
|
+
HypothesisCoreIntegersStruct,
|
276
|
+
HypothesisCoreIntegersStructWrapper,
|
277
|
+
HYPOTHESIS_CORE_INTEGERS_STRUCT_WRAPPER
|
278
|
+
);
|
165
279
|
|
166
|
-
|
167
|
-
|
168
|
-
|
280
|
+
class!(HypothesisCoreIntegers);
|
281
|
+
|
282
|
+
#[rustfmt::skip]
|
283
|
+
methods!(
|
284
|
+
HypothesisCoreIntegers,
|
285
|
+
itself,
|
286
|
+
fn ruby_hypothesis_core_integers_new() -> AnyObject {
|
287
|
+
let core_integers = HypothesisCoreIntegersStruct::new();
|
288
|
+
|
289
|
+
Class::from_existing("HypothesisCoreIntegers")
|
290
|
+
.wrap_data(core_integers, &*HYPOTHESIS_CORE_INTEGERS_STRUCT_WRAPPER)
|
169
291
|
}
|
170
|
-
|
171
|
-
|
292
|
+
fn ruby_hypothesis_core_integers_provide(data: AnyObject) -> AnyObject {
|
293
|
+
let core_integers = itself.get_data_mut(&*HYPOTHESIS_CORE_INTEGERS_STRUCT_WRAPPER);
|
294
|
+
let mut rdata = safe_access(data);
|
295
|
+
let data_source = rdata.get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER);
|
296
|
+
|
297
|
+
match core_integers.provide(data_source) {
|
298
|
+
Some(i) => Integer::new(i).into(),
|
299
|
+
None => NilClass::new().into(),
|
300
|
+
}
|
172
301
|
}
|
302
|
+
);
|
173
303
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
304
|
+
pub struct HypothesisCoreRepeatValuesStruct {
|
305
|
+
repeat: Repeat,
|
306
|
+
}
|
307
|
+
|
308
|
+
impl HypothesisCoreRepeatValuesStruct {
|
309
|
+
fn new(
|
310
|
+
min_count: u64,
|
311
|
+
max_count: u64,
|
312
|
+
expected_count: f64,
|
313
|
+
) -> HypothesisCoreRepeatValuesStruct {
|
314
|
+
HypothesisCoreRepeatValuesStruct {
|
315
|
+
repeat: Repeat::new(min_count, max_count, expected_count),
|
316
|
+
}
|
317
|
+
}
|
318
|
+
|
319
|
+
fn _should_continue(&mut self, data: &mut HypothesisCoreDataSourceStruct) -> Option<bool> {
|
320
|
+
return data
|
321
|
+
.source
|
322
|
+
.as_mut()
|
323
|
+
.and_then(|ref mut source| self.repeat.should_continue(source).ok());
|
324
|
+
}
|
325
|
+
|
326
|
+
fn reject(&mut self) {
|
327
|
+
self.repeat.reject();
|
178
328
|
}
|
179
|
-
}
|
180
329
|
}
|
181
330
|
|
182
|
-
|
183
|
-
|
184
|
-
|
331
|
+
wrappable_struct!(
|
332
|
+
HypothesisCoreRepeatValuesStruct,
|
333
|
+
HypothesisCoreRepeatValuesStructWrapper,
|
334
|
+
HYPOTHESIS_CORE_REPEAT_VALUES_STRUCT_WRAPPER
|
335
|
+
);
|
336
|
+
|
337
|
+
class!(HypothesisCoreRepeatValues);
|
338
|
+
|
339
|
+
#[rustfmt::skip]
|
340
|
+
methods!(
|
341
|
+
HypothesisCoreRepeatValues,
|
342
|
+
itself,
|
343
|
+
fn ruby_hypothesis_core_repeat_values_new(
|
344
|
+
min_count: Integer,
|
345
|
+
max_count: Integer,
|
346
|
+
expected_count: Float
|
347
|
+
) -> AnyObject {
|
348
|
+
let repeat_values = HypothesisCoreRepeatValuesStruct::new(
|
349
|
+
safe_access(min_count).to_u64(),
|
350
|
+
safe_access(max_count).to_u64(),
|
351
|
+
safe_access(expected_count).to_f64(),
|
352
|
+
);
|
353
|
+
|
354
|
+
Class::from_existing("HypothesisCoreRepeatValues").wrap_data(
|
355
|
+
repeat_values,
|
356
|
+
&*HYPOTHESIS_CORE_REPEAT_VALUES_STRUCT_WRAPPER,
|
357
|
+
)
|
358
|
+
}
|
359
|
+
fn ruby_hypothesis_core_repeat_values_should_continue(data: AnyObject) -> AnyObject {
|
360
|
+
let mut rdata = safe_access(data);
|
361
|
+
let mut data_source = rdata.get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER);
|
362
|
+
|
363
|
+
let should_continue = itself
|
364
|
+
.get_data_mut(&*HYPOTHESIS_CORE_REPEAT_VALUES_STRUCT_WRAPPER)
|
365
|
+
._should_continue(data_source);
|
185
366
|
|
186
|
-
|
187
|
-
|
188
|
-
|
367
|
+
match should_continue {
|
368
|
+
Some(b) => Boolean::new(b).into(),
|
369
|
+
None => NilClass::new().into(),
|
370
|
+
}
|
189
371
|
}
|
372
|
+
fn ruby_hypothesis_core_repeat_values_reject() -> NilClass {
|
373
|
+
let repeat_values = itself.get_data_mut(&*HYPOTHESIS_CORE_REPEAT_VALUES_STRUCT_WRAPPER);
|
374
|
+
|
375
|
+
repeat_values.reject();
|
376
|
+
|
377
|
+
NilClass::new()
|
378
|
+
}
|
379
|
+
);
|
380
|
+
|
381
|
+
pub struct HypothesisCoreBoundedIntegersStruct {
|
382
|
+
max_value: u64,
|
383
|
+
}
|
384
|
+
|
385
|
+
impl HypothesisCoreBoundedIntegersStruct {
|
386
|
+
fn provide(&mut self, data: &mut HypothesisCoreDataSourceStruct) -> Option<u64> {
|
387
|
+
data.source
|
388
|
+
.as_mut()
|
389
|
+
.and_then(|ref mut source| distributions::bounded_int(source, self.max_value).ok())
|
390
|
+
}
|
391
|
+
}
|
392
|
+
|
393
|
+
wrappable_struct!(
|
394
|
+
HypothesisCoreBoundedIntegersStruct,
|
395
|
+
HypothesisCoreBoundedIntegersStructWrapper,
|
396
|
+
HYPOTHESIS_CORE_BOUNDED_INTEGERS_STRUCT_WRAPPER
|
397
|
+
);
|
398
|
+
|
399
|
+
class!(HypothesisCoreBoundedIntegers);
|
400
|
+
|
401
|
+
#[rustfmt::skip]
|
402
|
+
methods!(
|
403
|
+
HypothesisCoreBoundedIntegers,
|
404
|
+
itself,
|
405
|
+
fn ruby_hypothesis_core_bounded_integers_new(max_value: Integer) -> AnyObject {
|
406
|
+
let bounded_integers = HypothesisCoreBoundedIntegersStruct {
|
407
|
+
max_value: safe_access(max_value).to_u64(),
|
408
|
+
};
|
409
|
+
|
410
|
+
Class::from_existing("HypothesisCoreBoundedIntegers").wrap_data(
|
411
|
+
bounded_integers,
|
412
|
+
&*HYPOTHESIS_CORE_BOUNDED_INTEGERS_STRUCT_WRAPPER,
|
413
|
+
)
|
414
|
+
}
|
415
|
+
fn ruby_hypothesis_core_bounded_integers_provide(data: AnyObject) -> AnyObject {
|
416
|
+
let mut rdata = safe_access(data);
|
417
|
+
let data_source = rdata.get_data_mut(&*HYPOTHESIS_CORE_DATA_SOURCE_STRUCT_WRAPPER);
|
418
|
+
let bounded_integers =
|
419
|
+
itself.get_data_mut(&*HYPOTHESIS_CORE_BOUNDED_INTEGERS_STRUCT_WRAPPER);
|
420
|
+
|
421
|
+
match bounded_integers.provide(data_source) {
|
422
|
+
Some(i) => Integer::from(i).into(),
|
423
|
+
None => NilClass::new().into(),
|
424
|
+
}
|
425
|
+
}
|
426
|
+
);
|
427
|
+
|
428
|
+
#[allow(non_snake_case)]
|
429
|
+
#[no_mangle]
|
430
|
+
pub extern "C" fn Init_rutie_hypothesis_core() {
|
431
|
+
Class::new("HypothesisCoreEngine", None).define(|klass| {
|
432
|
+
klass.def_self("new", ruby_hypothesis_core_engine_new);
|
433
|
+
klass.def("new_source", ruby_hypothesis_core_engine_new_source);
|
434
|
+
klass.def(
|
435
|
+
"count_failing_examples",
|
436
|
+
ruby_hypothesis_core_engine_count_failing_examples,
|
437
|
+
);
|
438
|
+
klass.def("failing_example", ruby_hypothesis_core_failing_example);
|
439
|
+
klass.def(
|
440
|
+
"was_unsatisfiable",
|
441
|
+
ruby_hypothesis_core_engine_was_unsatisfiable,
|
442
|
+
);
|
443
|
+
klass.def(
|
444
|
+
"finish_overflow",
|
445
|
+
ruby_hypothesis_core_engine_finish_overflow,
|
446
|
+
);
|
447
|
+
klass.def("finish_valid", ruby_hypothesis_core_engine_finish_valid);
|
448
|
+
klass.def("finish_invalid", ruby_hypothesis_core_engine_finish_invalid);
|
449
|
+
klass.def(
|
450
|
+
"finish_interesting",
|
451
|
+
ruby_hypothesis_core_engine_finish_interesting,
|
452
|
+
);
|
453
|
+
});
|
454
|
+
|
455
|
+
Class::new("HypothesisCoreDataSource", None).define(|klass| {
|
456
|
+
klass.def("start_draw", ruby_hypothesis_core_data_source_start_draw);
|
457
|
+
klass.def("stop_draw", ruby_hypothesis_core_data_source_stop_draw);
|
458
|
+
});
|
459
|
+
|
460
|
+
Class::new("HypothesisCoreIntegers", None).define(|klass| {
|
461
|
+
klass.def_self("new", ruby_hypothesis_core_integers_new);
|
462
|
+
klass.def("provide", ruby_hypothesis_core_integers_provide);
|
463
|
+
});
|
464
|
+
|
465
|
+
Class::new("HypothesisCoreRepeatValues", None).define(|klass| {
|
466
|
+
klass.def_self("new", ruby_hypothesis_core_repeat_values_new);
|
467
|
+
klass.def(
|
468
|
+
"_should_continue",
|
469
|
+
ruby_hypothesis_core_repeat_values_should_continue,
|
470
|
+
);
|
471
|
+
klass.def("reject", ruby_hypothesis_core_repeat_values_reject);
|
472
|
+
});
|
473
|
+
|
474
|
+
Class::new("HypothesisCoreBoundedIntegers", None).define(|klass| {
|
475
|
+
klass.def_self("new", ruby_hypothesis_core_bounded_integers_new);
|
476
|
+
klass.def("provide", ruby_hypothesis_core_bounded_integers_provide);
|
477
|
+
});
|
478
|
+
}
|
479
|
+
|
480
|
+
fn mark_child_status(
|
481
|
+
engine: &mut Engine,
|
482
|
+
child: &mut HypothesisCoreDataSourceStruct,
|
483
|
+
status: Status,
|
484
|
+
) {
|
485
|
+
if let Some(source) = mem::take(&mut child.source) {
|
486
|
+
engine.mark_finished(source, status)
|
487
|
+
}
|
488
|
+
}
|
489
|
+
|
490
|
+
fn safe_access<T>(value: Result<T, AnyException>) -> T {
|
491
|
+
value.map_err(VM::raise_ex).unwrap()
|
190
492
|
}
|
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.
|
4
|
+
version: 0.6.1
|
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:
|
12
|
+
date: 2021-02-01 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
15
|
+
name: rutie
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
16
17
|
requirements:
|
17
18
|
- - "~>"
|
18
19
|
- !ruby/object:Gem::Version
|
19
|
-
version: 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.
|
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
|
-
|
92
|
-
rubygems_version: 2.7.6
|
92
|
+
rubygems_version: 3.2.7
|
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
|