Because -1 is a valid index in Python. Where possible, defaults should be chosen to avoid any possibility of confusion or mis-interpretation.
Six informative tests are:
Line 1 | Line 2 | Expected | Explanation |
"hello" |
"world" |
exception |
Make sure the function is sanity testing its inputs. |
[[0, 0], [0, 1]] |
[[1, 0], [1, 1]] |
None |
Lines do not overlap. |
[[0, 0], [1, 1]] |
[[0, 1], [1, 0]] |
[0.5, 0.5] |
Lines cross at one point. |
[[0, 0], [1, 1]] |
[[1, 1], [2, 2]] |
[1, 1] |
Lines cross at an endpoint. |
[[0, 0], [1, 0]] |
[[0, 0], [1, 0]] |
[[0, 0], [1, 0]] |
Lines lie exactly on top of each other. |
[[0, 0], [2, 0]] |
[[1, 0], [3, 0]] |
[[1, 0], [2, 0]] |
Lines partially overlap. |
I would want to test both single-letter and double-letter symbols for all 26 languages, which would be 52 tests. I would also want to test illegal symbols (non-string, empty string, more than two characters, and one or two letters that aren't a symbol) for at least one language (at least four more tests), and at least one valid symbol with the same kinds of illega country codes (another four tests), bringing the total to 60.
The first problem is that these tests are now tied to an
implementation detail of the function is_salt
. If
whoever wrote that function decides to change their implementation,
the tests could all break or (even worse) succeed for the wrong
reasons.
The second problem is that if the sets Acids
and
Bases
are not being initialized correctly, then
re-setting them for testing purposes will result in tests passing when
the function would fail in real-world use.
def test_non_list(): try: is_sorted("string") assert False except ValueError: pass except: assert False def test_non_integer(): try: is_sorted([1, []]) assert False except ValueError: pass except: assert False def test_empty(): assert is_sorted([]) def test_single(): assert is_sorted([33]) def test_pair_sorted(): assert is_sorted([22, 44]) def test_pair_reversed(): assert not is_sorted([44, 22]) def test_equal_values(): assert is_sorted([5, 5, 5, 5, 5]) def test_middle_mislocated(): assert not is_sorted([1, 2, 5, 3, 4]) def test_last_mislocated(): assert not is_sorted([1, 2, 3, 4, 0]) def test_long_ordered(): assert is_sorted([-100, -50, 2, 99, 173, 450, 172389])
The StringIO
and cStringIO
modules allow
programs to read from strings as if they were files. Programs can
also write to these objects as if they were files; if asked, the
objects will return the concatenation of all the data that has been
written to them as a string.
import cStringIO from file_util import count_lines def test_five_lines(): data = '''one two three four five ''' mock_file = cStringIO.StringIO(data) assert count_lines(mock_files) == 5
a) If limit
is negative, the function will count down
until current
becomes the most negative value that Python
can represent, at which point the program will fail.
b) The function "hangs", i.e., appears to be doing nothing.
c) One solution would be to break the loop into two pieces, i.e., to say:
if limit > 0: ...count down to zero as the function presently does... else: ...count up to zero instead...
Another possibility is to make the increment a variable:
if limit < 0: increment = 1 else: increment = -1 while current != 0: total += current current += increment
find_last
:
Variable | Role | Better name |
---|---|---|
v0 | stepper | current_index |
v1 | most-wanted holder | last_so_far |
v2 | fixed value | the_file |
v3 | stepper | line |
standard_deviation
:
v0 | accumulator | sum |
v1 | stepper | value |
v2 | temporary | average |
v3 | accumulator | std_sum |
v4 | stepper | value |
v5 | temporary | std_avg |
def process_file(filename): '''Read and print the contents of a file.''' try: f = open(filename, 'r') for line in f: line = line.strip() print line except: pass f.close()
a) What happens if one or both of prefix
and
pattern
do not occur in source
? What if the
only occurrence of pattern
occurs immediately after
prefix
?
b)
'''Return the index of the first occurrence of 'pattern' in 'source' that is NOT immediately after an occurrence of 'prefix'. If 'pattern' not in 'source', or only occurs immediately after an occurrence of 'prefix', raise a ValueError. If 'prefix' is the empty string, also raise a ValueError. For example, findButNotAfter('abcdcd', 'ab', 'cd') returns 4, since the first occurrence of 'cd' comes immediately after an 'ab', but findButNotAfter('abxcdcd', 'ab', 'cd') returns 3.'''
c)
import nose import find_but_not_after def test_empty_error(): try: res = find_but_not_after.findButNotAfter('', '', '') assert False, 'Empty prefix should cause an exception.' except ValueError: pass def test_one_empty_error(): try: res = find_but_not_after.findButNotAfter('a', '', 'a') assert False, 'Empty prefix should cause an exception.' except ValueError: pass def test_none_error(): try: res = find_but_not_after.findButNotAfter('ab', 'a', 'b') assert False, 'Should raise error: no occurrence without a prefix.' except ValueError: pass def test_after_error(): try: res = find_but_not_after.findButNotAfter('abcd', 'ab', 'cd') assert False, 'Should raise error: no occurrence without a prefix.' except ValueError: pass def test_one_same_okay(): res = find_but_not_after.findButNotAfter('a', 'a', 'a') assert res == 0, \ 'Prefix and pattern are the same, but this should be okay.' def test_same_letter_okay(): res = find_but_not_after.findButNotAfter('aa', 'a', 'a') assert res == 0, \ 'Prefix and pattern are the same, but this should be okay.' def test_prefix_after_no_error(): res = find_but_not_after.findButNotAfter('ab', 'b', 'a') assert res == 0, \ 'Prefix occurs after pattern, and this should be okay.' def test_prefix_but_no_error(): res = find_but_not_after.findButNotAfter('abxcd', 'ab', 'cd') assert res == 3, \ 'Prefix and pattern separated by another character.' def test_overlap(): res = find_but_not_after.findButNotAfter('abcd', 'ab', 'bc') assert res == 1, \ 'Prefix and pattern overlap, but that should be okay.' def test_second_occurrence(): res = find_but_not_after.findButNotAfter('xabab', 'x', 'ab') assert res == 3, \ 'Prefix and pattern appear together, but just the pattern afterwards.' def test_twice_no_prefix(): res = find_but_not_after.findButNotAfter('abab', 'x', 'ab') assert res == 0, \ 'Should have returned the first occurrence.'
d)
def findButNotAfter(source, prefix, pattern): '''Return the index of the first occurrence of 'pattern' in 'source' that is NOT immediately after an occurrence of 'prefix'. If 'pattern' not in 'source', or only occurs immediately after an occurrence of 'prefix', raise a ValueError. For example, findButNotAfter('abcdcd', 'ab', 'cd') returns 4, since the first occurrence of 'cd' comes immediately after an 'ab', but findButNotAfter('abxcdcd', 'ab', 'cd') returns 3.''' start = 0 result = -1 # Will be -1 until valid solution found. loc = source.find(pattern, start) while loc != -1 and result == -1: # Check whether prefix occurs immediately before. if source[loc - len(prefix) : loc] != prefix: result = loc else: start = loc + 1 loc = source.find(pattern, start) if result == -1: raise ValueError, 'Pattern not found in source' return result