[Checkins] SVN: gocept.selenium/trunk/src/gocept/selenium/ refactored and fixed fall-back rules for assertions, improved failure messages
Thomas Lotze
tl at gocept.com
Wed Mar 17 03:03:47 EDT 2010
Log message for revision 110012:
refactored and fixed fall-back rules for assertions, improved failure messages
Changed:
U gocept.selenium/trunk/src/gocept/selenium/selenese.py
U gocept.selenium/trunk/src/gocept/selenium/ztk/tests/test_selenese.py
-=-
Modified: gocept.selenium/trunk/src/gocept/selenium/selenese.py
===================================================================
--- gocept.selenium/trunk/src/gocept/selenium/selenese.py 2010-03-17 02:17:26 UTC (rev 110011)
+++ gocept.selenium/trunk/src/gocept/selenium/selenese.py 2010-03-17 07:03:47 UTC (rev 110012)
@@ -274,53 +274,86 @@
def __getattr__(self, name):
requested_name = name
+ def _getattr(name):
+ try:
+ return getattr(self, name)
+ except AttributeError:
+ raise AttributeError(requested_name)
+
+ # Generate a number of assertions that aren't implemented directly.
+ # Apply a fall-back chain that first implements waitFor* using
+ # corresponding assert* and maps verify* methods to corresponding
+ # assert*, then implements negative assert* by negating their positive
+ # counterparts. Generate only these three kinds of assertions. After
+ # each fall-back step, getattr() is called to make use of all directly
+ # implemented methods. If a method cannot be looked up in spite of the
+ # fall-back, raise an AttributeError that reports the method name
+ # actually used by client code.
if name.startswith('waitFor'):
name = name.replace('waitFor', 'assert', 1)
- assertion = getattr(self, name)
+ assertion = _getattr(name)
return (lambda *args, **kw:
self._waitFor(assertion, *args, **kw))
+ if name.startswith('verify'):
+ name = name.replace('verify', 'assert', 1)
+ return _getattr(name)
+
+ if not name.startswith('assert'):
+ raise AttributeError(requested_name)
+
if 'Not' in name:
name = name.replace('Not', '', 1)
+ assertion = _getattr(name)
+ return (lambda *args, **kw:
+ self._negate(assertion, requested_name, *args, **kw))
- if name.startswith('verify'):
- name = name.replace('verify', 'assert', 1)
+ # Positive assertions are synthesised by looking up a getter method
+ # for a value, getting the value and evaluating it in an appropriate
+ # way. Getters may be named either get* or is*.
+ try:
+ getter = _getattr(name.replace('assert', 'get', 1))
+ except AttributeError:
+ getter = _getattr(name.replace('assert', 'is', 1))
- if name.startswith('assert'):
- getter_name = name.replace('assert', 'get', 1)
- getter = getattr(self, getter_name, None)
- if getter is None:
- getter_name = name.replace('assert', 'is', 1)
- getter = getattr(self, getter_name, None)
- if getter is None:
- raise AttributeError(requested_name)
- if getter.assert_type == 'pattern':
- return lambda pattern: self._assert_pattern(
- getter, requested_name, pattern)
- elif getter.assert_type == 'locator':
- return lambda locator: self._assert(
- getter, requested_name, locator)
- elif getter.assert_type == 'locator_pattern':
- return lambda locator, pattern: self._assert_pattern(
- getter, requested_name, pattern, locator)
- elif getter.assert_type is None:
- return lambda: self._assert(getter, requested_name)
+ if getter.assert_type == 'pattern':
+ return lambda pattern: self._assert_pattern(
+ getter, requested_name, pattern)
+ elif getter.assert_type == 'locator':
+ return lambda locator: self._assert(
+ getter, requested_name, locator)
+ elif getter.assert_type == 'locator_pattern':
+ return lambda locator, pattern: self._assert_pattern(
+ getter, requested_name, pattern, locator)
+ elif getter.assert_type is None:
+ return lambda: self._assert(getter, requested_name)
+ else:
+ raise ValueError('Unknown assert type %r for selenese method %r.'
+ % (getter.assert_type, requested_name))
- raise AttributeError(requested_name)
-
def _assert(self, getter, name, *args, **kw):
- if ('Not' not in name) ^ bool(getter(*args, **kw)):
+ value = getter(*args, **kw)
+ if not value:
raise self.failureException(
- 'not valid: %s(%r, %r)' % (name, args, kw))
+ 'Failed: %s -> %r' %
+ (self._call_repr(name, *args, **kw), value))
def _assert_pattern(self, getter, name, pattern, *args):
result = getter(*args)
- if ('Not' not in name) ^ bool(
- selenese_pattern_equals(result, pattern)):
+ if not selenese_pattern_equals(result, pattern):
raise self.failureException(
- '%r did not match expected %r'
- % (result, pattern))
+ 'Expected: %r, got: %r from %s' %
+ (pattern, result, self._call_repr(name, *args)))
+ def _negate(self, assertion, name, *args, **kw):
+ try:
+ assertion(*args, **kw)
+ except self.failureException:
+ return
+ else:
+ raise self.failureException(
+ 'Failed: ' + self._call_repr(name, *args, **kw))
+
def _waitFor(self, assertion, *args, **kw):
start = time.time()
while True:
@@ -329,12 +362,18 @@
except self.failureException, e:
if time.time() - start > self.timeout:
raise self.failureException(
- 'Timed out waiting for: %s' % e.args[0])
+ 'Timed out. %s' % e.args[0])
else:
break
time.sleep(0.1)
+ def _call_repr(self, name, *args, **kw):
+ return '%s(%s)' % (
+ name,
+ ', '.join(map(repr, args) +
+ ['%s=%r' % item for item in sorted(kw.items())]))
+
def match_glob(text, pattern):
pattern = re.escape(pattern)
pattern = pattern.replace(r'\*', '.*')
Modified: gocept.selenium/trunk/src/gocept/selenium/ztk/tests/test_selenese.py
===================================================================
--- gocept.selenium/trunk/src/gocept/selenium/ztk/tests/test_selenese.py 2010-03-17 02:17:26 UTC (rev 110011)
+++ gocept.selenium/trunk/src/gocept/selenium/ztk/tests/test_selenese.py 2010-03-17 07:03:47 UTC (rev 110012)
@@ -14,6 +14,7 @@
from gocept.selenium.selenese import selenese_pattern_equals as match
from gocept.selenium.selenese import camelcase_to_underscore
+import gocept.selenium.selenese
import gocept.selenium.ztk.testing
import unittest
import time
@@ -54,6 +55,55 @@
self.assertEquals('foo_bar', camelcase_to_underscore('fooBar'))
+class NonexistentNameTest(unittest.TestCase):
+
+ def setUp(self):
+ class TestCase(object):
+ failureException = None
+
+ class Selenese(gocept.selenium.selenese.Selenese):
+ def get_without_assert_type(self):
+ pass
+ @gocept.selenium.selenese.assert_type('wrong_type')
+ def get_with_wrong_assert_type(self):
+ pass
+
+ self.selenese = Selenese(None, TestCase())
+
+ def assertError(self, error, name, expected_msg):
+ try:
+ getattr(self.selenese, name)
+ except error, e:
+ msg = e.args[0]
+ self.assertEquals(expected_msg, msg)
+
+ def assertAttributeError(self, name):
+ self.assertError(AttributeError, name, name)
+
+ def test_nonexistent_name(self):
+ self.assertAttributeError('a_nonexistent_name')
+ self.assertAttributeError('assert_a_nonexistent_name')
+
+ def test_waitfor_verify(self):
+ self.assertAttributeError('waitFor_a_nonexistent_name')
+ self.assertAttributeError('verify_a_nonexistent_name')
+
+ def test_not(self):
+ self.assertAttributeError('a_Notexistent_name')
+ self.assertAttributeError('assert_a_Notexistent_name')
+ self.assertAttributeError('waitFor_a_Notexistent_name')
+ self.assertAttributeError('verify_a_Notexistent_name')
+
+ def test_broken_assert_type(self):
+ self.assertError(AttributeError,
+ 'assert_without_assert_type',
+ "'function' object has no attribute 'assert_type'")
+ self.assertError(ValueError,
+ 'assert_with_wrong_assert_type',
+ "Unknown assert type 'wrong_type' for "
+ "selenese method 'assert_with_wrong_assert_type'.")
+
+
class AssertionTest(gocept.selenium.ztk.testing.TestCase):
def test_wait_for(self):
More information about the checkins
mailing list