def wait_for_next(self, expectation, freeze=True, explain=True, observe=True): if explain: print(colors.LIGHT_MAGENTA + 'Waiting for next ' + colors.RESET + colors.color_repr(expectation)) return self._wait_until_realized(expectation, False, freeze, explain, observe)
def wait_for(self, expectation, freeze=None, explain=True): assert expectation.has_lower_bound, ( 'Expectation must have a lower time bound to be used with wait_for()! ' 'Use >> to sequence an expectation against an occurrence to establish a lower bound, ' 'or wait_for_next() to wait for the next expectation since the timeline was last ' 'frozen, or wait_until_realized() when a lower bound is really not necessary.' ) if explain: print(colors.LIGHT_MAGENTA + 'Waiting for ' + colors.RESET + colors.color_repr(expectation)) return self._wait_until_realized(expectation, freeze, explain=explain)
def _explain_how_realized(self, occurrence, expectation, reasons): message = (colors.LIGHT_MAGENTA + 'Realized ' + colors.RESET + colors.color_repr(expectation) + colors.LIGHT_MAGENTA + ' via ' + colors.RESET + colors.color_repr(occurrence)) # For the breakdown, we want to skip the top-level expectation (since we already # printed that above), and also any expectations that were exact occurrences, # since there's no point explaining that occurrence was realized by itself. skip = [expectation] + [ exp for exp in reasons.keys() if isinstance(exp, Occurrence) ] for exp in skip: reasons.pop(exp, None) if reasons: message += colors.LIGHT_MAGENTA + '; breakdown:' + colors.RESET for exp, reason in reasons.items(): message += ('\n ' + colors.color_repr(exp) + colors.LIGHT_MAGENTA + ' by ' + colors.RESET + colors.color_repr(reason)) print(message)
def wait_until_realized(self, expectation, freeze=None, explain=True, observe=True): if explain: print(colors.LIGHT_MAGENTA + 'Waiting for ' + colors.RESET + colors.color_repr(expectation)) reasons = {} check_past = [True] def has_been_realized(occ): # First time wait_until() calls us, we have to check the whole timeline. # On subsequent calls, we only need to check the newly added occurrence. if check_past: # if explain: # print( # colors.LIGHT_MAGENTA + 'Testing ' + colors.RESET + # colors.color_repr(expectation) + # colors.LIGHT_MAGENTA + ' against timeline up to and including ' + colors.RESET + # colors.color_repr(occ) # ) reasons.update(expectation.test_at_or_before(occ) or {}) del check_past[:] else: # if explain: # print( # colors.LIGHT_MAGENTA + 'Testing ' + colors.RESET + # colors.color_repr(expectation) + # colors.LIGHT_MAGENTA + ' against ' + colors.RESET + # colors.color_repr(occ) # ) reasons.update(expectation.test_at(occ) or {}) if reasons: if observe: self.expect_realized(expectation, explain=explain, observe=observe) return True # else: # if explain: # print( # colors.color_repr(occ) + # colors.LIGHT_MAGENTA + ' did not realize ' + colors.RESET + # colors.color_repr(expectation) # ) self.wait_until(has_been_realized, freeze) realized_at = reasons[expectation] return realized_at
def has_been_realized(occ): # First time wait_until() calls us, we have to check the whole timeline. # On subsequent calls, we only need to check the newly added occurrence. if check_past: if explain: print( colors.LIGHT_MAGENTA + 'Testing ' + colors.RESET + colors.color_repr(expectation) + colors.LIGHT_MAGENTA + ' against timeline up to and including ' + colors.RESET + colors.color_repr(occ) ) reasons.update(expectation.test_at_or_before(occ) or {}) del check_past[:] else: if explain: print( colors.LIGHT_MAGENTA + 'Testing ' + colors.RESET + colors.color_repr(expectation) + colors.LIGHT_MAGENTA + ' against ' + colors.RESET + colors.color_repr(occ) ) reasons.update(expectation.test_at(occ) or {}) if reasons: if observe: self.expect_realized(expectation, explain=explain, observe=observe) return True else: if explain: print( colors.color_repr(occ) + colors.LIGHT_MAGENTA + ' did not realize ' + colors.RESET + colors.color_repr(expectation) )
def expect_no_unobserved(self): if not self: return # print('Checking for unobserved since %s' % colors.color_repr(self[0])) unobserved = [ occ for occ in self if not occ.observed and all( exp != occ for exp in self.timeline.ignore_unobserved) ] if not unobserved: return print(colors.LIGHT_RED + 'Unobserved occurrences detected:' + colors.RESET) for occ in unobserved: print(' ' + colors.color_repr(occ)) raise Exception('Unobserved occurrences detected')
def _expect_realized(self, expectation, first, explain=True, observe=True): self.expect_frozen() try: reasons = next(expectation.test(first, self.last)) except StopIteration: print(colors.LIGHT_RED + 'No matching ' + colors.RESET + colors.color_repr(expectation)) # The weird always-false assert is to make pytest print occurrences nicely. occurrences = list(first.and_following()) assert occurrences is ('not matching expectation', expectation) occs = tuple(reasons.values()) assert occs if observe: self.observe(*occs) if explain: self._explain_how_realized(expectation, reasons) return occs if len(occs) > 1 else occs[0]
def _expect_realized(self, expectation, occurrences, explain=True, observe=True): self.expect_frozen() occurrences = list(occurrences) reasons = expectation.test_until_realized(occurrences) if reasons is None: print(colors.LIGHT_RED + 'No matching ' + colors.RESET + colors.color_repr(expectation)) # The weird always-false assert is to make pytest print occurrences nicely. occurrences = list(occurrences) assert occurrences is ('not matching expectation', expectation) if observe: self.observe(*reasons.values()) realized_at = reasons[expectation] if explain: self._explain_how_realized(realized_at, expectation, reasons) return realized_at