Repository: HypothesisWorks/hypothesis

Issue:
test_explore_an_arbitrary_language found a bug
https://travis-ci.org/HypothesisWorks/hypothesis/jobs/399408345#L1111

Assigning to @DRMacIver, who added this test in #1302.  (:dog::wink:)


Discussion:
In fact, this is not an example of flakiness, but of Hypothesis behaving how it's supposed to and occasionaly finding new bugs in the code!
🎉 

Resolving patch:
diff --git a/hypothesis-python/src/hypothesis/internal/conjecture/engine.py b/hypothesis-python/src/hypothesis/internal/conjecture/engine.py
--- a/hypothesis-python/src/hypothesis/internal/conjecture/engine.py
+++ b/hypothesis-python/src/hypothesis/internal/conjecture/engine.py
@@ -663,6 +663,17 @@ def generate_new_examples(self):
                 HealthCheck.large_base_example
             )
 
+        # If the language starts with writes of length >= cap then there is
+        # only one string in it: Everything after cap is forced to be zero (or
+        # to be whatever value is written there). That means that once we've
+        # tried the zero value, there's nothing left for us to do, so we
+        # exit early here.
+        for i in hrange(self.cap):
+            if i not in zero_data.forced_indices:
+                break
+        else:
+            self.exit_with(ExitReason.finished)
+
         self.health_check_state = HealthCheckState()
 
         count = 0


Test patch:
diff --git a/hypothesis-python/tests/cover/test_conjecture_engine.py b/hypothesis-python/tests/cover/test_conjecture_engine.py
--- a/hypothesis-python/tests/cover/test_conjecture_engine.py
+++ b/hypothesis-python/tests/cover/test_conjecture_engine.py
@@ -36,7 +36,7 @@
     ConjectureData
 from hypothesis.internal.conjecture.utils import calc_label_from_name
 from hypothesis.internal.conjecture.engine import Negated, Shrinker, \
-    RunIsComplete, ConjectureRunner, universal
+    ExitReason, RunIsComplete, ConjectureRunner, universal
 
 SOME_LABEL = calc_label_from_name('some label')
 
@@ -1313,3 +1313,20 @@ def x(data):
                 break
         data.mark_interesting()
     assert x == hbytes([0])
+
+
+def test_large_initial_write():
+    big = hbytes(b'\xff') * 512
+
+    def f(data):
+        data.write(big)
+        data.draw_bits(63)
+
+    with deterministic_PRNG():
+        runner = ConjectureRunner(f, settings=settings(
+            max_examples=5000, buffer_size=1024,
+            database=None, suppress_health_check=HealthCheck.all(),
+        ))
+        runner.run()
+
+    assert runner.exit_reason == ExitReason.finished
diff --git a/hypothesis-python/tests/nocover/test_explore_arbitrary_languages.py b/hypothesis-python/tests/nocover/test_explore_arbitrary_languages.py
--- a/hypothesis-python/tests/nocover/test_explore_arbitrary_languages.py
+++ b/hypothesis-python/tests/nocover/test_explore_arbitrary_languages.py
@@ -23,13 +23,22 @@
 import pytest
 
 import hypothesis.strategies as st
-from hypothesis import Verbosity, HealthCheck, note, given, assume, \
-    settings, unlimited
+import hypothesis.internal.escalation as esc
+from hypothesis import Phase, Verbosity, HealthCheck, note, given, \
+    assume, settings, unlimited
 from hypothesis.internal.compat import hbytes
 from hypothesis.internal.conjecture.data import Status
 from hypothesis.internal.conjecture.engine import ConjectureRunner
 
 
+def setup_module(module):
+    esc.PREVENT_ESCALATION = True
+
+
+def teardown_module(module):
+    esc.PREVENT_ESCALATION = False
+
+
 @attr.s()
 class Write(object):
     value = attr.ib()
@@ -95,7 +104,7 @@ def test(local_data):
     runner = ConjectureRunner(test, settings=settings(
         max_examples=1, max_shrinks=100, buffer_size=512,
         database=None, suppress_health_check=HealthCheck.all(),
-        verbosity=Verbosity.quiet,
+        verbosity=Verbosity.quiet, phases=list(Phase),
     ))
     try:
         runner.run()
@@ -107,8 +116,8 @@ def test(local_data):
 
 @settings(
     max_examples=100, suppress_health_check=HealthCheck.all(),
-    deadline=None, verbosity=Verbosity.debug, timeout=unlimited,
-    use_coverage=False,
+    deadline=None, timeout=unlimited,
+    use_coverage=False, phases=set(Phase) - {Phase.shrink},
 )
 @given(st.data())
 def test_explore_an_arbitrary_language(data):