Hello community, here is the log from the commit of package python-hypothesis for openSUSE:Factory checked in at 2018-07-21 10:09:37 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-hypothesis (Old) and /work/SRC/openSUSE:Factory/.python-hypothesis.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-hypothesis" Sat Jul 21 10:09:37 2018 rev:24 rq:624329 version:3.66.4 Changes: -------- --- /work/SRC/openSUSE:Factory/python-hypothesis/python-hypothesis.changes 2018-07-13 10:17:55.834210845 +0200 +++ /work/SRC/openSUSE:Factory/.python-hypothesis.new/python-hypothesis.changes 2018-07-21 10:09:38.775178581 +0200 @@ -1,0 +2,6 @@ +Fri Jul 20 15:28:09 UTC 2018 - [email protected] + +- update to version 3.66.4: + * This release improves the shrinker’s ability to reorder examples. + +------------------------------------------------------------------- Old: ---- hypothesis-python-3.66.1.tar.gz New: ---- hypothesis-python-3.66.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-hypothesis.spec ++++++ --- /var/tmp/diff_new_pack.ouL3w1/_old 2018-07-21 10:09:39.167178491 +0200 +++ /var/tmp/diff_new_pack.ouL3w1/_new 2018-07-21 10:09:39.171178490 +0200 @@ -28,7 +28,7 @@ %endif %bcond_without python2 Name: python-hypothesis -Version: 3.66.1 +Version: 3.66.4 Release: 0 Summary: A library for property based testing License: MPL-2.0 ++++++ hypothesis-python-3.66.1.tar.gz -> hypothesis-python-3.66.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/CONTRIBUTING.rst new/hypothesis-hypothesis-python-3.66.4/CONTRIBUTING.rst --- old/hypothesis-hypothesis-python-3.66.1/CONTRIBUTING.rst 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/CONTRIBUTING.rst 2018-07-20 15:37:18.000000000 +0200 @@ -158,6 +158,7 @@ * `Alex Stapleton <https://www.github.com/public>`_ * `Alex Willmer <https://github.com/moreati>`_ ([email protected]) * `Ben Peterson <https://github.com/killthrush>`_ ([email protected]) +* `Bill Tucker <https://github.com/imbilltucker>`_ ([email protected]) * `Buck Evan, copyright Google LLC <https://github.com/bukzor>`_ * `Charles O'Farrell <https://www.github.com/charleso>`_ * `Charlie Tanksley <https://www.github.com/charlietanksley>`_ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/conjecture-rust/CHANGELOG.md new/hypothesis-hypothesis-python-3.66.4/conjecture-rust/CHANGELOG.md --- old/hypothesis-hypothesis-python-3.66.1/conjecture-rust/CHANGELOG.md 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/conjecture-rust/CHANGELOG.md 2018-07-20 15:37:18.000000000 +0200 @@ -1,3 +1,10 @@ +# Conjecture for Rust 0.3.0 (2018-07-16) + +This release adds support for annotating interesting examples +to indicate that they are logically distinct. When multiple distinct +reasons for being interesting are found, Conjecture will attempt to +shrink all of them. + # Conjecture for Rust 0.2.1 (2018-06-25) This release fixes an occasional assertion failure that could occur diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/conjecture-rust/Cargo.toml new/hypothesis-hypothesis-python-3.66.4/conjecture-rust/Cargo.toml --- old/hypothesis-hypothesis-python-3.66.1/conjecture-rust/Cargo.toml 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/conjecture-rust/Cargo.toml 2018-07-20 15:37:18.000000000 +0200 @@ -1,6 +1,6 @@ [package] name = "conjecture" -version = '0.2.1' +version = '0.3.0' authors = ["David R. MacIver <[email protected]>"] homepage = "https://github.com/HypothesisWorks/hypothesis/tree/master/conjecture-rust" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/conjecture-rust/src/data.rs new/hypothesis-hypothesis-python-3.66.4/conjecture-rust/src/data.rs --- old/hypothesis-hypothesis-python-3.66.1/conjecture-rust/src/data.rs 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/conjecture-rust/src/data.rs 2018-07-20 15:37:18.000000000 +0200 @@ -3,6 +3,7 @@ use rand::{ChaChaRng, Rng}; use std::collections::HashSet; +use std::cmp::Ordering; pub type DataStream = Vec<u64>; @@ -167,7 +168,7 @@ // This was an interesting test execution! (Usually this // means failing, but for things like find it may not). - Interesting, + Interesting(u64), } // Once a data source is finished it "decays" to a @@ -182,3 +183,25 @@ pub sizes: Vec<u64>, pub written_indices: HashSet<usize>, } + + +impl Ord for TestResult { + fn cmp(&self, other: &TestResult) -> Ordering { + self.record.len().cmp(&other.record.len()). + then(self.record.cmp(&other.record)) + } +} + +impl PartialOrd for TestResult { + fn partial_cmp(&self, other: &TestResult) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl PartialEq for TestResult { + fn eq(&self, other: &TestResult) -> bool { + self.record == other.record + } +} + +impl Eq for TestResult { } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/conjecture-rust/src/engine.rs new/hypothesis-hypothesis-python-3.66.4/conjecture-rust/src/engine.rs --- old/hypothesis-hypothesis-python-3.66.1/conjecture-rust/src/engine.rs 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/conjecture-rust/src/engine.rs 2018-07-20 15:37:18.000000000 +0200 @@ -4,7 +4,7 @@ use rand::{ChaChaRng, Rng, SeedableRng}; use std::cmp::Reverse; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::mem; use std::sync::mpsc::{sync_channel, Receiver, SyncSender}; use std::thread; @@ -33,6 +33,8 @@ random: ChaChaRng, best_example: Option<TestResult>, + minimized_examples: HashMap<u64, TestResult>, + fully_minimized: HashSet<u64>, valid_examples: u64, invalid_examples: u64, @@ -59,13 +61,36 @@ } fn loop_body(&mut self) -> StepResult { - let interesting_example = self.generate_examples()?; + self.generate_examples()?; - let mut shrinker = Shrinker::new(self, interesting_example, |r| { - r.status == Status::Interesting - }); + // At the start of this loop we can only have example in + // self.minimized_examples, but as we shrink we may find other ones. + // The reason why we loop is twofold: + // a) This allows us to include newly discovered examples. Labels that + // are not found in self.minimized_examples at the beginning of the + // loop will be added for the next iteration around. + // b) If we've previously marked a label as finished it can become + // unfinished again if when shrinking another label, as when trying + // to shrink one label we might accidentally find an improved shrink + // for another. + // + // In principle this might cause us to loop for a very long time before + // eventually settling on a fixed point, but when that happens we + // should hit limits on shrinking (which we haven't implemented yet). + while self.minimized_examples.len() > self.fully_minimized.len() { + let keys: Vec<u64> = self.minimized_examples.keys().map(|i| *i).collect(); + for label in keys.iter() { + if self.fully_minimized.insert(*label) { + let target = self.minimized_examples[label].clone(); + let mut shrinker = Shrinker::new( + self, target, |r| { + r.status == Status::Interesting(*label) + }); - shrinker.run()?; + shrinker.run()?; + } + } + } return Err(LoopExitReason::Complete); } @@ -76,8 +101,9 @@ { let r = self.random.gen(); let result = self.execute(DataSource::from_random(r))?; - if result.status == Status::Interesting { - return Ok(result); + match result.status { + Status::Interesting(_) => return Ok(result), + _ => (), } } return Err(LoopExitReason::MaxExamples); @@ -95,8 +121,19 @@ Status::Overflow => (), Status::Invalid => self.invalid_examples += 1, Status::Valid => self.valid_examples += 1, - Status::Interesting => { + Status::Interesting(n) => { self.best_example = Some(result.clone()); + let mut changed = false; + self.minimized_examples.entry(n).or_insert_with(|| {result.clone()}); + self.minimized_examples.entry(n).and_modify(|e| { + if result < *e { + changed = true; + *e = result.clone() + }; + }); + if changed { + self.fully_minimized.remove(&n); + } self.interesting_examples += 1; } } @@ -497,6 +534,8 @@ sender: send_remote, receiver: recv_remote, best_example: None, + minimized_examples: HashMap::new(), + fully_minimized: HashSet::new(), valid_examples: 0, invalid_examples: 0, interesting_examples: 0, @@ -541,6 +580,23 @@ } } + pub fn list_minimized_examples(&self) -> Vec<TestResult> { + match &self.loop_response { + &Some(LoopCommand::Finished( + _, + MainGenerationLoop { + ref minimized_examples, + .. + }, + )) => { + let mut results: Vec<TestResult> = minimized_examples.values().map(|v| v.clone()).collect(); + results.sort(); + results + }, + _ => Vec::new(), + } + } + pub fn best_source(&self) -> Option<DataSource> { match &self.loop_response { &Some(LoopCommand::Finished( @@ -554,6 +610,7 @@ } } + fn consume_test_result(&mut self, result: TestResult) -> () { assert!(self.state == EngineState::AwaitingCompletion); self.state = EngineState::ReadyToProvide; @@ -623,3 +680,40 @@ } } } + + +#[cfg(test)] +mod tests { + use super::*; + use data::FailedDraw; + + fn run_to_results<F>(mut f: F) -> Vec<TestResult> + where F: FnMut(&mut DataSource) -> Result<Status, FailedDraw> { + let seed: [u32; 2] = [0, 0]; + let mut engine = Engine::new(1000, &seed); + while let Some(mut source) = engine.next_source() { + if let Ok(status) = f(&mut source) { + engine.mark_finished(source, status); + } else { + engine.mark_finished(source, Status::Overflow); + } + } + engine.list_minimized_examples() + } + + #[test] + fn minimizes_all_examples(){ + let results = run_to_results(|source| { + let n = source.bits(64)?; + if n >= 100 { + Ok(Status::Interesting(n % 2)) + } else { + Ok(Status::Valid) + } + }); + + assert!(results.len() == 2); + assert_eq!(results[0].record[0], 100); + assert_eq!(results[1].record[0], 101); + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/docs/changes.rst new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/docs/changes.rst --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/docs/changes.rst 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/docs/changes.rst 2018-07-20 15:37:18.000000000 +0200 @@ -21,6 +21,71 @@ You should generally assume that an API is internal unless you have specific information to the contrary. +.. _v3.66.4: + +------------------- +3.66.4 - 2018-07-20 +------------------- + +This release improves the shrinker's ability to reorder examples. + +For example, consider the following test: + +.. code-block:: python + + import hypothesis.strategies as st + from hypothesis import given + + @given(st.text(), st.text()) + def test_non_equal(x, y): + assert x != y + +Previously this could have failed with either of ``x="", y="0"`` or +``x="0", y=""``. Now it should always fail with ``x="", y="0"``. + +This will allow the shrinker to produce more consistent results, especially in +cases where test cases contain some ordered collection whose actual order does +not matter. + +.. _v3.66.3: + +------------------- +3.66.3 - 2018-07-20 +------------------- + +This patch fixes inference in the :func:`~hypothesis.strategies.builds` +strategy with subtypes of :class:`python:typing.NamedTuple`, where the +``__init__`` method is not useful for introspection. We now use the +field types instead - thanks to James Uther for identifying this bug. + +.. _v3.66.2: + +------------------- +3.66.2 - 2018-07-19 +------------------- + +This release improves the shrinker's ability to handle situations where there +is an additive constraint between two values. + +For example, consider the following test: + + +.. code-block:: python + + import hypothesis.strategies as st + from hypothesis import given + + @given(st.integers(), st.integers()) + def test_does_not_exceed_100(m, n): + assert m + n < 100 + +Previously this could have failed with almost any pair ``(m, n)`` with +``0 <= m <= n`` and ``m + n == 100``. Now it should almost always fail with +``m=0, n=100``. + +This is a relatively niche specialisation, but can be useful in situations +where e.g. a bug is triggered by an integer overflow. + .. _v3.66.1: ------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/docs/endorsements.rst new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/docs/endorsements.rst --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/docs/endorsements.rst 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/docs/endorsements.rst 2018-07-20 15:37:18.000000000 +0200 @@ -185,6 +185,18 @@ __ https://github.com/merchise/xoutil/commit/0a4a0f529812fed363efb653f3ade2d2bc203945 +---------------------------------------------- +`Florian Kromer <https://github.com/fkromer>`_ +---------------------------------------------- + +At `Roboception GmbH <https://roboception.com/en/>`_ I use Hypothesis to +implement fully automated stateless and stateful reliability tests for the +`3D sensor rc_visard <https://roboception.com/en/rc_visard-en/>`_ and +`robotic software components <https://roboception.com/en/rc_reason-en/>`_ . + +Thank you very much for creating the (probably) most powerful property-based +testing framework. + ------------------------------------------- `Your name goes here <http://example.com>`_ ------------------------------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/docs/examples.rst new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/docs/examples.rst --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/docs/examples.rst 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/docs/examples.rst 2018-07-20 15:37:18.000000000 +0200 @@ -94,7 +94,7 @@ .. code:: python - from hypothesis import settings, strategy + from hypothesis import settings, strategies import hypothesis.strategies as s NodeStrategy = s.builds( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/internal/compat.py new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/internal/compat.py --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/internal/compat.py 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/internal/compat.py 2018-07-20 15:37:18.000000000 +0200 @@ -25,6 +25,7 @@ import time import array import codecs +import inspect import platform import importlib from base64 import b64encode @@ -277,7 +278,6 @@ 'kwonlyargs, kwonlydefaults, annotations') def getfullargspec(func): - import inspect args, varargs, varkw, defaults = inspect.getargspec(func) return FullArgSpec(args, varargs, varkw, defaults, [], None, getattr(func, '__annotations__', {})) @@ -296,9 +296,10 @@ except TypeError: return {} else: + import typing + def get_type_hints(thing): try: - import typing return typing.get_type_hints(thing) except TypeError: return {} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/internal/conjecture/engine.py new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/internal/conjecture/engine.py --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/internal/conjecture/engine.py 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/internal/conjecture/engine.py 2018-07-20 15:37:18.000000000 +0200 @@ -1335,10 +1335,12 @@ if not run_expensive_shrinks: continue + self.reorder_examples() self.shrink_offset_pairs() self.interval_deletion_with_block_lowering() self.pass_to_interval() self.reorder_bytes() + self.minimize_block_pairs_retaining_sum() @property def blocks(self): @@ -2279,3 +2281,104 @@ break else: i += 1 + + def minimize_block_pairs_retaining_sum(self): + """This pass minimizes pairs of blocks subject to the constraint that + their sum when interpreted as integers remains the same. This allow us + to normalize a number of examples that we would otherwise struggle on. + e.g. consider the following: + + m = data.draw_bits(8) + n = data.draw_bits(8) + if m + n >= 256: + data.mark_interesting() + + The ideal example for this is m=1, n=255, but we will almost never + find that without a pass like this - we would only do so if we + happened to draw n=255 by chance. + + This kind of scenario comes up reasonably often in the context of e.g. + triggering overflow behaviour. + """ + i = 0 + while i < len(self.shrink_target.blocks): + if self.is_payload_block(i): + j = i + 1 + while j < len(self.shrink_target.blocks): + u, v = self.shrink_target.blocks[i] + m = int_from_bytes(self.shrink_target.buffer[u:v]) + if m == 0: + break + r, s = self.shrink_target.blocks[j] + n = int_from_bytes(self.shrink_target.buffer[r:s]) + + if ( + s - r == v - u and + self.is_payload_block(j) + ): + def trial(x, y): + if s > len(self.shrink_target.buffer): + return False + attempt = bytearray(self.shrink_target.buffer) + try: + attempt[u:v] = int_to_bytes(x, v - u) + attempt[r:s] = int_to_bytes(y, s - r) + except OverflowError: + return False + return self.incorporate_new_buffer(attempt) + # We first attempt to move 1 from m to n. If that works + # then we treat that as a sign that it's worth trying + # a more expensive minimization. But if m was already 1 + # (we know it's > 0) then there's no point continuing + # because the value there is now zero. + if trial(m - 1, n + 1) and m > 1: + m = int_from_bytes(self.shrink_target.buffer[u:v]) + n = int_from_bytes(self.shrink_target.buffer[r:s]) + + tot = m + n + minimize_int( + m, lambda x: trial(x, tot - x) + ) + j += 1 + i += 1 + + def reorder_examples(self): + """This pass allows us to reorder pairs of examples which come from the + same strategy (or strategies that happen to pun to the same label by + accident, but that shouldn't happen often). + + For example, consider the following: + + .. code-block:: python + + import hypothesis.strategies as st + from hypothesis import given + + @given(st.text(), st.text()) + def test_does_not_exceed_100(x, y): + assert x != y + + Without the ability to reorder x and y this could fail either with + ``x="", ``y="0"``, or the other way around. With reordering it will + reliably fail with ``x=""``, ``y="0"``. + """ + i = 0 + while i < len(self.shrink_target.examples): + j = i + 1 + while j < len(self.shrink_target.examples): + ex1 = self.shrink_target.examples[i] + ex2 = self.shrink_target.examples[j] + if ex1.label == ex2.label and ex2.start >= ex1.end: + buf = self.shrink_target.buffer + attempt = ( + buf[:ex1.start] + + buf[ex2.start:ex2.end] + + buf[ex1.end:ex2.start] + + buf[ex1.start:ex1.end] + + buf[ex2.end:] + ) + assert len(attempt) == len(buf) + if attempt < buf: + self.incorporate_new_buffer(attempt) + j += 1 + i += 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/internal/reflection.py new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/internal/reflection.py --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/internal/reflection.py 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/internal/reflection.py 2018-07-20 15:37:18.000000000 +0200 @@ -88,6 +88,18 @@ return hasher.digest() +def is_typed_named_tuple(cls): + """Return True if cls is probably a subtype of `typing.NamedTuple`. + + Unfortunately types created with `class T(NamedTuple):` actually + subclass `tuple` directly rather than NamedTuple. This is annoying, + and means we just have to hope that nobody defines a different tuple + subclass with similar attributes. + """ + return issubclass(cls, tuple) and hasattr(cls, '_fields') and \ + hasattr(cls, '_field_types') + + def required_args(target, args=(), kwargs=()): """Return a set of names of required args to target that were not supplied in args or kwargs. @@ -97,6 +109,11 @@ and bound methods). args and kwargs should be as they are passed to builds() - that is, a tuple of values and a dict of names: values. """ + # We start with a workaround for NamedTuples, which don't have nice inits + if inspect.isclass(target) and is_typed_named_tuple(target): + provided = set(kwargs) | set(target._fields[:len(args)]) + return set(target._fields) - provided + # Then we try to do the right thing with getfullargspec try: spec = getfullargspec( target.__init__ if inspect.isclass(target) else target) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/strategies.py new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/strategies.py --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/strategies.py 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/strategies.py 2018-07-20 15:37:18.000000000 +0200 @@ -46,7 +46,7 @@ from hypothesis.internal.renaming import renamed_arguments from hypothesis.utils.conventions import infer, not_set from hypothesis.internal.reflection import proxies, required_args, \ - define_function_signature + is_typed_named_tuple, define_function_signature from hypothesis.internal.validation import check_type, try_convert, \ check_valid_size, check_valid_bound, check_valid_sizes, \ check_valid_integer, check_valid_interval, check_valid_magnitude @@ -1125,8 +1125,14 @@ from hypothesis.searchstrategy.attrs import from_attrs return from_attrs(target, args, kwargs, required | to_infer) # Otherwise, try using type hints - hints = get_type_hints( - target.__init__ if isclass(target) else target) + if isclass(target): + if is_typed_named_tuple(target): + # Special handling for typing.NamedTuple + hints = target._field_types + else: + hints = get_type_hints(target.__init__) + else: + hints = get_type_hints(target) if to_infer - set(hints): raise InvalidArgument( 'passed infer for %s, but there is no type annotation' @@ -1248,25 +1254,22 @@ return one_of(strategies) # If we don't have a strategy registered for this type or any subtype, we # may be able to fall back on type annotations. - # Types created via typing.NamedTuple use a custom attribute instead - - # but we can still use builds(), if we work out the right kwargs. - if issubclass(thing, tuple) and hasattr(thing, '_fields') \ - and hasattr(thing, '_field_types'): - kwargs = {k: from_type(thing._field_types[k]) for k in thing._fields} - return builds(thing, **kwargs) if issubclass(thing, enum.Enum): assert len(thing), repr(thing) + ' has no members to sample' return sampled_from(thing) - # If the constructor has an annotation for all required arguments, - # or the class was defined with attrs, builds(thing) will work. - # (unless inference fails for an argument, but that's the same above too) + # If we know that builds(thing) will fail, give a better error message required = required_args(thing) - if not required or required.issubset(get_type_hints(thing.__init__)) or \ - attr.has(thing): - return builds(thing) - # We have utterly failed, and might as well say so now. - raise ResolutionFailed('Could not resolve %r to a strategy; consider ' - 'using register_type_strategy' % (thing,)) + if not any([ + not required, + required.issubset(get_type_hints(thing.__init__)), + attr.has(thing), + # NamedTuples are weird enough that we need a specific check for them. + is_typed_named_tuple(thing), + ]): + raise ResolutionFailed('Could not resolve %r to a strategy; consider ' + 'using register_type_strategy' % (thing,)) + # Finally, try to build an instance by calling the type object + return builds(thing) @cacheable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/version.py new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/version.py --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/version.py 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/version.py 2018-07-20 15:37:18.000000000 +0200 @@ -17,5 +17,5 @@ from __future__ import division, print_function, absolute_import -__version_info__ = (3, 66, 1) +__version_info__ = (3, 66, 4) __version__ = '.'.join(map(str, __version_info__)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/tests/cover/test_conjecture_engine.py new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/tests/cover/test_conjecture_engine.py --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/tests/cover/test_conjecture_engine.py 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/tests/cover/test_conjecture_engine.py 2018-07-20 15:37:18.000000000 +0200 @@ -1330,3 +1330,69 @@ runner.run() assert runner.exit_reason == ExitReason.finished + + [email protected]('lo', [0, 1, 50]) +def test_can_shrink_additively(monkeypatch, lo): + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda self: self.test_function( + ConjectureData.for_buffer(hbytes([100, 100])))) + + @run_to_buffer + def x(data): + m = data.draw_bits(8) + n = data.draw_bits(8) + if m >= lo and m + n == 200: + data.mark_interesting() + + assert list(x) == [lo, 200 - lo] + + +def test_can_shrink_additively_losing_size(monkeypatch): + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda self: self.test_function( + ConjectureData.for_buffer(hbytes([100, 100])))) + + monkeypatch.setattr( + Shrinker, 'shrink', lambda self: ( + self.minimize_block_pairs_retaining_sum(), + ) + ) + + @run_to_buffer + def x(data): + m = data.draw_bits(8) + if m >= 10: + if m <= 50: + data.mark_interesting() + else: + n = data.draw_bits(8) + if m + n == 200: + data.mark_interesting() + assert len(x) == 1 + + +def test_can_reorder_examples(monkeypatch): + monkeypatch.setattr( + ConjectureRunner, 'generate_new_examples', + lambda runner: runner.test_function( + ConjectureData.for_buffer([1, 0, 1, 1, 0, 1, 0, 0, 0]))) + + monkeypatch.setattr( + Shrinker, 'shrink', Shrinker.reorder_examples, + ) + + @run_to_buffer + def x(data): + total = 0 + for _ in range(5): + data.start_example(0) + if data.draw_bits(8): + total += data.draw_bits(9) + data.stop_example(0) + if total == 2: + data.mark_interesting() + + assert list(x) == [0, 0, 0, 1, 0, 1, 1, 0, 1] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/tests/py3/test_lookup.py new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/tests/py3/test_lookup.py --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/tests/py3/test_lookup.py 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/tests/py3/test_lookup.py 2018-07-20 15:37:18.000000000 +0200 @@ -367,6 +367,24 @@ **{k: st.just(v) for k, v in kwargs.items()}).example() +AnnotatedNamedTuple = typing.NamedTuple('AnnotatedNamedTuple', [('a', str)]) + + +@given(st.builds(AnnotatedNamedTuple)) +def test_infers_args_for_namedtuple_builds(thing): + assert isinstance(thing.a, str) + + +@given(st.from_type(AnnotatedNamedTuple)) +def test_infers_args_for_namedtuple_from_type(thing): + assert isinstance(thing.a, str) + + +@given(st.builds(AnnotatedNamedTuple, a=st.none())) +def test_override_args_for_namedtuple(thing): + assert thing.a is None + + @pytest.mark.parametrize('thing', [ typing.Optional, typing.List, getattr(typing, 'Type', typing.Set) ]) # check Type if it's available, otherwise Set is redundant but harmless diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/.rubocop.yml new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/.rubocop.yml --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/.rubocop.yml 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/.rubocop.yml 2018-07-20 15:37:18.000000000 +0200 @@ -26,3 +26,5 @@ Enabled: false Lint/HandleExceptions: Enabled: false +Style/GuardClause: + Enabled: false diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/CHANGELOG.md new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/CHANGELOG.md --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/CHANGELOG.md 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/CHANGELOG.md 2018-07-20 15:37:18.000000000 +0200 @@ -1,3 +1,8 @@ +# Hypothesis for Ruby 0.1.0 (2018-07-16) + +This release adds support for reporting multiple exceptions when Hypothesis +finds more than one way for the test to fail. + # Hypothesis for Ruby 0.0.15 (2018-06-25) This release fixes an occasional `RuntimeError` that could occur diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/Gemfile.lock new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/Gemfile.lock --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/Gemfile.lock 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/Gemfile.lock 2018-07-20 15:37:18.000000000 +0200 @@ -1,7 +1,7 @@ PATH remote: . specs: - hypothesis-specs (0.0.14) + hypothesis-specs (0.0.15) helix_runtime (~> 0.7.0) rake (>= 10.0, < 13.0) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/hypothesis-specs.gemspec new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/hypothesis-specs.gemspec --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/hypothesis-specs.gemspec 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/hypothesis-specs.gemspec 2018-07-20 15:37:18.000000000 +0200 @@ -2,8 +2,8 @@ Gem::Specification.new do |s| s.name = 'hypothesis-specs' - s.version = '0.0.15' - s.date = '2018-06-25' + s.version = '0.1.0' + s.date = '2018-07-16' s.description = <<~DESCRIPTION Hypothesis is a powerful, flexible, and easy to use library for property-based testing. DESCRIPTION diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/lib/hypothesis/engine.rb new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/lib/hypothesis/engine.rb --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/lib/hypothesis/engine.rb 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/lib/hypothesis/engine.rb 2018-07-20 15:37:18.000000000 +0200 @@ -2,9 +2,12 @@ require 'helix_runtime' require 'hypothesis-ruby/native' +require 'rspec/expectations' module Hypothesis class Engine + include RSpec::Matchers + attr_reader :current_source attr_accessor :is_find @@ -13,6 +16,8 @@ @core_engine = HypothesisCoreEngine.new( seed, options.fetch(:max_examples) ) + + @exceptions_to_tags = Hash.new { |h, k| h[k] = h.size } end def run @@ -23,7 +28,7 @@ begin result = yield(@current_source) if is_find && result - @core_engine.finish_interesting(core) + @core_engine.finish_interesting(core, 0) else @core_engine.finish_valid(core) end @@ -31,54 +36,64 @@ @core_engine.finish_invalid(core) rescue DataOverflow @core_engine.finish_overflow(core) - rescue Exception + rescue Exception => e raise if is_find - @core_engine.finish_interesting(core) + key = [ + e.class, + HypothesisJunkDrawer.find_first_relevant_line(e.backtrace) + ] + @core_engine.finish_interesting(core, @exceptions_to_tags[key]) end end - @current_source = nil - core = @core_engine.failing_example - if core.nil? + if @core_engine.count_failing_examples.zero? raise Unsatisfiable if @core_engine.was_unsatisfiable + @current_source = nil return end if is_find + core = @core_engine.failing_example(0) @current_source = TestCase.new(core, record_draws: true) yield @current_source else - @current_source = TestCase.new(core, print_draws: true) - - begin - yield @current_source - rescue Exception => e - givens = @current_source.print_log - given_str = givens.each_with_index.map do |(name, s), i| - name = "##{i + 1}" if name.nil? - "Given #{name}: #{s}" - end.to_a - - if e.respond_to? :hypothesis_data - e.hypothesis_data[0] = given_str - else - original_to_s = e.to_s - original_inspect = e.inspect - - class <<e - attr_accessor :hypothesis_data - - def to_s - ['', hypothesis_data[0], '', hypothesis_data[1]].join("\n") - end - - def inspect - ['', hypothesis_data[0], '', hypothesis_data[2]].join("\n") + exceptions = [] + (0...@core_engine.count_failing_examples).each do |example| + core = @core_engine.failing_example(example) + @current_source = TestCase.new(core, print_draws: true) + + begin + yield @current_source + rescue Exception => e + givens = @current_source.print_log + given_str = givens.each_with_index.map do |(name, s), i| + name = "##{i + 1}" if name.nil? + "Given #{name}: #{s}" + end.to_a + + if e.respond_to? :hypothesis_data + e.hypothesis_data[0] = given_str + else + original_to_s = e.to_s + original_inspect = e.inspect + + class <<e + attr_accessor :hypothesis_data + + def to_s + ['', hypothesis_data[0], '', hypothesis_data[1]].join("\n") + end + + def inspect + ['', hypothesis_data[0], '', hypothesis_data[2]].join("\n") + end end + e.hypothesis_data = [given_str, original_to_s, original_inspect] end - e.hypothesis_data = [given_str, original_to_s, original_inspect] + raise e if @core_engine.count_failing_examples == 1 + exceptions.push(e) end - raise e end + raise Hypothesis::MultipleExceptionError.new(*exceptions) end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/lib/hypothesis/errors.rb new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/lib/hypothesis/errors.rb --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/lib/hypothesis/errors.rb 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/lib/hypothesis/errors.rb 2018-07-20 15:37:18.000000000 +0200 @@ -25,4 +25,37 @@ # @!visibility private class DataOverflow < HypothesisError end + + if defined?(RSpec::Core::MultipleExceptionError) + MultipleExceptionErrorParent = RSpec::Core::MultipleExceptionError + # :nocov: + else + class MultipleExceptionErrorParent < StandardError + def initialize(*exceptions) + super() + + @all_exceptions = exceptions.to_a + end + + attr_reader :all_exceptions + end + end + + class MultipleExceptionError < MultipleExceptionErrorParent + def message + jd = HypothesisJunkDrawer + "Test raised #{all_exceptions.length} distinct errors:\n\n" + + all_exceptions.map do |e| + location = jd.find_first_relevant_line(e.backtrace).sub(/:in.+$/, '') + backtrace = jd.prune_backtrace(e.backtrace) + "#{e.class} at #{location}:\n" \ + "#{e.message}\n#{backtrace.map { |s| ' ' + s } + .join("\n")}" + end.join("\n\n") + end + + def backtrace + [] + end + end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/lib/hypothesis/junkdrawer.rb new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/lib/hypothesis/junkdrawer.rb --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/lib/hypothesis/junkdrawer.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/lib/hypothesis/junkdrawer.rb 2018-07-20 15:37:18.000000000 +0200 @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Hypothesis + # @!visibility private + module HypothesisJunkDrawer + HYPOTHESIS_ROOT = File.absolute_path(File.dirname(__FILE__)) + + def self.prune_backtrace(backtrace) + result = [] + seen_hypothesis = false + backtrace.each do |b| + if b.start_with?(HYPOTHESIS_ROOT) + seen_hypothesis = true + else + result.push(b) + break if seen_hypothesis + end + end + result + end + + def self.find_first_relevant_line(backtrace) + backtrace.each do |b| + next if b.include?('minitest/assertions.rb') + next if b.start_with?(HYPOTHESIS_ROOT) + return b + end + nil + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/lib/hypothesis.rb new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/lib/hypothesis.rb --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/lib/hypothesis.rb 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/lib/hypothesis.rb 2018-07-20 15:37:18.000000000 +0200 @@ -1,5 +1,6 @@ # frozen_string_literal: true +require 'hypothesis/junkdrawer' require 'hypothesis/errors' require 'hypothesis/possible' require 'hypothesis/testcase' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/minitests/test_multiple_failures.rb new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/minitests/test_multiple_failures.rb --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/minitests/test_multiple_failures.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/minitests/test_multiple_failures.rb 2018-07-20 15:37:18.000000000 +0200 @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'minitest/autorun' +require 'hypothesis' + +class TestMultipleFailures < Minitest::Test + include Hypothesis + include Hypothesis::Possibilities + + def test_multiple_failures + assert_raises(Hypothesis::MultipleExceptionError) do + @initial = nil + + hypothesis do + x = any integers + if @initial.nil? + if x >= 1000 + @initial = x + else + next + end + end + + assert(x != @initial) + raise 'Nope' + end + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/spec/backtrace_spec.rb new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/spec/backtrace_spec.rb --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/spec/backtrace_spec.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/spec/backtrace_spec.rb 2018-07-20 15:37:18.000000000 +0200 @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +RSpec.describe 'backtrace manipulation' do + JD = Hypothesis::HypothesisJunkDrawer + + it 'identifies the test file as relevant' do + JD.find_first_relevant_line(caller).include?('backtrace_spec.rb') + end + + it 'prunes out hypothesis and rspec related lines' do + hypothesis do + relevant = JD.prune_backtrace(caller) + relevant.each do |e| + expect(e).to_not include(JD::HYPOTHESIS_ROOT) + expect(e).to_not include('/rspec-core/') + end + expect(relevant.grep(/backtrace_spec.rb/)).to_not be_empty + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/spec/multiple_failures_spec.rb new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/spec/multiple_failures_spec.rb --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/spec/multiple_failures_spec.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/spec/multiple_failures_spec.rb 2018-07-20 15:37:18.000000000 +0200 @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +RSpec.describe 'tests with multiple failures' do + they 'show multiple failures' do + expect do + @initial = nil + + hypothesis do + x = any integers + if @initial.nil? + if x >= 1000 + @initial = x + else + next + end + end + + expect(x).to_not eq(@initial) + raise 'Nope' + end + end.to raise_exception(Hypothesis::MultipleExceptionError) { |e| + expect(e.all_exceptions.length).to eq(2) + } + end +end + +RSpec.describe Hypothesis::MultipleExceptionError do + it 'includes the message from each exception' do + exceptions = [] + %w[hello world].each do |m| + begin + raise m + rescue Exception => e + exceptions.append(e) + end + end + + e = Hypothesis::MultipleExceptionError.new(*exceptions) + expect(e.message).to include('hello') + expect(e.message).to include('world') + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/spec/spec_helper.rb new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/spec/spec_helper.rb --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/spec/spec_helper.rb 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/spec/spec_helper.rb 2018-07-20 15:37:18.000000000 +0200 @@ -2,10 +2,51 @@ require 'simplecov' SimpleCov.minimum_coverage 100 + +class PrintingFormatter + # Takes a SimpleCov::Result and generates a string out of it + def format(result) + bad = [] + result.files.each do |file| + bad.push file if file.covered_percent < 100.0 + end + + unless bad.empty? + puts 'Files with missing coverage!' + bad.each do |file| + lines = file.source_lines.select { |l| l.coverage == 0 } + .map(&:line_number).sort + s = lines[0] + groups = [[s, s]] + lines.each do |i| + if i <= groups[-1][-1] + 1 + groups[-1][-1] = i + else + groups.push([i, i]) + end + end + markers = [] + groups.each do |g| + if g[0] == g[1] + markers.push(g[0].to_s) + else + markers.push(g.join('-')) + end + end + puts "#{file.filename}: #{markers.join(', ')}" + end + end + end +end + +SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new( + [SimpleCov::Formatter::HTMLFormatter, PrintingFormatter] +) + SimpleCov.start do add_filter do |source_file| name = source_file.filename - !(name.include?('/hypothesis/') || name.end_with?('hypothesis.rb')) + !(name.include?('/hypothesis-ruby/lib/') || name.end_with?('hypothesis.rb')) end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/src/lib.rs new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/src/lib.rs --- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/src/lib.rs 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/src/lib.rs 2018-07-20 15:37:18.000000000 +0200 @@ -15,7 +15,7 @@ use std::mem; -use conjecture::data::{DataSource, Status}; +use conjecture::data::{DataSource, Status, TestResult}; use conjecture::distributions::Repeat; use conjecture::distributions; use conjecture::engine::Engine; @@ -49,6 +49,7 @@ struct { engine: Engine, pending: Option<DataSource>, + interesting_examples: Vec<TestResult>, } def initialize(helix, seed: u64, max_examples: u64){ @@ -57,12 +58,16 @@ helix, engine: Engine::new(max_examples, &xs), pending: None, + interesting_examples: Vec::new(), } } def new_source(&mut self) -> Option<HypothesisCoreDataSource> { match self.engine.next_source() { - None => None, + None => { + self.interesting_examples = self.engine.list_minimized_examples(); + None + }, Some(source) => { self.pending = Some(source); Some(HypothesisCoreDataSource::new(self)) @@ -70,13 +75,15 @@ } } - def failing_example(&mut self) -> Option<HypothesisCoreDataSource> { - if let Some(source) = self.engine.best_source() { - self.pending = Some(source); - return Some(HypothesisCoreDataSource::new(self)); - } else { - return None; - } + def count_failing_examples(&self) -> usize { + self.interesting_examples.len() + } + + def failing_example(&mut self, i: usize) -> HypothesisCoreDataSource { + self.pending = Some( + DataSource::from_vec(self.interesting_examples[i].record.clone()) + ); + HypothesisCoreDataSource::new(self) } def was_unsatisfiable(&mut self) -> bool { @@ -91,8 +98,8 @@ mark_child_status(&mut self.engine, child, Status::Invalid); } - def finish_interesting(&mut self, child: &mut HypothesisCoreDataSource){ - mark_child_status(&mut self.engine, child, Status::Interesting); + def finish_interesting(&mut self, child: &mut HypothesisCoreDataSource, label: u64){ + mark_child_status(&mut self.engine, child, Status::Interesting(label)); } def finish_valid(&mut self, child: &mut HypothesisCoreDataSource){ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/requirements/coverage.txt new/hypothesis-hypothesis-python-3.66.4/requirements/coverage.txt --- old/hypothesis-hypothesis-python-3.66.1/requirements/coverage.txt 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/requirements/coverage.txt 2018-07-20 15:37:18.000000000 +0200 @@ -6,7 +6,7 @@ # coverage==4.5.1 numpy==1.14.5 -pandas==0.23.1 +pandas==0.23.3 python-dateutil==2.7.3 # via pandas pytz==2018.5 six==1.11.0 # via python-dateutil diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/requirements/test.txt new/hypothesis-hypothesis-python-3.66.4/requirements/test.txt --- old/hypothesis-hypothesis-python-3.66.1/requirements/test.txt 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/requirements/test.txt 2018-07-20 15:37:18.000000000 +0200 @@ -4,17 +4,17 @@ # # pip-compile --output-file requirements/test.txt requirements/test.in # -apipkg==1.4 # via execnet +apipkg==1.5 # via execnet atomicwrites==1.1.5 # via pytest attrs==18.1.0 execnet==1.5.0 # via pytest-xdist flaky==3.4.0 mock==2.0.0 more-itertools==4.2.0 # via pytest -pbr==4.0.4 # via mock +pbr==4.1.0 # via mock pluggy==0.6.0 # via pytest py==1.5.4 # via pytest pytest-forked==0.2 # via pytest-xdist pytest-xdist==1.22.2 -pytest==3.6.2 +pytest==3.6.3 six==1.11.0 # via mock, more-itertools, pytest diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/requirements/tools.in new/hypothesis-hypothesis-python-3.66.4/requirements/tools.in --- old/hypothesis-hypothesis-python-3.66.1/requirements/tools.in 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/requirements/tools.in 2018-07-20 15:37:18.000000000 +0200 @@ -17,7 +17,3 @@ django numpy IPython - -prompt-toolkit==1.0.15 # via ipython==6.4.0 -pycodestyle==2.3.1 # via flake8==3.5.0 -pyflakes==1.6.0 # via flake8==3.5.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/requirements/tools.txt new/hypothesis-hypothesis-python-3.66.4/requirements/tools.txt --- old/hypothesis-hypothesis-python-3.66.1/requirements/tools.txt 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/requirements/tools.txt 2018-07-20 15:37:18.000000000 +0200 @@ -34,43 +34,43 @@ markupsafe==1.0 # via jinja2 mccabe==0.6.1 # via flake8 more-itertools==4.2.0 # via pytest -mypy==0.610 +mypy==0.620 numpy==1.14.5 -packaging==17.1 # via dparse, pyupio, safety, sphinx +packaging==17.1 # via dparse, pyupio, safety, sphinx, tox parso==0.3.0 # via jedi pexpect==4.6.0 # via ipython pickleshare==0.7.4 # via ipython pip-tools==2.0.2 pkginfo==1.4.2 # via twine pluggy==0.6.0 # via pytest, tox -prompt-toolkit==1.0.15 +prompt-toolkit==1.0.15 # via ipython ptyprocess==0.6.0 # via pexpect py==1.5.4 # via pytest, tox -pycodestyle==2.3.1 +pycodestyle==2.3.1 # via autopep8, flake8 pydocstyle==2.1.1 # via flake8-docstrings -pyflakes==1.6.0 +pyflakes==1.6.0 # via autoflake, flake8 pyformat==0.7 pygithub==1.40 # via pyupio pygments==2.2.0 # via ipython, sphinx pyjwt==1.6.4 # via pygithub pyparsing==2.2.0 # via packaging -pytest==3.6.2 +pytest==3.6.3 python-dateutil==2.7.3 python-gitlab==1.5.1 # via pyupio pytz==2018.5 # via babel, django pyupio==1.0.1 -pyyaml==3.12 # via dparse, pyupio +pyyaml==3.13 # via dparse, pyupio requests-toolbelt==0.8.0 # via twine requests==2.19.1 # via pygithub, python-gitlab, pyupio, requests-toolbelt, safety, sphinx, twine restructuredtext-lint==1.1.3 -safety==1.8.1 # via pyupio +safety==1.8.2 # via pyupio simplegeneric==0.8.1 # via ipython six==1.11.0 # via dparse, more-itertools, packaging, pip-tools, prompt-toolkit, pydocstyle, pytest, python-dateutil, python-gitlab, pyupio, sphinx, tox, traitlets snowballstemmer==1.2.1 # via pydocstyle, sphinx sphinx-rtd-theme==0.4.0 sphinx==1.7.5 sphinxcontrib-websupport==1.1.0 # via sphinx -tox==3.0.0 +tox==3.1.2 tqdm==4.23.4 # via pyupio, twine traitlets==4.3.2 # via ipython twine==1.11.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/tooling/scripts/ensure-rustup.sh new/hypothesis-hypothesis-python-3.66.4/tooling/scripts/ensure-rustup.sh --- old/hypothesis-hypothesis-python-3.66.1/tooling/scripts/ensure-rustup.sh 2018-07-09 01:06:33.000000000 +0200 +++ new/hypothesis-hypothesis-python-3.66.4/tooling/scripts/ensure-rustup.sh 2018-07-20 15:37:18.000000000 +0200 @@ -13,4 +13,4 @@ rustup default stable -rustup update +rustup update stable
