hypothesis-specs 0.0.15 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/Cargo.toml +1 -1
- data/lib/hypothesis.rb +1 -0
- data/lib/hypothesis/engine.rb +44 -29
- data/lib/hypothesis/errors.rb +33 -0
- data/lib/hypothesis/junkdrawer.rb +31 -0
- data/src/lib.rs +18 -11
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c8b0daf467cfba3ff5d8713fca58165154c19dbe24a9c063337da10244a4858
|
4
|
+
data.tar.gz: 5220bf53ee4d96028f54ffc0cb3513f263e06b5edb53a549a00bc3e4720ddbaf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a33f06784dec07894b9d0bb3ff0bd8366c78d0a332e25c9fac5e5589b6026f7cacc22a12575c1010416116f3527e07b9603a2da96e763148b9bdaa3ca1d085b9
|
7
|
+
data.tar.gz: a92b046f6384b42a6e28d836a29b6f654944fc9a8cccd6ff27ff6b8682a9d9588a7c326177aca48e6376866754fcda85c15b0734e728cc905d69fae146ac7683
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# Hypothesis for Ruby 0.1.0 (2018-07-16)
|
2
|
+
|
3
|
+
This release adds support for reporting multiple exceptions when Hypothesis
|
4
|
+
finds more than one way for the test to fail.
|
5
|
+
|
1
6
|
# Hypothesis for Ruby 0.0.15 (2018-06-25)
|
2
7
|
|
3
8
|
This release fixes an occasional `RuntimeError` that could occur
|
data/Cargo.toml
CHANGED
data/lib/hypothesis.rb
CHANGED
data/lib/hypothesis/engine.rb
CHANGED
@@ -2,9 +2,12 @@
|
|
2
2
|
|
3
3
|
require 'helix_runtime'
|
4
4
|
require 'hypothesis-ruby/native'
|
5
|
+
require 'rspec/expectations'
|
5
6
|
|
6
7
|
module Hypothesis
|
7
8
|
class Engine
|
9
|
+
include RSpec::Matchers
|
10
|
+
|
8
11
|
attr_reader :current_source
|
9
12
|
attr_accessor :is_find
|
10
13
|
|
@@ -13,6 +16,8 @@ module Hypothesis
|
|
13
16
|
@core_engine = HypothesisCoreEngine.new(
|
14
17
|
seed, options.fetch(:max_examples)
|
15
18
|
)
|
19
|
+
|
20
|
+
@exceptions_to_tags = Hash.new { |h, k| h[k] = h.size }
|
16
21
|
end
|
17
22
|
|
18
23
|
def run
|
@@ -23,7 +28,7 @@ module Hypothesis
|
|
23
28
|
begin
|
24
29
|
result = yield(@current_source)
|
25
30
|
if is_find && result
|
26
|
-
@core_engine.finish_interesting(core)
|
31
|
+
@core_engine.finish_interesting(core, 0)
|
27
32
|
else
|
28
33
|
@core_engine.finish_valid(core)
|
29
34
|
end
|
@@ -31,54 +36,64 @@ module Hypothesis
|
|
31
36
|
@core_engine.finish_invalid(core)
|
32
37
|
rescue DataOverflow
|
33
38
|
@core_engine.finish_overflow(core)
|
34
|
-
rescue Exception
|
39
|
+
rescue Exception => e
|
35
40
|
raise if is_find
|
36
|
-
|
41
|
+
key = [
|
42
|
+
e.class,
|
43
|
+
HypothesisJunkDrawer.find_first_relevant_line(e.backtrace)
|
44
|
+
]
|
45
|
+
@core_engine.finish_interesting(core, @exceptions_to_tags[key])
|
37
46
|
end
|
38
47
|
end
|
39
|
-
@
|
40
|
-
core = @core_engine.failing_example
|
41
|
-
if core.nil?
|
48
|
+
if @core_engine.count_failing_examples.zero?
|
42
49
|
raise Unsatisfiable if @core_engine.was_unsatisfiable
|
50
|
+
@current_source = nil
|
43
51
|
return
|
44
52
|
end
|
45
53
|
|
46
54
|
if is_find
|
55
|
+
core = @core_engine.failing_example(0)
|
47
56
|
@current_source = TestCase.new(core, record_draws: true)
|
48
57
|
yield @current_source
|
49
58
|
else
|
50
|
-
|
59
|
+
exceptions = []
|
60
|
+
(0...@core_engine.count_failing_examples).each do |example|
|
61
|
+
core = @core_engine.failing_example(example)
|
62
|
+
@current_source = TestCase.new(core, print_draws: true)
|
51
63
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
64
|
+
begin
|
65
|
+
yield @current_source
|
66
|
+
rescue Exception => e
|
67
|
+
givens = @current_source.print_log
|
68
|
+
given_str = givens.each_with_index.map do |(name, s), i|
|
69
|
+
name = "##{i + 1}" if name.nil?
|
70
|
+
"Given #{name}: #{s}"
|
71
|
+
end.to_a
|
60
72
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
73
|
+
if e.respond_to? :hypothesis_data
|
74
|
+
e.hypothesis_data[0] = given_str
|
75
|
+
else
|
76
|
+
original_to_s = e.to_s
|
77
|
+
original_inspect = e.inspect
|
66
78
|
|
67
|
-
|
68
|
-
|
79
|
+
class <<e
|
80
|
+
attr_accessor :hypothesis_data
|
69
81
|
|
70
|
-
|
71
|
-
|
72
|
-
|
82
|
+
def to_s
|
83
|
+
['', hypothesis_data[0], '', hypothesis_data[1]].join("\n")
|
84
|
+
end
|
73
85
|
|
74
|
-
|
75
|
-
|
86
|
+
def inspect
|
87
|
+
['', hypothesis_data[0], '', hypothesis_data[2]].join("\n")
|
88
|
+
end
|
76
89
|
end
|
90
|
+
e.hypothesis_data = [given_str, original_to_s, original_inspect]
|
77
91
|
end
|
78
|
-
e
|
92
|
+
raise e if @core_engine.count_failing_examples == 1
|
93
|
+
exceptions.push(e)
|
79
94
|
end
|
80
|
-
raise e
|
81
95
|
end
|
96
|
+
raise Hypothesis::MultipleExceptionError.new(*exceptions)
|
82
97
|
end
|
83
98
|
end
|
84
99
|
end
|
data/lib/hypothesis/errors.rb
CHANGED
@@ -25,4 +25,37 @@ module Hypothesis
|
|
25
25
|
# @!visibility private
|
26
26
|
class DataOverflow < HypothesisError
|
27
27
|
end
|
28
|
+
|
29
|
+
if defined?(RSpec::Core::MultipleExceptionError)
|
30
|
+
MultipleExceptionErrorParent = RSpec::Core::MultipleExceptionError
|
31
|
+
# :nocov:
|
32
|
+
else
|
33
|
+
class MultipleExceptionErrorParent < StandardError
|
34
|
+
def initialize(*exceptions)
|
35
|
+
super()
|
36
|
+
|
37
|
+
@all_exceptions = exceptions.to_a
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_reader :all_exceptions
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class MultipleExceptionError < MultipleExceptionErrorParent
|
45
|
+
def message
|
46
|
+
jd = HypothesisJunkDrawer
|
47
|
+
"Test raised #{all_exceptions.length} distinct errors:\n\n" +
|
48
|
+
all_exceptions.map do |e|
|
49
|
+
location = jd.find_first_relevant_line(e.backtrace).sub(/:in.+$/, '')
|
50
|
+
backtrace = jd.prune_backtrace(e.backtrace)
|
51
|
+
"#{e.class} at #{location}:\n" \
|
52
|
+
"#{e.message}\n#{backtrace.map { |s| ' ' + s }
|
53
|
+
.join("\n")}"
|
54
|
+
end.join("\n\n")
|
55
|
+
end
|
56
|
+
|
57
|
+
def backtrace
|
58
|
+
[]
|
59
|
+
end
|
60
|
+
end
|
28
61
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hypothesis
|
4
|
+
# @!visibility private
|
5
|
+
module HypothesisJunkDrawer
|
6
|
+
HYPOTHESIS_ROOT = File.absolute_path(File.dirname(__FILE__))
|
7
|
+
|
8
|
+
def self.prune_backtrace(backtrace)
|
9
|
+
result = []
|
10
|
+
seen_hypothesis = false
|
11
|
+
backtrace.each do |b|
|
12
|
+
if b.start_with?(HYPOTHESIS_ROOT)
|
13
|
+
seen_hypothesis = true
|
14
|
+
else
|
15
|
+
result.push(b)
|
16
|
+
break if seen_hypothesis
|
17
|
+
end
|
18
|
+
end
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.find_first_relevant_line(backtrace)
|
23
|
+
backtrace.each do |b|
|
24
|
+
next if b.include?('minitest/assertions.rb')
|
25
|
+
next if b.start_with?(HYPOTHESIS_ROOT)
|
26
|
+
return b
|
27
|
+
end
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/src/lib.rs
CHANGED
@@ -15,7 +15,7 @@ extern crate conjecture;
|
|
15
15
|
|
16
16
|
use std::mem;
|
17
17
|
|
18
|
-
use conjecture::data::{DataSource, Status};
|
18
|
+
use conjecture::data::{DataSource, Status, TestResult};
|
19
19
|
use conjecture::distributions::Repeat;
|
20
20
|
use conjecture::distributions;
|
21
21
|
use conjecture::engine::Engine;
|
@@ -49,6 +49,7 @@ ruby! {
|
|
49
49
|
struct {
|
50
50
|
engine: Engine,
|
51
51
|
pending: Option<DataSource>,
|
52
|
+
interesting_examples: Vec<TestResult>,
|
52
53
|
}
|
53
54
|
|
54
55
|
def initialize(helix, seed: u64, max_examples: u64){
|
@@ -57,12 +58,16 @@ ruby! {
|
|
57
58
|
helix,
|
58
59
|
engine: Engine::new(max_examples, &xs),
|
59
60
|
pending: None,
|
61
|
+
interesting_examples: Vec::new(),
|
60
62
|
}
|
61
63
|
}
|
62
64
|
|
63
65
|
def new_source(&mut self) -> Option<HypothesisCoreDataSource> {
|
64
66
|
match self.engine.next_source() {
|
65
|
-
None =>
|
67
|
+
None => {
|
68
|
+
self.interesting_examples = self.engine.list_minimized_examples();
|
69
|
+
None
|
70
|
+
},
|
66
71
|
Some(source) => {
|
67
72
|
self.pending = Some(source);
|
68
73
|
Some(HypothesisCoreDataSource::new(self))
|
@@ -70,13 +75,15 @@ ruby! {
|
|
70
75
|
}
|
71
76
|
}
|
72
77
|
|
73
|
-
def
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
78
|
+
def count_failing_examples(&self) -> usize {
|
79
|
+
self.interesting_examples.len()
|
80
|
+
}
|
81
|
+
|
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)
|
80
87
|
}
|
81
88
|
|
82
89
|
def was_unsatisfiable(&mut self) -> bool {
|
@@ -91,8 +98,8 @@ ruby! {
|
|
91
98
|
mark_child_status(&mut self.engine, child, Status::Invalid);
|
92
99
|
}
|
93
100
|
|
94
|
-
def finish_interesting(&mut self, child: &mut HypothesisCoreDataSource){
|
95
|
-
mark_child_status(&mut self.engine, child, Status::Interesting);
|
101
|
+
def finish_interesting(&mut self, child: &mut HypothesisCoreDataSource, label: u64){
|
102
|
+
mark_child_status(&mut self.engine, child, Status::Interesting(label));
|
96
103
|
}
|
97
104
|
|
98
105
|
def finish_valid(&mut self, child: &mut HypothesisCoreDataSource){
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hypothesis-specs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David R. Maciver
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: helix_runtime
|
@@ -64,6 +64,7 @@ files:
|
|
64
64
|
- lib/hypothesis.rb
|
65
65
|
- lib/hypothesis/engine.rb
|
66
66
|
- lib/hypothesis/errors.rb
|
67
|
+
- lib/hypothesis/junkdrawer.rb
|
67
68
|
- lib/hypothesis/possible.rb
|
68
69
|
- lib/hypothesis/testcase.rb
|
69
70
|
- lib/hypothesis/world.rb
|