Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't do unnecessary condition evaluations in assertEventuallyTrueInGui #1168

Merged
13 changes: 9 additions & 4 deletions pyface/ui/qt4/util/event_loop_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,14 @@ def event_loop_until_condition(self, condition, timeout=10.0):
`timeout` is rounded to the nearest millisecond.
"""

condition_result = False
mdickinson marked this conversation as resolved.
Show resolved Hide resolved

def handler():
if condition():
self.qt_app.quit()
nonlocal condition_result

condition_result = bool(condition())
if condition_result:
self.qt_app.exit()

# Make sure we don't get a premature exit from the event loop.
with dont_quit_when_last_window_closed(self.qt_app):
Expand All @@ -123,12 +128,12 @@ def handler():
timeout_timer = QtCore.QTimer()
timeout_timer.setSingleShot(True)
timeout_timer.setInterval(round(timeout * 1000))
timeout_timer.timeout.connect(self.qt_app.quit)
timeout_timer.timeout.connect(self.qt_app.exit)
timeout_timer.start()
condition_timer.start()
try:
self.qt_app.exec_()
if not condition():
if not condition_result:
raise ConditionTimeoutError(
"Timed out waiting for condition"
)
Expand Down
35 changes: 35 additions & 0 deletions pyface/ui/qt4/util/tests/test_gui_test_assistant.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
import itertools
import unittest

from pyface.timer.api import CallbackTimer
Expand Down Expand Up @@ -94,3 +95,37 @@ def test_assert_eventually_true_in_gui_failure(self):
self.assertEventuallyTrueInGui(
lambda: len(my_list) > 0, timeout=0.1
)

def test_assert_eventually_true_in_gui_dont_retest_immediately_true(self):
# Given an always-True condition
return_value_logs = []

def logging_condition():
return_value = True
return_value_logs.append(return_value)
return return_value

# When we wait for the condition to become true
self.assertEventuallyTrueInGui(logging_condition)

# Then the condition should have been evaluated exactly once.
self.assertEqual(return_value_logs, [True])

def test_assert_eventually_true_in_gui_dont_retest_eventually_true(self):
# Given a condition that returns two False values, followed by
# infinitely many True values ...
return_values = itertools.chain([False]*2, itertools.repeat(True))

return_value_logs = []

def logging_condition():
return_value = next(return_values)
return_value_logs.append(return_value)
return return_value

# When we wait for the condition to become true
self.assertEventuallyTrueInGui(logging_condition)

# Then the condition should not have been evaluated again after
# becoming True.
self.assertEqual(return_value_logs.count(True), 1)