docstr: Checks the tree to see if we've tested this buffer, and returns the
  previous result if we have.
  
  Otherwise we call through to ``test_function``, and return a
  fresh result.
  
  If ``error_on_discard`` is set to True this will raise ``ContainsDiscard``
  in preference to running the actual test function. This is to allow us
  to skip test cases we expect to be redundant in some cases. Note that
  it may be the case that we don't raise ``ContainsDiscard`` even if the
  result has discards if we cannot determine from previous runs whether
  it will have a discard.
code: def cached_test_function(
      self, buffer, error_on_discard=False, extend=0
  ):
      """Checks the tree to see if we've tested this buffer, and returns the
      previous result if we have.
  
      Otherwise we call through to ``test_function``, and return a
      fresh result.
  
      If ``error_on_discard`` is set to True this will raise ``ContainsDiscard``
      in preference to running the actual test function. This is to allow us
      to skip test cases we expect to be redundant in some cases. Note that
      it may be the case that we don't raise ``ContainsDiscard`` even if the
      result has discards if we cannot determine from previous runs whether
      it will have a discard.
      """
      buffer = hbytes(buffer)[:BUFFER_SIZE]
  
      max_length = min(BUFFER_SIZE, len(buffer) + extend)
  
      def check_result(result):
          assert result is Overrun or (
              isinstance(result, ConjectureResult)
              and result.status != Status.OVERRUN
          )
          return result
  
      try:
          return check_result(self.__data_cache[buffer])
      except KeyError:
          pass
  
      if error_on_discard:
  
          class DiscardObserver(DataObserver):
              def kill_branch(self):
                  raise ContainsDiscard()
  
          observer = DiscardObserver()
      else:
          observer = DataObserver()
  
      dummy_data = self.new_conjecture_data(
          prefix=buffer, max_length=max_length, observer=observer
      )
  
      try:
          self.tree.simulate_test_function(dummy_data)
      except PreviouslyUnseenBehaviour:
          pass
      else:
          if dummy_data.status > Status.OVERRUN:
              dummy_data.freeze()
              try:
                  return self.__data_cache[dummy_data.buffer]
              except KeyError:
                  pass
          else:
              self.__data_cache[buffer] = Overrun
              return Overrun
  
      # We didn't find a match in the tree, so we need to run the test
      # function normally. Note that test_function will automatically
      # add this to the tree so we don't need to update the cache.
  
      result = None
  
      data = self.new_conjecture_data(
          prefix=max((buffer, dummy_data.buffer), key=len),
          max_length=max_length,
      )
      self.test_function(data)
      result = check_result(data.as_result())
      self.__data_cache[buffer] = result
      return result
  
imports: from __future__ import absolute_import, division, print_function
  from collections import Counter, defaultdict
  from enum import Enum
  from random import Random, getrandbits
  from weakref import WeakKeyDictionary
  import attr
  from hypothesis import HealthCheck, Phase, Verbosity, settings
  from hypothesis._settings import local_settings
  from hypothesis.internal.cache import LRUReusedCache
  from hypothesis.internal.compat import ceil, hbytes, int_from_bytes
  from hypothesis.internal.conjecture.data import ConjectureData, ConjectureResult, DataObserver, Overrun, Status, StopTest
  from hypothesis.internal.conjecture.datatree import DataTree, PreviouslyUnseenBehaviour, TreeRecordingObserver
  from hypothesis.internal.conjecture.junkdrawer import clamp
  from hypothesis.internal.conjecture.pareto import NO_SCORE, ParetoFront, ParetoOptimiser
  from hypothesis.internal.conjecture.shrinker import Shrinker, sort_key
  from hypothesis.internal.healthcheck import fail_health_check
  from hypothesis.reporting import base_report
label_desc: Use image node_id 33 for calling the ConjectureRunner obj's underlying member method code with example usage: obj.cached_test_function(buffer, error_on_discard, extend) and returns: result, result, check_result, Overrun, self