1# Copyright 2017 The Abseil Authors.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Tests for absltest."""
16
17import collections
18import contextlib
19import dataclasses
20import io
21import os
22import pathlib
23import re
24import stat
25import string
26import subprocess
27import sys
28import tempfile
29import textwrap
30from typing import Optional
31import unittest
32
33from absl.testing import _bazelize_command
34from absl.testing import absltest
35from absl.testing import parameterized
36from absl.testing.tests import absltest_env
37
38
39class BaseTestCase(absltest.TestCase):
40
41  def _get_helper_exec_path(self, helper_name):
42    helper = 'absl/testing/tests/' + helper_name
43    return _bazelize_command.get_executable_path(helper)
44
45  def run_helper(
46      self,
47      test_id,
48      args,
49      env_overrides,
50      expect_success,
51      helper_name=None,
52  ):
53    env = absltest_env.inherited_env()
54    for key, value in env_overrides.items():
55      if value is None:
56        if key in env:
57          del env[key]
58      else:
59        env[key] = value
60
61    if helper_name is None:
62      helper_name = 'absltest_test_helper'
63    command = [self._get_helper_exec_path(helper_name)]
64    if test_id is not None:
65      command.append('--test_id={}'.format(test_id))
66    command.extend(args)
67    process = subprocess.Popen(
68        command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env,
69        universal_newlines=True)
70    stdout, stderr = process.communicate()
71    if expect_success:
72      self.assertEqual(
73          0,
74          process.returncode,
75          'Expected success, but failed with exit code {},'
76          ' stdout:\n{}\nstderr:\n{}\n'.format(
77              process.returncode, stdout, stderr
78          ),
79      )
80    else:
81      self.assertGreater(
82          process.returncode,
83          0,
84          'Expected failure, but succeeded with '
85          'stdout:\n{}\nstderr:\n{}\n'.format(stdout, stderr),
86      )
87    return stdout, stderr, process.returncode
88
89
90class TestCaseTest(BaseTestCase):
91  longMessage = True
92
93  def run_helper(
94      self, test_id, args, env_overrides, expect_success, helper_name=None
95  ):
96    return super(TestCaseTest, self).run_helper(
97        test_id,
98        args + ['HelperTest'],
99        env_overrides,
100        expect_success,
101        helper_name,
102    )
103
104  def test_flags_no_env_var_no_flags(self):
105    self.run_helper(
106        1,
107        [],
108        {'TEST_RANDOM_SEED': None,
109         'TEST_SRCDIR': None,
110         'TEST_TMPDIR': None,
111        },
112        expect_success=True)
113
114  def test_flags_env_var_no_flags(self):
115    tmpdir = tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value)
116    srcdir = tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value)
117    self.run_helper(
118        2,
119        [],
120        {'TEST_RANDOM_SEED': '321',
121         'TEST_SRCDIR': srcdir,
122         'TEST_TMPDIR': tmpdir,
123         'ABSLTEST_TEST_HELPER_EXPECTED_TEST_SRCDIR': srcdir,
124         'ABSLTEST_TEST_HELPER_EXPECTED_TEST_TMPDIR': tmpdir,
125        },
126        expect_success=True)
127
128  def test_flags_no_env_var_flags(self):
129    tmpdir = tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value)
130    srcdir = tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value)
131    self.run_helper(
132        3,
133        ['--test_random_seed=123', '--test_srcdir={}'.format(srcdir),
134         '--test_tmpdir={}'.format(tmpdir)],
135        {'TEST_RANDOM_SEED': None,
136         'TEST_SRCDIR': None,
137         'TEST_TMPDIR': None,
138         'ABSLTEST_TEST_HELPER_EXPECTED_TEST_SRCDIR': srcdir,
139         'ABSLTEST_TEST_HELPER_EXPECTED_TEST_TMPDIR': tmpdir,
140        },
141        expect_success=True)
142
143  def test_flags_env_var_flags(self):
144    tmpdir_from_flag = tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value)
145    srcdir_from_flag = tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value)
146    tmpdir_from_env_var = tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value)
147    srcdir_from_env_var = tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value)
148    self.run_helper(
149        4,
150        ['--test_random_seed=221', '--test_srcdir={}'.format(srcdir_from_flag),
151         '--test_tmpdir={}'.format(tmpdir_from_flag)],
152        {'TEST_RANDOM_SEED': '123',
153         'TEST_SRCDIR': srcdir_from_env_var,
154         'TEST_TMPDIR': tmpdir_from_env_var,
155         'ABSLTEST_TEST_HELPER_EXPECTED_TEST_SRCDIR': srcdir_from_flag,
156         'ABSLTEST_TEST_HELPER_EXPECTED_TEST_TMPDIR': tmpdir_from_flag,
157        },
158        expect_success=True)
159
160  def test_xml_output_file_from_xml_output_file_env(self):
161    xml_dir = tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value)
162    xml_output_file_env = os.path.join(xml_dir, 'xml_output_file.xml')
163    random_dir = tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value)
164    self.run_helper(
165        6,
166        [],
167        {'XML_OUTPUT_FILE': xml_output_file_env,
168         'RUNNING_UNDER_TEST_DAEMON': '1',
169         'TEST_XMLOUTPUTDIR': random_dir,
170         'ABSLTEST_TEST_HELPER_EXPECTED_XML_OUTPUT_FILE': xml_output_file_env,
171        },
172        expect_success=True)
173
174  def test_xml_output_file_from_daemon(self):
175    tmpdir = os.path.join(tempfile.mkdtemp(
176        dir=absltest.TEST_TMPDIR.value), 'sub_dir')
177    random_dir = tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value)
178    self.run_helper(
179        6,
180        ['--test_tmpdir', tmpdir],
181        {'XML_OUTPUT_FILE': None,
182         'RUNNING_UNDER_TEST_DAEMON': '1',
183         'TEST_XMLOUTPUTDIR': random_dir,
184         'ABSLTEST_TEST_HELPER_EXPECTED_XML_OUTPUT_FILE': os.path.join(
185             os.path.dirname(tmpdir), 'test_detail.xml'),
186        },
187        expect_success=True)
188
189  def test_xml_output_file_from_test_xmloutputdir_env(self):
190    xml_output_dir = tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value)
191    expected_xml_file = 'absltest_test_helper.xml'
192    self.run_helper(
193        6,
194        [],
195        {'XML_OUTPUT_FILE': None,
196         'RUNNING_UNDER_TEST_DAEMON': None,
197         'TEST_XMLOUTPUTDIR': xml_output_dir,
198         'ABSLTEST_TEST_HELPER_EXPECTED_XML_OUTPUT_FILE': os.path.join(
199             xml_output_dir, expected_xml_file),
200        },
201        expect_success=True)
202
203  def test_xml_output_file_from_flag(self):
204    random_dir = tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value)
205    flag_file = os.path.join(
206        tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value), 'output.xml')
207    self.run_helper(
208        6,
209        ['--xml_output_file', flag_file],
210        {'XML_OUTPUT_FILE': os.path.join(random_dir, 'output.xml'),
211         'RUNNING_UNDER_TEST_DAEMON': '1',
212         'TEST_XMLOUTPUTDIR': random_dir,
213         'ABSLTEST_TEST_HELPER_EXPECTED_XML_OUTPUT_FILE': flag_file,
214        },
215        expect_success=True)
216
217  def test_app_run(self):
218    stdout, _, _ = self.run_helper(
219        7,
220        ['--name=cat', '--name=dog'],
221        {'ABSLTEST_TEST_HELPER_USE_APP_RUN': '1'},
222        expect_success=True,
223    )
224    self.assertIn('Names in main() are: cat dog', stdout)
225    self.assertIn('Names in test_name_flag() are: cat dog', stdout)
226
227  def test_assert_in(self):
228    animals = {'monkey': 'banana', 'cow': 'grass', 'seal': 'fish'}
229
230    self.assertIn('a', 'abc')
231    self.assertIn(2, [1, 2, 3])
232    self.assertIn('monkey', animals)
233
234    self.assertNotIn('d', 'abc')
235    self.assertNotIn(0, [1, 2, 3])
236    self.assertNotIn('otter', animals)
237
238    self.assertRaises(AssertionError, self.assertIn, 'x', 'abc')
239    self.assertRaises(AssertionError, self.assertIn, 4, [1, 2, 3])
240    self.assertRaises(AssertionError, self.assertIn, 'elephant', animals)
241
242    self.assertRaises(AssertionError, self.assertNotIn, 'c', 'abc')
243    self.assertRaises(AssertionError, self.assertNotIn, 1, [1, 2, 3])
244    self.assertRaises(AssertionError, self.assertNotIn, 'cow', animals)
245
246  @absltest.expectedFailure
247  def test_expected_failure(self):
248    self.assertEqual(1, 2)  # the expected failure
249
250  @absltest.expectedFailureIf(True, 'always true')
251  def test_expected_failure_if(self):
252    self.assertEqual(1, 2)  # the expected failure
253
254  def test_expected_failure_success(self):
255    _, stderr, _ = self.run_helper(5, ['--', '-v'], {}, expect_success=False)
256    self.assertRegex(stderr, r'FAILED \(.*unexpected successes=1\)')
257
258  def test_assert_equal(self):
259    self.assertListEqual([], [])
260    self.assertTupleEqual((), ())
261    self.assertSequenceEqual([], ())
262
263    a = [0, 'a', []]
264    b = []
265    self.assertRaises(absltest.TestCase.failureException,
266                      self.assertListEqual, a, b)
267    self.assertRaises(absltest.TestCase.failureException,
268                      self.assertListEqual, tuple(a), tuple(b))
269    self.assertRaises(absltest.TestCase.failureException,
270                      self.assertSequenceEqual, a, tuple(b))
271
272    b.extend(a)
273    self.assertListEqual(a, b)
274    self.assertTupleEqual(tuple(a), tuple(b))
275    self.assertSequenceEqual(a, tuple(b))
276    self.assertSequenceEqual(tuple(a), b)
277
278    self.assertRaises(AssertionError, self.assertListEqual, a, tuple(b))
279    self.assertRaises(AssertionError, self.assertTupleEqual, tuple(a), b)
280    self.assertRaises(AssertionError, self.assertListEqual, None, b)
281    self.assertRaises(AssertionError, self.assertTupleEqual, None, tuple(b))
282    self.assertRaises(AssertionError, self.assertSequenceEqual, None, tuple(b))
283    self.assertRaises(AssertionError, self.assertListEqual, 1, 1)
284    self.assertRaises(AssertionError, self.assertTupleEqual, 1, 1)
285    self.assertRaises(AssertionError, self.assertSequenceEqual, 1, 1)
286
287    self.assertSameElements([1, 2, 3], [3, 2, 1])
288    self.assertSameElements([1, 2] + [3] * 100, [1] * 100 + [2, 3])
289    self.assertSameElements(['foo', 'bar', 'baz'], ['bar', 'baz', 'foo'])
290    self.assertRaises(AssertionError, self.assertSameElements, [10], [10, 11])
291    self.assertRaises(AssertionError, self.assertSameElements, [10, 11], [10])
292
293    # Test that sequences of unhashable objects can be tested for sameness:
294    self.assertSameElements([[1, 2], [3, 4]], [[3, 4], [1, 2]])
295    self.assertRaises(AssertionError, self.assertSameElements, [[1]], [[2]])
296
297  def test_assert_items_equal_hotfix(self):
298    """Confirm that http://bugs.python.org/issue14832 - b/10038517 is gone."""
299    for assert_items_method in (self.assertItemsEqual, self.assertCountEqual):
300      with self.assertRaises(self.failureException) as error_context:
301        assert_items_method([4], [2])
302      error_message = str(error_context.exception)
303      # Confirm that the bug is either no longer present in Python or that our
304      # assertItemsEqual patching version of the method in absltest.TestCase
305      # doesn't get used.
306      self.assertIn('First has 1, Second has 0:  4', error_message)
307      self.assertIn('First has 0, Second has 1:  2', error_message)
308
309  def test_assert_dict_equal(self):
310    self.assertDictEqual({}, {})
311
312    c = {'x': 1}
313    d = {}
314    self.assertRaises(absltest.TestCase.failureException,
315                      self.assertDictEqual, c, d)
316
317    d.update(c)
318    self.assertDictEqual(c, d)
319
320    d['x'] = 0
321    self.assertRaises(absltest.TestCase.failureException,
322                      self.assertDictEqual, c, d, 'These are unequal')
323
324    self.assertRaises(AssertionError, self.assertDictEqual, None, d)
325    self.assertRaises(AssertionError, self.assertDictEqual, [], d)
326    self.assertRaises(AssertionError, self.assertDictEqual, 1, 1)
327
328    try:
329      # Ensure we use equality as the sole measure of elements, not type, since
330      # that is consistent with dict equality.
331      self.assertDictEqual({1: 1.0, 2: 2}, {1: 1, 2: 3})
332    except AssertionError as e:
333      self.assertMultiLineEqual('{1: 1.0, 2: 2} != {1: 1, 2: 3}\n'
334                                'repr() of differing entries:\n2: 2 != 3\n',
335                                str(e))
336
337    try:
338      self.assertDictEqual({}, {'x': 1})
339    except AssertionError as e:
340      self.assertMultiLineEqual("{} != {'x': 1}\n"
341                                "Unexpected, but present entries:\n'x': 1\n",
342                                str(e))
343    else:
344      self.fail('Expecting AssertionError')
345
346    try:
347      self.assertDictEqual({}, {'x': 1}, 'a message')
348    except AssertionError as e:
349      self.assertIn('a message', str(e))
350    else:
351      self.fail('Expecting AssertionError')
352
353    expected = {'a': 1, 'b': 2, 'c': 3}
354    seen = {'a': 2, 'c': 3, 'd': 4}
355    try:
356      self.assertDictEqual(expected, seen)
357    except AssertionError as e:
358      self.assertMultiLineEqual("""\
359{'a': 1, 'b': 2, 'c': 3} != {'a': 2, 'c': 3, 'd': 4}
360Unexpected, but present entries:
361'd': 4
362
363repr() of differing entries:
364'a': 1 != 2
365
366Missing entries:
367'b': 2
368""", str(e))
369    else:
370      self.fail('Expecting AssertionError')
371
372    self.assertRaises(AssertionError, self.assertDictEqual, (1, 2), {})
373    self.assertRaises(AssertionError, self.assertDictEqual, {}, (1, 2))
374
375    # Ensure deterministic output of keys in dictionaries whose sort order
376    # doesn't match the lexical ordering of repr -- this is most Python objects,
377    # which are keyed by memory address.
378    class Obj(object):
379
380      def __init__(self, name):
381        self.name = name
382
383      def __repr__(self):
384        return self.name
385
386    try:
387      self.assertDictEqual(
388          {'a': Obj('A'), Obj('b'): Obj('B'), Obj('c'): Obj('C')},
389          {'a': Obj('A'), Obj('d'): Obj('D'), Obj('e'): Obj('E')})
390    except AssertionError as e:
391      # Do as best we can not to be misleading when objects have the same repr
392      # but aren't equal.
393      err_str = str(e)
394      self.assertStartsWith(err_str,
395                            "{'a': A, b: B, c: C} != {'a': A, d: D, e: E}\n")
396      self.assertRegex(
397          err_str, r'(?ms).*^Unexpected, but present entries:\s+'
398          r'^(d: D$\s+^e: E|e: E$\s+^d: D)$')
399      self.assertRegex(
400          err_str, r'(?ms).*^repr\(\) of differing entries:\s+'
401          r'^.a.: A != A$', err_str)
402      self.assertRegex(
403          err_str, r'(?ms).*^Missing entries:\s+'
404          r'^(b: B$\s+^c: C|c: C$\s+^b: B)$')
405    else:
406      self.fail('Expecting AssertionError')
407
408    # Confirm that safe_repr, not repr, is being used.
409    class RaisesOnRepr(object):
410
411      def __repr__(self):
412        return 1/0  # Intentionally broken __repr__ implementation.
413
414    try:
415      self.assertDictEqual(
416          {RaisesOnRepr(): RaisesOnRepr()},
417          {RaisesOnRepr(): RaisesOnRepr()}
418          )
419      self.fail('Expected dicts not to match')
420    except AssertionError as e:
421      # Depending on the testing environment, the object may get a __main__
422      # prefix or a absltest_test prefix, so strip that for comparison.
423      error_msg = re.sub(
424          r'( at 0x[^>]+)|__main__\.|absltest_test\.', '', str(e))
425      self.assertRegex(error_msg, """(?m)\
426{<.*RaisesOnRepr object.*>: <.*RaisesOnRepr object.*>} != \
427{<.*RaisesOnRepr object.*>: <.*RaisesOnRepr object.*>}
428Unexpected, but present entries:
429<.*RaisesOnRepr object.*>: <.*RaisesOnRepr object.*>
430
431Missing entries:
432<.*RaisesOnRepr object.*>: <.*RaisesOnRepr object.*>
433""")
434
435    # Confirm that safe_repr, not repr, is being used.
436    class RaisesOnLt(object):
437
438      def __lt__(self, unused_other):
439        raise TypeError('Object is unordered.')
440
441      def __repr__(self):
442        return '<RaisesOnLt object>'
443
444    try:
445      self.assertDictEqual(
446          {RaisesOnLt(): RaisesOnLt()},
447          {RaisesOnLt(): RaisesOnLt()})
448    except AssertionError as e:
449      self.assertIn('Unexpected, but present entries:\n<RaisesOnLt', str(e))
450      self.assertIn('Missing entries:\n<RaisesOnLt', str(e))
451
452  def test_assert_set_equal(self):
453    set1 = set()
454    set2 = set()
455    self.assertSetEqual(set1, set2)
456
457    self.assertRaises(AssertionError, self.assertSetEqual, None, set2)
458    self.assertRaises(AssertionError, self.assertSetEqual, [], set2)
459    self.assertRaises(AssertionError, self.assertSetEqual, set1, None)
460    self.assertRaises(AssertionError, self.assertSetEqual, set1, [])
461
462    set1 = set(['a'])
463    set2 = set()
464    self.assertRaises(AssertionError, self.assertSetEqual, set1, set2)
465
466    set1 = set(['a'])
467    set2 = set(['a'])
468    self.assertSetEqual(set1, set2)
469
470    set1 = set(['a'])
471    set2 = set(['a', 'b'])
472    self.assertRaises(AssertionError, self.assertSetEqual, set1, set2)
473
474    set1 = set(['a'])
475    set2 = frozenset(['a', 'b'])
476    self.assertRaises(AssertionError, self.assertSetEqual, set1, set2)
477
478    set1 = set(['a', 'b'])
479    set2 = frozenset(['a', 'b'])
480    self.assertSetEqual(set1, set2)
481
482    set1 = set()
483    set2 = 'foo'
484    self.assertRaises(AssertionError, self.assertSetEqual, set1, set2)
485    self.assertRaises(AssertionError, self.assertSetEqual, set2, set1)
486
487    # make sure any string formatting is tuple-safe
488    set1 = set([(0, 1), (2, 3)])
489    set2 = set([(4, 5)])
490    self.assertRaises(AssertionError, self.assertSetEqual, set1, set2)
491
492  def test_assert_sequence_almost_equal(self):
493    actual = (1.1, 1.2, 1.4)
494
495    # Test across sequence types.
496    self.assertSequenceAlmostEqual((1.1, 1.2, 1.4), actual)
497    self.assertSequenceAlmostEqual([1.1, 1.2, 1.4], actual)
498
499    # Test sequence size mismatch.
500    with self.assertRaises(AssertionError):
501      self.assertSequenceAlmostEqual([1.1, 1.2], actual)
502    with self.assertRaises(AssertionError):
503      self.assertSequenceAlmostEqual([1.1, 1.2, 1.4, 1.5], actual)
504
505    # Test delta.
506    with self.assertRaises(AssertionError):
507      self.assertSequenceAlmostEqual((1.15, 1.15, 1.4), actual)
508    self.assertSequenceAlmostEqual((1.15, 1.15, 1.4), actual, delta=0.1)
509
510    # Test places.
511    with self.assertRaises(AssertionError):
512      self.assertSequenceAlmostEqual((1.1001, 1.2001, 1.3999), actual)
513    self.assertSequenceAlmostEqual((1.1001, 1.2001, 1.3999), actual, places=3)
514
515  def test_assert_contains_subset(self):
516    # sets, lists, tuples, dicts all ok.  Types of set and subset do not have to
517    # match.
518    actual = ('a', 'b', 'c')
519    self.assertContainsSubset({'a', 'b'}, actual)
520    self.assertContainsSubset(('b', 'c'), actual)
521    self.assertContainsSubset({'b': 1, 'c': 2}, list(actual))
522    self.assertContainsSubset(['c', 'a'], set(actual))
523    self.assertContainsSubset([], set())
524    self.assertContainsSubset([], {'a': 1})
525
526    self.assertRaises(AssertionError, self.assertContainsSubset, ('d',), actual)
527    self.assertRaises(AssertionError, self.assertContainsSubset, ['d'],
528                      set(actual))
529    self.assertRaises(AssertionError, self.assertContainsSubset, {'a': 1}, [])
530
531    with self.assertRaisesRegex(AssertionError, 'Missing elements'):
532      self.assertContainsSubset({1, 2, 3}, {1, 2})
533
534    with self.assertRaisesRegex(
535        AssertionError,
536        re.compile('Missing elements .* Custom message', re.DOTALL)):
537      self.assertContainsSubset({1, 2}, {1}, 'Custom message')
538
539  def test_assert_no_common_elements(self):
540    actual = ('a', 'b', 'c')
541    self.assertNoCommonElements((), actual)
542    self.assertNoCommonElements(('d', 'e'), actual)
543    self.assertNoCommonElements({'d', 'e'}, actual)
544
545    with self.assertRaisesRegex(
546        AssertionError,
547        re.compile('Common elements .* Custom message', re.DOTALL)):
548      self.assertNoCommonElements({1, 2}, {1}, 'Custom message')
549
550    with self.assertRaises(AssertionError):
551      self.assertNoCommonElements(['a'], actual)
552
553    with self.assertRaises(AssertionError):
554      self.assertNoCommonElements({'a', 'b', 'c'}, actual)
555
556    with self.assertRaises(AssertionError):
557      self.assertNoCommonElements({'b', 'c'}, set(actual))
558
559  def test_assert_almost_equal(self):
560    self.assertAlmostEqual(1.00000001, 1.0)
561    self.assertNotAlmostEqual(1.0000001, 1.0)
562
563  def test_assert_almost_equals_with_delta(self):
564    self.assertAlmostEqual(3.14, 3, delta=0.2)
565    self.assertAlmostEqual(2.81, 3.14, delta=1)
566    self.assertAlmostEqual(-1, 1, delta=3)
567    self.assertRaises(AssertionError, self.assertAlmostEqual,
568                      3.14, 2.81, delta=0.1)
569    self.assertRaises(AssertionError, self.assertAlmostEqual,
570                      1, 2, delta=0.5)
571    self.assertNotAlmostEqual(3.14, 2.81, delta=0.1)
572
573  def test_assert_starts_with(self):
574    self.assertStartsWith('foobar', 'foo')
575    self.assertStartsWith('foobar', 'foobar')
576    msg = 'This is a useful message'
577    whole_msg = "'foobar' does not start with 'bar' : This is a useful message"
578    self.assertRaisesWithLiteralMatch(AssertionError, whole_msg,
579                                      self.assertStartsWith,
580                                      'foobar', 'bar', msg)
581    self.assertRaises(AssertionError, self.assertStartsWith, 'foobar', 'blah')
582
583  def test_assert_not_starts_with(self):
584    self.assertNotStartsWith('foobar', 'bar')
585    self.assertNotStartsWith('foobar', 'blah')
586    msg = 'This is a useful message'
587    whole_msg = "'foobar' does start with 'foo' : This is a useful message"
588    self.assertRaisesWithLiteralMatch(AssertionError, whole_msg,
589                                      self.assertNotStartsWith,
590                                      'foobar', 'foo', msg)
591    self.assertRaises(AssertionError, self.assertNotStartsWith, 'foobar',
592                      'foobar')
593
594  def test_assert_ends_with(self):
595    self.assertEndsWith('foobar', 'bar')
596    self.assertEndsWith('foobar', 'foobar')
597    msg = 'This is a useful message'
598    whole_msg = "'foobar' does not end with 'foo' : This is a useful message"
599    self.assertRaisesWithLiteralMatch(AssertionError, whole_msg,
600                                      self.assertEndsWith,
601                                      'foobar', 'foo', msg)
602    self.assertRaises(AssertionError, self.assertEndsWith, 'foobar', 'blah')
603
604  def test_assert_not_ends_with(self):
605    self.assertNotEndsWith('foobar', 'foo')
606    self.assertNotEndsWith('foobar', 'blah')
607    msg = 'This is a useful message'
608    whole_msg = "'foobar' does end with 'bar' : This is a useful message"
609    self.assertRaisesWithLiteralMatch(AssertionError, whole_msg,
610                                      self.assertNotEndsWith,
611                                      'foobar', 'bar', msg)
612    self.assertRaises(AssertionError, self.assertNotEndsWith, 'foobar',
613                      'foobar')
614
615  def test_assert_regex_backports(self):
616    self.assertRegex('regex', 'regex')
617    self.assertNotRegex('not-regex', 'no-match')
618    with self.assertRaisesRegex(ValueError, 'pattern'):
619      raise ValueError('pattern')
620
621  def test_assert_regex_match_matches(self):
622    self.assertRegexMatch('str', ['str'])
623
624  def test_assert_regex_match_matches_substring(self):
625    self.assertRegexMatch('pre-str-post', ['str'])
626
627  def test_assert_regex_match_multiple_regex_matches(self):
628    self.assertRegexMatch('str', ['rts', 'str'])
629
630  def test_assert_regex_match_empty_list_fails(self):
631    expected_re = re.compile(r'No regexes specified\.', re.MULTILINE)
632
633    with self.assertRaisesRegex(AssertionError, expected_re):
634      self.assertRegexMatch('str', regexes=[])
635
636  def test_assert_regex_match_bad_arguments(self):
637    with self.assertRaisesRegex(AssertionError,
638                                'regexes is string or bytes;.*'):
639      self.assertRegexMatch('1.*2', '1 2')
640
641  def test_assert_regex_match_unicode_vs_bytes(self):
642    """Ensure proper utf-8 encoding or decoding happens automatically."""
643    self.assertRegexMatch(u'str', [b'str'])
644    self.assertRegexMatch(b'str', [u'str'])
645
646  def test_assert_regex_match_unicode(self):
647    self.assertRegexMatch(u'foo str', [u'str'])
648
649  def test_assert_regex_match_bytes(self):
650    self.assertRegexMatch(b'foo str', [b'str'])
651
652  def test_assert_regex_match_all_the_same_type(self):
653    with self.assertRaisesRegex(AssertionError, 'regexes .* same type'):
654      self.assertRegexMatch('foo str', [b'str', u'foo'])
655
656  def test_assert_command_fails_stderr(self):
657    tmpdir = tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value)
658    self.assertCommandFails(
659        ['cat', os.path.join(tmpdir, 'file.txt')],
660        ['No such file or directory'],
661        env=_env_for_command_tests())
662
663  def test_assert_command_fails_with_list_of_string(self):
664    self.assertCommandFails(
665        ['false'], [''], env=_env_for_command_tests())
666
667  def test_assert_command_fails_with_list_of_unicode_string(self):
668    self.assertCommandFails(
669        [u'false'], [''], env=_env_for_command_tests())
670
671  def test_assert_command_fails_with_unicode_string(self):
672    self.assertCommandFails(
673        u'false', [u''], env=_env_for_command_tests())
674
675  def test_assert_command_fails_with_unicode_string_bytes_regex(self):
676    self.assertCommandFails(
677        u'false', [b''], env=_env_for_command_tests())
678
679  def test_assert_command_fails_with_message(self):
680    msg = 'This is a useful message'
681    expected_re = re.compile('The following command succeeded while expected to'
682                             ' fail:.* This is a useful message', re.DOTALL)
683
684    with self.assertRaisesRegex(AssertionError, expected_re):
685      self.assertCommandFails(
686          [u'true'], [''], msg=msg, env=_env_for_command_tests())
687
688  def test_assert_command_succeeds_stderr(self):
689    expected_re = re.compile('No such file or directory')
690    tmpdir = tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value)
691
692    with self.assertRaisesRegex(AssertionError, expected_re):
693      self.assertCommandSucceeds(
694          ['cat', os.path.join(tmpdir, 'file.txt')],
695          env=_env_for_command_tests())
696
697  def test_assert_command_succeeds_with_matching_unicode_regexes(self):
698    self.assertCommandSucceeds(
699        ['echo', 'SUCCESS'], regexes=[u'SUCCESS'],
700        env=_env_for_command_tests())
701
702  def test_assert_command_succeeds_with_matching_bytes_regexes(self):
703    self.assertCommandSucceeds(
704        ['echo', 'SUCCESS'], regexes=[b'SUCCESS'],
705        env=_env_for_command_tests())
706
707  def test_assert_command_succeeds_with_non_matching_regexes(self):
708    expected_re = re.compile('Running command.* This is a useful message',
709                             re.DOTALL)
710    msg = 'This is a useful message'
711
712    with self.assertRaisesRegex(AssertionError, expected_re):
713      self.assertCommandSucceeds(
714          ['echo', 'FAIL'], regexes=['SUCCESS'], msg=msg,
715          env=_env_for_command_tests())
716
717  def test_assert_command_succeeds_with_list_of_string(self):
718    self.assertCommandSucceeds(
719        ['true'], env=_env_for_command_tests())
720
721  def test_assert_command_succeeds_with_list_of_unicode_string(self):
722    self.assertCommandSucceeds(
723        [u'true'], env=_env_for_command_tests())
724
725  def test_assert_command_succeeds_with_unicode_string(self):
726    self.assertCommandSucceeds(
727        u'true', env=_env_for_command_tests())
728
729  def test_inequality(self):
730    # Try ints
731    self.assertGreater(2, 1)
732    self.assertGreaterEqual(2, 1)
733    self.assertGreaterEqual(1, 1)
734    self.assertLess(1, 2)
735    self.assertLessEqual(1, 2)
736    self.assertLessEqual(1, 1)
737    self.assertRaises(AssertionError, self.assertGreater, 1, 2)
738    self.assertRaises(AssertionError, self.assertGreater, 1, 1)
739    self.assertRaises(AssertionError, self.assertGreaterEqual, 1, 2)
740    self.assertRaises(AssertionError, self.assertLess, 2, 1)
741    self.assertRaises(AssertionError, self.assertLess, 1, 1)
742    self.assertRaises(AssertionError, self.assertLessEqual, 2, 1)
743
744    # Try Floats
745    self.assertGreater(1.1, 1.0)
746    self.assertGreaterEqual(1.1, 1.0)
747    self.assertGreaterEqual(1.0, 1.0)
748    self.assertLess(1.0, 1.1)
749    self.assertLessEqual(1.0, 1.1)
750    self.assertLessEqual(1.0, 1.0)
751    self.assertRaises(AssertionError, self.assertGreater, 1.0, 1.1)
752    self.assertRaises(AssertionError, self.assertGreater, 1.0, 1.0)
753    self.assertRaises(AssertionError, self.assertGreaterEqual, 1.0, 1.1)
754    self.assertRaises(AssertionError, self.assertLess, 1.1, 1.0)
755    self.assertRaises(AssertionError, self.assertLess, 1.0, 1.0)
756    self.assertRaises(AssertionError, self.assertLessEqual, 1.1, 1.0)
757
758    # Try Strings
759    self.assertGreater('bug', 'ant')
760    self.assertGreaterEqual('bug', 'ant')
761    self.assertGreaterEqual('ant', 'ant')
762    self.assertLess('ant', 'bug')
763    self.assertLessEqual('ant', 'bug')
764    self.assertLessEqual('ant', 'ant')
765    self.assertRaises(AssertionError, self.assertGreater, 'ant', 'bug')
766    self.assertRaises(AssertionError, self.assertGreater, 'ant', 'ant')
767    self.assertRaises(AssertionError, self.assertGreaterEqual, 'ant', 'bug')
768    self.assertRaises(AssertionError, self.assertLess, 'bug', 'ant')
769    self.assertRaises(AssertionError, self.assertLess, 'ant', 'ant')
770    self.assertRaises(AssertionError, self.assertLessEqual, 'bug', 'ant')
771
772    # Try Unicode
773    self.assertGreater(u'bug', u'ant')
774    self.assertGreaterEqual(u'bug', u'ant')
775    self.assertGreaterEqual(u'ant', u'ant')
776    self.assertLess(u'ant', u'bug')
777    self.assertLessEqual(u'ant', u'bug')
778    self.assertLessEqual(u'ant', u'ant')
779    self.assertRaises(AssertionError, self.assertGreater, u'ant', u'bug')
780    self.assertRaises(AssertionError, self.assertGreater, u'ant', u'ant')
781    self.assertRaises(AssertionError, self.assertGreaterEqual, u'ant', u'bug')
782    self.assertRaises(AssertionError, self.assertLess, u'bug', u'ant')
783    self.assertRaises(AssertionError, self.assertLess, u'ant', u'ant')
784    self.assertRaises(AssertionError, self.assertLessEqual, u'bug', u'ant')
785
786    # Try Mixed String/Unicode
787    self.assertGreater('bug', u'ant')
788    self.assertGreater(u'bug', 'ant')
789    self.assertGreaterEqual('bug', u'ant')
790    self.assertGreaterEqual(u'bug', 'ant')
791    self.assertGreaterEqual('ant', u'ant')
792    self.assertGreaterEqual(u'ant', 'ant')
793    self.assertLess('ant', u'bug')
794    self.assertLess(u'ant', 'bug')
795    self.assertLessEqual('ant', u'bug')
796    self.assertLessEqual(u'ant', 'bug')
797    self.assertLessEqual('ant', u'ant')
798    self.assertLessEqual(u'ant', 'ant')
799    self.assertRaises(AssertionError, self.assertGreater, 'ant', u'bug')
800    self.assertRaises(AssertionError, self.assertGreater, u'ant', 'bug')
801    self.assertRaises(AssertionError, self.assertGreater, 'ant', u'ant')
802    self.assertRaises(AssertionError, self.assertGreater, u'ant', 'ant')
803    self.assertRaises(AssertionError, self.assertGreaterEqual, 'ant', u'bug')
804    self.assertRaises(AssertionError, self.assertGreaterEqual, u'ant', 'bug')
805    self.assertRaises(AssertionError, self.assertLess, 'bug', u'ant')
806    self.assertRaises(AssertionError, self.assertLess, u'bug', 'ant')
807    self.assertRaises(AssertionError, self.assertLess, 'ant', u'ant')
808    self.assertRaises(AssertionError, self.assertLess, u'ant', 'ant')
809    self.assertRaises(AssertionError, self.assertLessEqual, 'bug', u'ant')
810    self.assertRaises(AssertionError, self.assertLessEqual, u'bug', 'ant')
811
812  def test_assert_multi_line_equal(self):
813    sample_text = """\
814http://www.python.org/doc/2.3/lib/module-unittest.html
815test case
816    A test case is the smallest unit of testing. [...]
817"""
818    revised_sample_text = """\
819http://www.python.org/doc/2.4.1/lib/module-unittest.html
820test case
821    A test case is the smallest unit of testing. [...] You may provide your
822    own implementation that does not subclass from TestCase, of course.
823"""
824    sample_text_error = """
825- http://www.python.org/doc/2.3/lib/module-unittest.html
826?                             ^
827+ http://www.python.org/doc/2.4.1/lib/module-unittest.html
828?                             ^^^
829  test case
830-     A test case is the smallest unit of testing. [...]
831+     A test case is the smallest unit of testing. [...] You may provide your
832?                                                       +++++++++++++++++++++
833+     own implementation that does not subclass from TestCase, of course.
834"""
835    self.assertRaisesWithLiteralMatch(AssertionError, sample_text_error,
836                                      self.assertMultiLineEqual,
837                                      sample_text,
838                                      revised_sample_text)
839
840    self.assertRaises(AssertionError, self.assertMultiLineEqual, (1, 2), 'str')
841    self.assertRaises(AssertionError, self.assertMultiLineEqual, 'str', (1, 2))
842
843  def test_assert_multi_line_equal_adds_newlines_if_needed(self):
844    self.assertRaisesWithLiteralMatch(
845        AssertionError,
846        '\n'
847        '  line1\n'
848        '- line2\n'
849        '?     ^\n'
850        '+ line3\n'
851        '?     ^\n',
852        self.assertMultiLineEqual,
853        'line1\n'
854        'line2',
855        'line1\n'
856        'line3')
857
858  def test_assert_multi_line_equal_shows_missing_newlines(self):
859    self.assertRaisesWithLiteralMatch(
860        AssertionError,
861        '\n'
862        '  line1\n'
863        '- line2\n'
864        '?      -\n'
865        '+ line2\n',
866        self.assertMultiLineEqual,
867        'line1\n'
868        'line2\n',
869        'line1\n'
870        'line2')
871
872  def test_assert_multi_line_equal_shows_extra_newlines(self):
873    self.assertRaisesWithLiteralMatch(
874        AssertionError,
875        '\n'
876        '  line1\n'
877        '- line2\n'
878        '+ line2\n'
879        '?      +\n',
880        self.assertMultiLineEqual,
881        'line1\n'
882        'line2',
883        'line1\n'
884        'line2\n')
885
886  def test_assert_multi_line_equal_line_limit_limits(self):
887    self.assertRaisesWithLiteralMatch(
888        AssertionError,
889        '\n'
890        '  line1\n'
891        '(... and 4 more delta lines omitted for brevity.)\n',
892        self.assertMultiLineEqual,
893        'line1\n'
894        'line2\n',
895        'line1\n'
896        'line3\n',
897        line_limit=1)
898
899  def test_assert_multi_line_equal_line_limit_limits_with_message(self):
900    self.assertRaisesWithLiteralMatch(
901        AssertionError,
902        'Prefix:\n'
903        '  line1\n'
904        '(... and 4 more delta lines omitted for brevity.)\n',
905        self.assertMultiLineEqual,
906        'line1\n'
907        'line2\n',
908        'line1\n'
909        'line3\n',
910        'Prefix',
911        line_limit=1)
912
913  def test_assert_is_none(self):
914    self.assertIsNone(None)
915    self.assertRaises(AssertionError, self.assertIsNone, False)
916    self.assertIsNotNone('Google')
917    self.assertRaises(AssertionError, self.assertIsNotNone, None)
918    self.assertRaises(AssertionError, self.assertIsNone, (1, 2))
919
920  def test_assert_is(self):
921    self.assertIs(object, object)
922    self.assertRaises(AssertionError, self.assertIsNot, object, object)
923    self.assertIsNot(True, False)
924    self.assertRaises(AssertionError, self.assertIs, True, False)
925
926  def test_assert_between(self):
927    self.assertBetween(3.14, 3.1, 3.141)
928    self.assertBetween(4, 4, 1e10000)
929    self.assertBetween(9.5, 9.4, 9.5)
930    self.assertBetween(-1e10, -1e10000, 0)
931    self.assertRaises(AssertionError, self.assertBetween, 9.4, 9.3, 9.3999)
932    self.assertRaises(AssertionError, self.assertBetween, -1e10000, -1e10, 0)
933
934  def test_assert_raises_with_predicate_match_no_raise(self):
935    with self.assertRaisesRegex(AssertionError, '^Exception not raised$'):
936      self.assertRaisesWithPredicateMatch(Exception,
937                                          lambda e: True,
938                                          lambda: 1)  # don't raise
939
940    with self.assertRaisesRegex(AssertionError, '^Exception not raised$'):
941      with self.assertRaisesWithPredicateMatch(Exception, lambda e: True):
942        pass  # don't raise
943
944  def test_assert_raises_with_predicate_match_raises_wrong_exception(self):
945    def _raise_value_error():
946      raise ValueError
947
948    with self.assertRaises(ValueError):
949      self.assertRaisesWithPredicateMatch(IOError,
950                                          lambda e: True,
951                                          _raise_value_error)
952
953    with self.assertRaises(ValueError):
954      with self.assertRaisesWithPredicateMatch(IOError, lambda e: True):
955        raise ValueError
956
957  def test_assert_raises_with_predicate_match_predicate_fails(self):
958    def _raise_value_error():
959      raise ValueError
960    with self.assertRaisesRegex(AssertionError, ' does not match predicate '):
961      self.assertRaisesWithPredicateMatch(ValueError,
962                                          lambda e: False,
963                                          _raise_value_error)
964
965    with self.assertRaisesRegex(AssertionError, ' does not match predicate '):
966      with self.assertRaisesWithPredicateMatch(ValueError, lambda e: False):
967        raise ValueError
968
969  def test_assert_raises_with_predicate_match_predicate_passes(self):
970    def _raise_value_error():
971      raise ValueError
972
973    self.assertRaisesWithPredicateMatch(ValueError,
974                                        lambda e: True,
975                                        _raise_value_error)
976
977    with self.assertRaisesWithPredicateMatch(ValueError, lambda e: True):
978      raise ValueError
979
980  def test_assert_raises_with_predicate_match_exception_captured(self):
981    def _raise_value_error():
982      raise ValueError
983
984    predicate = lambda e: e is not None
985    with self.assertRaisesWithPredicateMatch(ValueError, predicate) as ctx_mgr:
986      _raise_value_error()
987
988    expected = getattr(ctx_mgr, 'exception', None)
989    self.assertIsInstance(expected, ValueError)
990
991  def test_assert_raises_with_literal_match_exception_captured(self):
992    message = 'some value error'
993    def _raise_value_error():
994      raise ValueError(message)
995
996    # predicate = lambda e: e is not None
997    with self.assertRaisesWithLiteralMatch(ValueError, message) as ctx_mgr:
998      _raise_value_error()
999
1000    expected = getattr(ctx_mgr, 'exception', None)
1001    self.assertIsInstance(expected, ValueError)
1002
1003  def test_assert_contains_in_order(self):
1004    # Valids
1005    self.assertContainsInOrder(
1006        ['fox', 'dog'], 'The quick brown fox jumped over the lazy dog.')
1007    self.assertContainsInOrder(
1008        ['quick', 'fox', 'dog'],
1009        'The quick brown fox jumped over the lazy dog.')
1010    self.assertContainsInOrder(
1011        ['The', 'fox', 'dog.'], 'The quick brown fox jumped over the lazy dog.')
1012    self.assertContainsInOrder(
1013        ['fox'], 'The quick brown fox jumped over the lazy dog.')
1014    self.assertContainsInOrder(
1015        'fox', 'The quick brown fox jumped over the lazy dog.')
1016    self.assertContainsInOrder(
1017        ['fox', 'dog'], 'fox dog fox')
1018    self.assertContainsInOrder(
1019        [], 'The quick brown fox jumped over the lazy dog.')
1020    self.assertContainsInOrder(
1021        [], '')
1022
1023    # Invalids
1024    msg = 'This is a useful message'
1025    whole_msg = ("Did not find 'fox' after 'dog' in 'The quick brown fox"
1026                 " jumped over the lazy dog' : This is a useful message")
1027    self.assertRaisesWithLiteralMatch(
1028        AssertionError, whole_msg, self.assertContainsInOrder,
1029        ['dog', 'fox'], 'The quick brown fox jumped over the lazy dog', msg=msg)
1030    self.assertRaises(
1031        AssertionError, self.assertContainsInOrder,
1032        ['The', 'dog', 'fox'], 'The quick brown fox jumped over the lazy dog')
1033    self.assertRaises(
1034        AssertionError, self.assertContainsInOrder, ['dog'], '')
1035
1036  def test_assert_contains_subsequence_for_numbers(self):
1037    self.assertContainsSubsequence([1, 2, 3], [1])
1038    self.assertContainsSubsequence([1, 2, 3], [1, 2])
1039    self.assertContainsSubsequence([1, 2, 3], [1, 3])
1040
1041    with self.assertRaises(AssertionError):
1042      self.assertContainsSubsequence([1, 2, 3], [4])
1043    msg = 'This is a useful message'
1044    whole_msg = ('[3, 1] not a subsequence of [1, 2, 3]. '
1045                 'First non-matching element: 1 : This is a useful message')
1046    self.assertRaisesWithLiteralMatch(AssertionError, whole_msg,
1047                                      self.assertContainsSubsequence,
1048                                      [1, 2, 3], [3, 1], msg=msg)
1049
1050  def test_assert_contains_subsequence_for_strings(self):
1051    self.assertContainsSubsequence(['foo', 'bar', 'blorp'], ['foo', 'blorp'])
1052    with self.assertRaises(AssertionError):
1053      self.assertContainsSubsequence(
1054          ['foo', 'bar', 'blorp'], ['blorp', 'foo'])
1055
1056  def test_assert_contains_subsequence_with_empty_subsequence(self):
1057    self.assertContainsSubsequence([1, 2, 3], [])
1058    self.assertContainsSubsequence(['foo', 'bar', 'blorp'], [])
1059    self.assertContainsSubsequence([], [])
1060
1061  def test_assert_contains_subsequence_with_empty_container(self):
1062    with self.assertRaises(AssertionError):
1063      self.assertContainsSubsequence([], [1])
1064    with self.assertRaises(AssertionError):
1065      self.assertContainsSubsequence([], ['foo'])
1066
1067  def test_assert_contains_exact_subsequence_for_numbers(self):
1068    self.assertContainsExactSubsequence([1, 2, 3], [1])
1069    self.assertContainsExactSubsequence([1, 2, 3], [1, 2])
1070    self.assertContainsExactSubsequence([1, 2, 3], [2, 3])
1071
1072    with self.assertRaises(AssertionError):
1073      self.assertContainsExactSubsequence([1, 2, 3], [4])
1074    msg = 'This is a useful message'
1075    whole_msg = ('[1, 2, 4] not an exact subsequence of [1, 2, 3, 4]. '
1076                 'Longest matching prefix: [1, 2] : This is a useful message')
1077    self.assertRaisesWithLiteralMatch(AssertionError, whole_msg,
1078                                      self.assertContainsExactSubsequence,
1079                                      [1, 2, 3, 4], [1, 2, 4], msg=msg)
1080
1081  def test_assert_contains_exact_subsequence_for_strings(self):
1082    self.assertContainsExactSubsequence(
1083        ['foo', 'bar', 'blorp'], ['foo', 'bar'])
1084    with self.assertRaises(AssertionError):
1085      self.assertContainsExactSubsequence(
1086          ['foo', 'bar', 'blorp'], ['blorp', 'foo'])
1087
1088  def test_assert_contains_exact_subsequence_with_empty_subsequence(self):
1089    self.assertContainsExactSubsequence([1, 2, 3], [])
1090    self.assertContainsExactSubsequence(['foo', 'bar', 'blorp'], [])
1091    self.assertContainsExactSubsequence([], [])
1092
1093  def test_assert_contains_exact_subsequence_with_empty_container(self):
1094    with self.assertRaises(AssertionError):
1095      self.assertContainsExactSubsequence([], [3])
1096    with self.assertRaises(AssertionError):
1097      self.assertContainsExactSubsequence([], ['foo', 'bar'])
1098    self.assertContainsExactSubsequence([], [])
1099
1100  def test_assert_totally_ordered(self):
1101    # Valid.
1102    self.assertTotallyOrdered()
1103    self.assertTotallyOrdered([1])
1104    self.assertTotallyOrdered([1], [2])
1105    self.assertTotallyOrdered([1, 1, 1])
1106    self.assertTotallyOrdered([(1, 1)], [(1, 2)], [(2, 1)])
1107
1108    # From the docstring.
1109    class A(object):
1110
1111      def __init__(self, x, y):
1112        self.x = x
1113        self.y = y
1114
1115      def __hash__(self):
1116        return hash(self.x)
1117
1118      def __repr__(self):
1119        return 'A(%r, %r)' % (self.x, self.y)
1120
1121      def __eq__(self, other):
1122        try:
1123          return self.x == other.x
1124        except AttributeError:
1125          return NotImplemented
1126
1127      def __ne__(self, other):
1128        try:
1129          return self.x != other.x
1130        except AttributeError:
1131          return NotImplemented
1132
1133      def __lt__(self, other):
1134        try:
1135          return self.x < other.x
1136        except AttributeError:
1137          return NotImplemented
1138
1139      def __le__(self, other):
1140        try:
1141          return self.x <= other.x
1142        except AttributeError:
1143          return NotImplemented
1144
1145      def __gt__(self, other):
1146        try:
1147          return self.x > other.x
1148        except AttributeError:
1149          return NotImplemented
1150
1151      def __ge__(self, other):
1152        try:
1153          return self.x >= other.x
1154        except AttributeError:
1155          return NotImplemented
1156
1157    class B(A):
1158      """Like A, but not hashable."""
1159      __hash__ = None
1160
1161    self.assertTotallyOrdered(
1162        [A(1, 'a')],
1163        [A(2, 'b')],  # 2 is after 1.
1164        [
1165            A(3, 'c'),
1166            B(3, 'd'),
1167            B(3, 'e')  # The second argument is irrelevant.
1168        ],
1169        [A(4, 'z')])
1170
1171    # Invalid.
1172    msg = 'This is a useful message'
1173    whole_msg = '2 not less than 1 : This is a useful message'
1174    self.assertRaisesWithLiteralMatch(AssertionError, whole_msg,
1175                                      self.assertTotallyOrdered, [2], [1],
1176                                      msg=msg)
1177    self.assertRaises(AssertionError, self.assertTotallyOrdered, [2], [1])
1178    self.assertRaises(AssertionError, self.assertTotallyOrdered, [2], [1], [3])
1179    self.assertRaises(AssertionError, self.assertTotallyOrdered, [1, 2])
1180
1181  def test_short_description_without_docstring(self):
1182    self.assertEqual(
1183        self.shortDescription(),
1184        'TestCaseTest.test_short_description_without_docstring',
1185    )
1186
1187  def test_short_description_with_one_line_docstring(self):
1188    """Tests shortDescription() for a method with a docstring."""
1189    self.assertEqual(
1190        self.shortDescription(),
1191        'TestCaseTest.test_short_description_with_one_line_docstring\n'
1192        'Tests shortDescription() for a method with a docstring.',
1193    )
1194
1195  def test_short_description_with_multi_line_docstring(self):
1196    """Tests shortDescription() for a method with a longer docstring.
1197
1198    This method ensures that only the first line of a docstring is
1199    returned used in the short description, no matter how long the
1200    whole thing is.
1201    """
1202    self.assertEqual(
1203        self.shortDescription(),
1204        'TestCaseTest.test_short_description_with_multi_line_docstring\n'
1205        'Tests shortDescription() for a method with a longer docstring.',
1206    )
1207
1208  def test_assert_url_equal_same(self):
1209    self.assertUrlEqual('http://a', 'http://a')
1210    self.assertUrlEqual('http://a/path/test', 'http://a/path/test')
1211    self.assertUrlEqual('#fragment', '#fragment')
1212    self.assertUrlEqual('http://a/?q=1', 'http://a/?q=1')
1213    self.assertUrlEqual('http://a/?q=1&v=5', 'http://a/?v=5&q=1')
1214    self.assertUrlEqual('/logs?v=1&a=2&t=labels&f=path%3A%22foo%22',
1215                        '/logs?a=2&f=path%3A%22foo%22&v=1&t=labels')
1216    self.assertUrlEqual('http://a/path;p1', 'http://a/path;p1')
1217    self.assertUrlEqual('http://a/path;p2;p3;p1', 'http://a/path;p1;p2;p3')
1218    self.assertUrlEqual('sip:[email protected];maddr=239.255.255.1;ttl=15',
1219                        'sip:[email protected];ttl=15;maddr=239.255.255.1')
1220    self.assertUrlEqual('http://nyan/cat?p=1&b=', 'http://nyan/cat?b=&p=1')
1221
1222  def test_assert_url_equal_different(self):
1223    msg = 'This is a useful message'
1224    whole_msg = 'This is a useful message:\n- a\n+ b\n'
1225    self.assertRaisesWithLiteralMatch(AssertionError, whole_msg,
1226                                      self.assertUrlEqual,
1227                                      'http://a', 'http://b', msg=msg)
1228    self.assertRaises(AssertionError, self.assertUrlEqual,
1229                      'http://a/x', 'http://a:8080/x')
1230    self.assertRaises(AssertionError, self.assertUrlEqual,
1231                      'http://a/x', 'http://a/y')
1232    self.assertRaises(AssertionError, self.assertUrlEqual,
1233                      'http://a/?q=2', 'http://a/?q=1')
1234    self.assertRaises(AssertionError, self.assertUrlEqual,
1235                      'http://a/?q=1&v=5', 'http://a/?v=2&q=1')
1236    self.assertRaises(AssertionError, self.assertUrlEqual,
1237                      'http://a', 'sip://b')
1238    self.assertRaises(AssertionError, self.assertUrlEqual,
1239                      'http://a#g', 'sip://a#f')
1240    self.assertRaises(AssertionError, self.assertUrlEqual,
1241                      'http://a/path;p1;p3;p1', 'http://a/path;p1;p2;p3')
1242    self.assertRaises(AssertionError, self.assertUrlEqual,
1243                      'http://nyan/cat?p=1&b=', 'http://nyan/cat?p=1')
1244
1245  def test_same_structure_same(self):
1246    self.assertSameStructure(0, 0)
1247    self.assertSameStructure(1, 1)
1248    self.assertSameStructure('', '')
1249    self.assertSameStructure('hello', 'hello', msg='This Should not fail')
1250    self.assertSameStructure(set(), set())
1251    self.assertSameStructure(set([1, 2]), set([1, 2]))
1252    self.assertSameStructure(set(), frozenset())
1253    self.assertSameStructure(set([1, 2]), frozenset([1, 2]))
1254    self.assertSameStructure([], [])
1255    self.assertSameStructure(['a'], ['a'])
1256    self.assertSameStructure([], ())
1257    self.assertSameStructure(['a'], ('a',))
1258    self.assertSameStructure({}, {})
1259    self.assertSameStructure({'one': 1}, {'one': 1})
1260    self.assertSameStructure(collections.defaultdict(None, {'one': 1}),
1261                             {'one': 1})
1262    self.assertSameStructure(collections.OrderedDict({'one': 1}),
1263                             collections.defaultdict(None, {'one': 1}))
1264
1265  def test_same_structure_different(self):
1266    # Different type
1267    with self.assertRaisesRegex(
1268        AssertionError,
1269        r"a is a <(type|class) 'int'> but b is a <(type|class) 'str'>"):
1270      self.assertSameStructure(0, 'hello')
1271    with self.assertRaisesRegex(
1272        AssertionError,
1273        r"a is a <(type|class) 'int'> but b is a <(type|class) 'list'>"):
1274      self.assertSameStructure(0, [])
1275    with self.assertRaisesRegex(
1276        AssertionError,
1277        r"a is a <(type|class) 'int'> but b is a <(type|class) 'float'>"):
1278      self.assertSameStructure(2, 2.0)
1279
1280    with self.assertRaisesRegex(
1281        AssertionError,
1282        r"a is a <(type|class) 'list'> but b is a <(type|class) 'dict'>"):
1283      self.assertSameStructure([], {})
1284
1285    with self.assertRaisesRegex(
1286        AssertionError,
1287        r"a is a <(type|class) 'list'> but b is a <(type|class) 'set'>"):
1288      self.assertSameStructure([], set())
1289
1290    with self.assertRaisesRegex(
1291        AssertionError,
1292        r"a is a <(type|class) 'dict'> but b is a <(type|class) 'set'>"):
1293      self.assertSameStructure({}, set())
1294
1295    # Different scalar values
1296    self.assertRaisesWithLiteralMatch(
1297        AssertionError, 'a is 0 but b is 1',
1298        self.assertSameStructure, 0, 1)
1299    self.assertRaisesWithLiteralMatch(
1300        AssertionError, "a is 'hello' but b is 'goodbye' : This was expected",
1301        self.assertSameStructure, 'hello', 'goodbye', msg='This was expected')
1302
1303    # Different sets
1304    self.assertRaisesWithLiteralMatch(
1305        AssertionError,
1306        r'AA has 2 but BB does not',
1307        self.assertSameStructure,
1308        set([1, 2]),
1309        set([1]),
1310        aname='AA',
1311        bname='BB')
1312    self.assertRaisesWithLiteralMatch(
1313        AssertionError,
1314        r'AA lacks 2 but BB has it',
1315        self.assertSameStructure,
1316        set([1]),
1317        set([1, 2]),
1318        aname='AA',
1319        bname='BB')
1320
1321    # Different lists
1322    self.assertRaisesWithLiteralMatch(
1323        AssertionError, "a has [2] with value 'z' but b does not",
1324        self.assertSameStructure, ['x', 'y', 'z'], ['x', 'y'])
1325    self.assertRaisesWithLiteralMatch(
1326        AssertionError, "a lacks [2] but b has it with value 'z'",
1327        self.assertSameStructure, ['x', 'y'], ['x', 'y', 'z'])
1328    self.assertRaisesWithLiteralMatch(
1329        AssertionError, "a[2] is 'z' but b[2] is 'Z'",
1330        self.assertSameStructure, ['x', 'y', 'z'], ['x', 'y', 'Z'])
1331
1332    # Different dicts
1333    self.assertRaisesWithLiteralMatch(
1334        AssertionError, "a has ['two'] with value 2 but it's missing in b",
1335        self.assertSameStructure, {'one': 1, 'two': 2}, {'one': 1})
1336    self.assertRaisesWithLiteralMatch(
1337        AssertionError, "a lacks ['two'] but b has it with value 2",
1338        self.assertSameStructure, {'one': 1}, {'one': 1, 'two': 2})
1339    self.assertRaisesWithLiteralMatch(
1340        AssertionError, "a['two'] is 2 but b['two'] is 3",
1341        self.assertSameStructure, {'one': 1, 'two': 2}, {'one': 1, 'two': 3})
1342
1343    # String and byte types should not be considered equivalent to other
1344    # sequences
1345    self.assertRaisesRegex(
1346        AssertionError,
1347        r"a is a <(type|class) 'list'> but b is a <(type|class) 'str'>",
1348        self.assertSameStructure, [], '')
1349    self.assertRaisesRegex(
1350        AssertionError,
1351        r"a is a <(type|class) 'str'> but b is a <(type|class) 'tuple'>",
1352        self.assertSameStructure, '', ())
1353    self.assertRaisesRegex(
1354        AssertionError,
1355        r"a is a <(type|class) 'list'> but b is a <(type|class) 'str'>",
1356        self.assertSameStructure, ['a', 'b', 'c'], 'abc')
1357    self.assertRaisesRegex(
1358        AssertionError,
1359        r"a is a <(type|class) 'str'> but b is a <(type|class) 'tuple'>",
1360        self.assertSameStructure, 'abc', ('a', 'b', 'c'))
1361
1362    # Deep key generation
1363    self.assertRaisesWithLiteralMatch(
1364        AssertionError,
1365        "a[0][0]['x']['y']['z'][0] is 1 but b[0][0]['x']['y']['z'][0] is 2",
1366        self.assertSameStructure,
1367        [[{'x': {'y': {'z': [1]}}}]], [[{'x': {'y': {'z': [2]}}}]])
1368
1369    # Multiple problems
1370    self.assertRaisesWithLiteralMatch(
1371        AssertionError,
1372        'a[0] is 1 but b[0] is 3; a[1] is 2 but b[1] is 4',
1373        self.assertSameStructure, [1, 2], [3, 4])
1374    with self.assertRaisesRegex(
1375        AssertionError,
1376        re.compile(r"^a\[0] is 'a' but b\[0] is 'A'; .*"
1377                   r"a\[18] is 's' but b\[18] is 'S'; \.\.\.$")):
1378      self.assertSameStructure(
1379          list(string.ascii_lowercase), list(string.ascii_uppercase))
1380
1381    # Verify same behavior with self.maxDiff = None
1382    self.maxDiff = None
1383    self.assertRaisesWithLiteralMatch(
1384        AssertionError,
1385        'a[0] is 1 but b[0] is 3; a[1] is 2 but b[1] is 4',
1386        self.assertSameStructure, [1, 2], [3, 4])
1387
1388  def test_same_structure_mapping_unchanged(self):
1389    default_a = collections.defaultdict(lambda: 'BAD MODIFICATION', {})
1390    dict_b = {'one': 'z'}
1391    self.assertRaisesWithLiteralMatch(
1392        AssertionError,
1393        r"a lacks ['one'] but b has it with value 'z'",
1394        self.assertSameStructure, default_a, dict_b)
1395    self.assertEmpty(default_a)
1396
1397    dict_a = {'one': 'z'}
1398    default_b = collections.defaultdict(lambda: 'BAD MODIFICATION', {})
1399    self.assertRaisesWithLiteralMatch(
1400        AssertionError,
1401        r"a has ['one'] with value 'z' but it's missing in b",
1402        self.assertSameStructure, dict_a, default_b)
1403    self.assertEmpty(default_b)
1404
1405  def test_same_structure_uses_type_equality_func_for_leaves(self):
1406    class CustomLeaf(object):
1407      def __init__(self, n):
1408        self.n = n
1409
1410      def __repr__(self):
1411        return f'CustomLeaf({self.n})'
1412
1413    def assert_custom_leaf_equal(a, b, msg):
1414      del msg
1415      assert a.n % 5 == b.n % 5
1416    self.addTypeEqualityFunc(CustomLeaf, assert_custom_leaf_equal)
1417
1418    self.assertSameStructure(CustomLeaf(4), CustomLeaf(9))
1419    self.assertRaisesWithLiteralMatch(
1420        AssertionError,
1421        r'a is CustomLeaf(4) but b is CustomLeaf(8)',
1422        self.assertSameStructure, CustomLeaf(4), CustomLeaf(8),
1423    )
1424
1425  def test_assert_json_equal_same(self):
1426    self.assertJsonEqual('{"success": true}', '{"success": true}')
1427    self.assertJsonEqual('{"success": true}', '{"success":true}')
1428    self.assertJsonEqual('true', 'true')
1429    self.assertJsonEqual('null', 'null')
1430    self.assertJsonEqual('false', 'false')
1431    self.assertJsonEqual('34', '34')
1432    self.assertJsonEqual('[1, 2, 3]', '[1,2,3]', msg='please PASS')
1433    self.assertJsonEqual('{"sequence": [1, 2, 3], "float": 23.42}',
1434                         '{"float": 23.42, "sequence": [1,2,3]}')
1435    self.assertJsonEqual('{"nest": {"spam": "eggs"}, "float": 23.42}',
1436                         '{"float": 23.42, "nest": {"spam":"eggs"}}')
1437
1438  def test_assert_json_equal_different(self):
1439    with self.assertRaises(AssertionError):
1440      self.assertJsonEqual('{"success": true}', '{"success": false}')
1441    with self.assertRaises(AssertionError):
1442      self.assertJsonEqual('{"success": false}', '{"Success": false}')
1443    with self.assertRaises(AssertionError):
1444      self.assertJsonEqual('false', 'true')
1445    with self.assertRaises(AssertionError) as error_context:
1446      self.assertJsonEqual('null', '0', msg='I demand FAILURE')
1447    self.assertIn('I demand FAILURE', error_context.exception.args[0])
1448    self.assertIn('None', error_context.exception.args[0])
1449    with self.assertRaises(AssertionError):
1450      self.assertJsonEqual('[1, 0, 3]', '[1,2,3]')
1451    with self.assertRaises(AssertionError):
1452      self.assertJsonEqual('{"sequence": [1, 2, 3], "float": 23.42}',
1453                           '{"float": 23.42, "sequence": [1,0,3]}')
1454    with self.assertRaises(AssertionError):
1455      self.assertJsonEqual('{"nest": {"spam": "eggs"}, "float": 23.42}',
1456                           '{"float": 23.42, "nest": {"Spam":"beans"}}')
1457
1458  def test_assert_json_equal_bad_json(self):
1459    with self.assertRaises(ValueError) as error_context:
1460      self.assertJsonEqual("alhg'2;#", '{"a": true}')
1461    self.assertIn('first', error_context.exception.args[0])
1462    self.assertIn('alhg', error_context.exception.args[0])
1463
1464    with self.assertRaises(ValueError) as error_context:
1465      self.assertJsonEqual('{"a": true}', "alhg'2;#")
1466    self.assertIn('second', error_context.exception.args[0])
1467    self.assertIn('alhg', error_context.exception.args[0])
1468
1469    with self.assertRaises(ValueError) as error_context:
1470      self.assertJsonEqual('', '')
1471
1472
1473class GetCommandStderrTestCase(absltest.TestCase):
1474
1475  def test_return_status(self):
1476    tmpdir = tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value)
1477    returncode = (
1478        absltest.get_command_stderr(
1479            ['cat', os.path.join(tmpdir, 'file.txt')],
1480            env=_env_for_command_tests())[0])
1481    self.assertEqual(1, returncode)
1482
1483  def test_stderr(self):
1484    tmpdir = tempfile.mkdtemp(dir=absltest.TEST_TMPDIR.value)
1485    stderr = (
1486        absltest.get_command_stderr(
1487            ['cat', os.path.join(tmpdir, 'file.txt')],
1488            env=_env_for_command_tests())[1])
1489    stderr = stderr.decode('utf-8')
1490    self.assertRegex(stderr, 'No such file or directory')
1491
1492
1493@contextlib.contextmanager
1494def cm_for_test(obj):
1495  try:
1496    obj.cm_state = 'yielded'
1497    yield 'value'
1498  finally:
1499    obj.cm_state = 'exited'
1500
1501
1502class EnterContextTest(absltest.TestCase):
1503
1504  def setUp(self):
1505    self.cm_state = 'unset'
1506    self.cm_value = 'unset'
1507
1508    def assert_cm_exited():
1509      self.assertEqual(self.cm_state, 'exited')
1510
1511    # Because cleanup functions are run in reverse order, we have to add
1512    # our assert-cleanup before the exit stack registers its own cleanup.
1513    # This ensures we see state after the stack cleanup runs.
1514    self.addCleanup(assert_cm_exited)
1515
1516    super(EnterContextTest, self).setUp()
1517    self.cm_value = self.enter_context(cm_for_test(self))
1518
1519  def test_enter_context(self):
1520    self.assertEqual(self.cm_value, 'value')
1521    self.assertEqual(self.cm_state, 'yielded')
1522
1523
1524@absltest.skipIf(not hasattr(absltest.TestCase, 'addClassCleanup'),
1525                 'Python 3.8 required for class-level enter_context')
1526class EnterContextClassmethodTest(absltest.TestCase):
1527
1528  cm_state = 'unset'
1529  cm_value = 'unset'
1530
1531  @classmethod
1532  def setUpClass(cls):
1533
1534    def assert_cm_exited():
1535      assert cls.cm_state == 'exited'
1536
1537    # Because cleanup functions are run in reverse order, we have to add
1538    # our assert-cleanup before the exit stack registers its own cleanup.
1539    # This ensures we see state after the stack cleanup runs.
1540    cls.addClassCleanup(assert_cm_exited)
1541
1542    super(EnterContextClassmethodTest, cls).setUpClass()
1543    cls.cm_value = cls.enter_context(cm_for_test(cls))
1544
1545  def test_enter_context(self):
1546    self.assertEqual(self.cm_value, 'value')
1547    self.assertEqual(self.cm_state, 'yielded')
1548
1549
1550class EqualityAssertionTest(absltest.TestCase):
1551  """This test verifies that absltest.failIfEqual actually tests __ne__.
1552
1553  If a user class implements __eq__, unittest.assertEqual will call it
1554  via first == second.   However, failIfEqual also calls
1555  first == second.   This means that while the caller may believe
1556  their __ne__ method is being tested, it is not.
1557  """
1558
1559  class NeverEqual(object):
1560    """Objects of this class behave like NaNs."""
1561
1562    def __eq__(self, unused_other):
1563      return False
1564
1565    def __ne__(self, unused_other):
1566      return False
1567
1568  class AllSame(object):
1569    """All objects of this class compare as equal."""
1570
1571    def __eq__(self, unused_other):
1572      return True
1573
1574    def __ne__(self, unused_other):
1575      return False
1576
1577  class EqualityTestsWithEq(object):
1578    """Performs all equality and inequality tests with __eq__."""
1579
1580    def __init__(self, value):
1581      self._value = value
1582
1583    def __eq__(self, other):
1584      return self._value == other._value
1585
1586    def __ne__(self, other):
1587      return not self.__eq__(other)
1588
1589  class EqualityTestsWithNe(object):
1590    """Performs all equality and inequality tests with __ne__."""
1591
1592    def __init__(self, value):
1593      self._value = value
1594
1595    def __eq__(self, other):
1596      return not self.__ne__(other)
1597
1598    def __ne__(self, other):
1599      return self._value != other._value
1600
1601  class EqualityTestsWithCmp(object):
1602
1603    def __init__(self, value):
1604      self._value = value
1605
1606    def __cmp__(self, other):
1607      return cmp(self._value, other._value)
1608
1609  class EqualityTestsWithLtEq(object):
1610
1611    def __init__(self, value):
1612      self._value = value
1613
1614    def __eq__(self, other):
1615      return self._value == other._value
1616
1617    def __lt__(self, other):
1618      return self._value < other._value
1619
1620  def test_all_comparisons_fail(self):
1621    i1 = self.NeverEqual()
1622    i2 = self.NeverEqual()
1623    self.assertFalse(i1 == i2)
1624    self.assertFalse(i1 != i2)
1625
1626    # Compare two distinct objects
1627    self.assertFalse(i1 is i2)
1628    self.assertRaises(AssertionError, self.assertEqual, i1, i2)
1629    self.assertRaises(AssertionError, self.assertNotEqual, i1, i2)
1630    # A NeverEqual object should not compare equal to itself either.
1631    i2 = i1
1632    self.assertTrue(i1 is i2)
1633    self.assertFalse(i1 == i2)
1634    self.assertFalse(i1 != i2)
1635    self.assertRaises(AssertionError, self.assertEqual, i1, i2)
1636    self.assertRaises(AssertionError, self.assertNotEqual, i1, i2)
1637
1638  def test_all_comparisons_succeed(self):
1639    a = self.AllSame()
1640    b = self.AllSame()
1641    self.assertFalse(a is b)
1642    self.assertTrue(a == b)
1643    self.assertFalse(a != b)
1644    self.assertEqual(a, b)
1645    self.assertRaises(AssertionError, self.assertNotEqual, a, b)
1646
1647  def _perform_apple_apple_orange_checks(self, same_a, same_b, different):
1648    """Perform consistency checks with two apples and an orange.
1649
1650    The two apples should always compare as being the same (and inequality
1651    checks should fail).  The orange should always compare as being different
1652    to each of the apples.
1653
1654    Args:
1655      same_a: the first apple
1656      same_b: the second apple
1657      different: the orange
1658    """
1659    self.assertTrue(same_a == same_b)
1660    self.assertFalse(same_a != same_b)
1661    self.assertEqual(same_a, same_b)
1662
1663    self.assertFalse(same_a == different)
1664    self.assertTrue(same_a != different)
1665    self.assertNotEqual(same_a, different)
1666
1667    self.assertFalse(same_b == different)
1668    self.assertTrue(same_b != different)
1669    self.assertNotEqual(same_b, different)
1670
1671  def test_comparison_with_eq(self):
1672    same_a = self.EqualityTestsWithEq(42)
1673    same_b = self.EqualityTestsWithEq(42)
1674    different = self.EqualityTestsWithEq(1769)
1675    self._perform_apple_apple_orange_checks(same_a, same_b, different)
1676
1677  def test_comparison_with_ne(self):
1678    same_a = self.EqualityTestsWithNe(42)
1679    same_b = self.EqualityTestsWithNe(42)
1680    different = self.EqualityTestsWithNe(1769)
1681    self._perform_apple_apple_orange_checks(same_a, same_b, different)
1682
1683  def test_comparison_with_cmp_or_lt_eq(self):
1684    same_a = self.EqualityTestsWithLtEq(42)
1685    same_b = self.EqualityTestsWithLtEq(42)
1686    different = self.EqualityTestsWithLtEq(1769)
1687    self._perform_apple_apple_orange_checks(same_a, same_b, different)
1688
1689
1690class AssertSequenceStartsWithTest(parameterized.TestCase):
1691
1692  def setUp(self):
1693    super().setUp()
1694    self.a = [5, 'foo', {'c': 'd'}, None]
1695
1696  def test_empty_sequence_starts_with_empty_prefix(self):
1697    self.assertSequenceStartsWith([], ())
1698
1699  def test_sequence_prefix_is_an_empty_list(self):
1700    self.assertSequenceStartsWith([[]], ([], 'foo'))
1701
1702  def test_raise_if_empty_prefix_with_non_empty_whole(self):
1703    with self.assertRaisesRegex(
1704        AssertionError, 'Prefix length is 0 but whole length is %d: %s' % (len(
1705            self.a), r"\[5, 'foo', \{'c': 'd'\}, None\]")):
1706      self.assertSequenceStartsWith([], self.a)
1707
1708  def test_single_element_prefix(self):
1709    self.assertSequenceStartsWith([5], self.a)
1710
1711  def test_two_element_prefix(self):
1712    self.assertSequenceStartsWith((5, 'foo'), self.a)
1713
1714  def test_prefix_is_full_sequence(self):
1715    self.assertSequenceStartsWith([5, 'foo', {'c': 'd'}, None], self.a)
1716
1717  def test_string_prefix(self):
1718    self.assertSequenceStartsWith('abc', 'abc123')
1719
1720  def test_convert_non_sequence_prefix_to_sequence_and_try_again(self):
1721    self.assertSequenceStartsWith(5, self.a)
1722
1723  def test_whole_not_asequence(self):
1724    msg = (r'For whole: len\(5\) is not supported, it appears to be type: '
1725           '<(type|class) \'int\'>')
1726    with self.assertRaisesRegex(AssertionError, msg):
1727      self.assertSequenceStartsWith(self.a, 5)
1728
1729  def test_raise_if_sequence_does_not_start_with_prefix(self):
1730    msg = (r"prefix: \['foo', \{'c': 'd'\}\] not found at start of whole: "
1731           r"\[5, 'foo', \{'c': 'd'\}, None\].")
1732    with self.assertRaisesRegex(AssertionError, msg):
1733      self.assertSequenceStartsWith(['foo', {'c': 'd'}], self.a)
1734
1735  @parameterized.named_parameters(
1736      ('dict', {'a': 1, 2: 'b'}, {'a': 1, 2: 'b', 'c': '3'}),
1737      ('set', {1, 2}, {1, 2, 3}),
1738  )
1739  def test_raise_if_set_or_dict(self, prefix, whole):
1740    with self.assertRaisesRegex(
1741        AssertionError, 'For whole: Mapping or Set objects are not supported'
1742    ):
1743      self.assertSequenceStartsWith(prefix, whole)
1744
1745
1746class TestAssertEmpty(absltest.TestCase):
1747  longMessage = True
1748
1749  def test_raises_if_not_asized_object(self):
1750    msg = "Expected a Sized object, got: 'int'"
1751    with self.assertRaisesRegex(AssertionError, msg):
1752      self.assertEmpty(1)
1753
1754  def test_calls_len_not_bool(self):
1755
1756    class BadList(list):
1757
1758      def __bool__(self):
1759        return False
1760
1761      __nonzero__ = __bool__
1762
1763    bad_list = BadList()
1764    self.assertEmpty(bad_list)
1765    self.assertFalse(bad_list)
1766
1767  def test_passes_when_empty(self):
1768    empty_containers = [
1769        list(),
1770        tuple(),
1771        dict(),
1772        set(),
1773        frozenset(),
1774        b'',
1775        u'',
1776        bytearray(),
1777    ]
1778    for container in empty_containers:
1779      self.assertEmpty(container)
1780
1781  def test_raises_with_not_empty_containers(self):
1782    not_empty_containers = [
1783        [1],
1784        (1,),
1785        {'foo': 'bar'},
1786        {1},
1787        frozenset([1]),
1788        b'a',
1789        u'a',
1790        bytearray(b'a'),
1791    ]
1792    regexp = r'.* has length of 1\.$'
1793    for container in not_empty_containers:
1794      with self.assertRaisesRegex(AssertionError, regexp):
1795        self.assertEmpty(container)
1796
1797  def test_user_message_added_to_default(self):
1798    msg = 'This is a useful message'
1799    whole_msg = re.escape('[1] has length of 1. : This is a useful message')
1800    with self.assertRaisesRegex(AssertionError, whole_msg):
1801      self.assertEmpty([1], msg=msg)
1802
1803
1804class TestAssertNotEmpty(absltest.TestCase):
1805  longMessage = True
1806
1807  def test_raises_if_not_asized_object(self):
1808    msg = "Expected a Sized object, got: 'int'"
1809    with self.assertRaisesRegex(AssertionError, msg):
1810      self.assertNotEmpty(1)
1811
1812  def test_calls_len_not_bool(self):
1813
1814    class BadList(list):
1815
1816      def __bool__(self):
1817        return False
1818
1819      __nonzero__ = __bool__
1820
1821    bad_list = BadList([1])
1822    self.assertNotEmpty(bad_list)
1823    self.assertFalse(bad_list)
1824
1825  def test_passes_when_not_empty(self):
1826    not_empty_containers = [
1827        [1],
1828        (1,),
1829        {'foo': 'bar'},
1830        {1},
1831        frozenset([1]),
1832        b'a',
1833        u'a',
1834        bytearray(b'a'),
1835    ]
1836    for container in not_empty_containers:
1837      self.assertNotEmpty(container)
1838
1839  def test_raises_with_empty_containers(self):
1840    empty_containers = [
1841        list(),
1842        tuple(),
1843        dict(),
1844        set(),
1845        frozenset(),
1846        b'',
1847        u'',
1848        bytearray(),
1849    ]
1850    regexp = r'.* has length of 0\.$'
1851    for container in empty_containers:
1852      with self.assertRaisesRegex(AssertionError, regexp):
1853        self.assertNotEmpty(container)
1854
1855  def test_user_message_added_to_default(self):
1856    msg = 'This is a useful message'
1857    whole_msg = re.escape('[] has length of 0. : This is a useful message')
1858    with self.assertRaisesRegex(AssertionError, whole_msg):
1859      self.assertNotEmpty([], msg=msg)
1860
1861
1862class TestAssertLen(absltest.TestCase):
1863  longMessage = True
1864
1865  def test_raises_if_not_asized_object(self):
1866    msg = "Expected a Sized object, got: 'int'"
1867    with self.assertRaisesRegex(AssertionError, msg):
1868      self.assertLen(1, 1)
1869
1870  def test_passes_when_expected_len(self):
1871    containers = [
1872        [[1], 1],
1873        [(1, 2), 2],
1874        [{'a': 1, 'b': 2, 'c': 3}, 3],
1875        [{1, 2, 3, 4}, 4],
1876        [frozenset([1]), 1],
1877        [b'abc', 3],
1878        [u'def', 3],
1879        [bytearray(b'ghij'), 4],
1880    ]
1881    for container, expected_len in containers:
1882      self.assertLen(container, expected_len)
1883
1884  def test_raises_when_unexpected_len(self):
1885    containers = [
1886        [1],
1887        (1, 2),
1888        {'a': 1, 'b': 2, 'c': 3},
1889        {1, 2, 3, 4},
1890        frozenset([1]),
1891        b'abc',
1892        u'def',
1893        bytearray(b'ghij'),
1894    ]
1895    for container in containers:
1896      regexp = r'.* has length of %d, expected 100\.$' % len(container)
1897      with self.assertRaisesRegex(AssertionError, regexp):
1898        self.assertLen(container, 100)
1899
1900  def test_user_message_added_to_default(self):
1901    msg = 'This is a useful message'
1902    whole_msg = (
1903        r'\[1\] has length of 1, expected 100. : This is a useful message')
1904    with self.assertRaisesRegex(AssertionError, whole_msg):
1905      self.assertLen([1], 100, msg)
1906
1907
1908class TestLoaderTest(absltest.TestCase):
1909  """Tests that the TestLoader bans methods named TestFoo."""
1910
1911  # pylint: disable=invalid-name
1912  class Valid(absltest.TestCase):
1913    """Test case containing a variety of valid names."""
1914
1915    test_property = 1
1916    TestProperty = 2
1917
1918    @staticmethod
1919    def TestStaticMethod():
1920      pass
1921
1922    @staticmethod
1923    def TestStaticMethodWithArg(foo):
1924      pass
1925
1926    @classmethod
1927    def TestClassMethod(cls):
1928      pass
1929
1930    def Test(self):
1931      pass
1932
1933    def TestingHelper(self):
1934      pass
1935
1936    def testMethod(self):
1937      pass
1938
1939    def TestHelperWithParams(self, a, b):
1940      pass
1941
1942    def TestHelperWithVarargs(self, *args, **kwargs):
1943      pass
1944
1945    def TestHelperWithDefaults(self, a=5):
1946      pass
1947
1948    def TestHelperWithKeywordOnly(self, *, arg):
1949      pass
1950
1951  class Invalid(absltest.TestCase):
1952    """Test case containing a suspicious method."""
1953
1954    def testMethod(self):
1955      pass
1956
1957    def TestSuspiciousMethod(self):
1958      pass
1959  # pylint: enable=invalid-name
1960
1961  def setUp(self):
1962    self.loader = absltest.TestLoader()
1963
1964  def test_valid(self):
1965    suite = self.loader.loadTestsFromTestCase(TestLoaderTest.Valid)
1966    self.assertEqual(1, suite.countTestCases())
1967
1968  def testInvalid(self):
1969    with self.assertRaisesRegex(TypeError, 'TestSuspiciousMethod'):
1970      self.loader.loadTestsFromTestCase(TestLoaderTest.Invalid)
1971
1972
1973class InitNotNecessaryForAssertsTest(absltest.TestCase):
1974  """TestCase assertions should work even if __init__ wasn't correctly called.
1975
1976  This is a workaround, see comment in
1977  absltest.TestCase._getAssertEqualityFunc. We know that not calling
1978  __init__ of a superclass is a bad thing, but people keep doing them,
1979  and this (even if a little bit dirty) saves them from shooting
1980  themselves in the foot.
1981  """
1982
1983  def test_subclass(self):
1984
1985    class Subclass(absltest.TestCase):
1986
1987      def __init__(self):  # pylint: disable=super-init-not-called
1988        pass
1989
1990    Subclass().assertEqual({}, {})
1991
1992  def test_multiple_inheritance(self):
1993
1994    class Foo(object):
1995
1996      def __init__(self, *args, **kwargs):
1997        pass
1998
1999    class Subclass(Foo, absltest.TestCase):
2000      pass
2001
2002    Subclass().assertEqual({}, {})
2003
2004
2005@dataclasses.dataclass
2006class _ExampleDataclass:
2007  comparable: str
2008  not_comparable: str = dataclasses.field(compare=False)
2009  comparable2: str = 'comparable2'
2010
2011
2012@dataclasses.dataclass
2013class _ExampleCustomEqualDataclass:
2014  value: str
2015
2016  def __eq__(self, other):
2017    return False
2018
2019
2020class TestAssertDataclassEqual(absltest.TestCase):
2021
2022  def test_assert_dataclass_equal_checks_a_for_dataclass(self):
2023    b = _ExampleDataclass('a', 'b')
2024
2025    message = 'First argument is not a dataclass instance.'
2026    with self.assertRaisesWithLiteralMatch(AssertionError, message):
2027      self.assertDataclassEqual('a', b)
2028
2029  def test_assert_dataclass_equal_checks_b_for_dataclass(self):
2030    a = _ExampleDataclass('a', 'b')
2031
2032    message = 'Second argument is not a dataclass instance.'
2033    with self.assertRaisesWithLiteralMatch(AssertionError, message):
2034      self.assertDataclassEqual(a, 'b')
2035
2036  def test_assert_dataclass_equal_different_dataclasses(self):
2037    a = _ExampleDataclass('a', 'b')
2038    b = _ExampleCustomEqualDataclass('c')
2039
2040    message = """Found different dataclass types: <class '__main__._ExampleDataclass'> != <class '__main__._ExampleCustomEqualDataclass'>"""
2041    with self.assertRaisesWithLiteralMatch(AssertionError, message):
2042      self.assertDataclassEqual(a, b)
2043
2044  def test_assert_dataclass_equal(self):
2045    a = _ExampleDataclass(comparable='a', not_comparable='b')
2046    b = _ExampleDataclass(comparable='a', not_comparable='c')
2047
2048    self.assertDataclassEqual(a, a)
2049    self.assertDataclassEqual(a, b)
2050    self.assertDataclassEqual(b, a)
2051
2052  def test_assert_dataclass_fails_non_equal_classes_assert_dict_passes(self):
2053    a = _ExampleCustomEqualDataclass(value='a')
2054    b = _ExampleCustomEqualDataclass(value='a')
2055
2056    message = textwrap.dedent("""\
2057        _ExampleCustomEqualDataclass(value='a') != _ExampleCustomEqualDataclass(value='a')
2058        Cannot detect difference by examining the fields of the dataclass.""")
2059    with self.assertRaisesWithLiteralMatch(AssertionError, message):
2060      self.assertDataclassEqual(a, b)
2061
2062  def test_assert_dataclass_fails_assert_dict_fails_one_field(self):
2063    a = _ExampleDataclass(comparable='a', not_comparable='b')
2064    b = _ExampleDataclass(comparable='c', not_comparable='d')
2065
2066    message = textwrap.dedent("""\
2067        _ExampleDataclass(comparable='a', not_comparable='b', comparable2='comparable2') != _ExampleDataclass(comparable='c', not_comparable='d', comparable2='comparable2')
2068        Fields that differ:
2069        comparable: 'a' != 'c'""")
2070    with self.assertRaisesWithLiteralMatch(AssertionError, message):
2071      self.assertDataclassEqual(a, b)
2072
2073  def test_assert_dataclass_fails_assert_dict_fails_multiple_fields(self):
2074    a = _ExampleDataclass(comparable='a', not_comparable='b', comparable2='c')
2075    b = _ExampleDataclass(comparable='c', not_comparable='d', comparable2='e')
2076
2077    message = textwrap.dedent("""\
2078        _ExampleDataclass(comparable='a', not_comparable='b', comparable2='c') != _ExampleDataclass(comparable='c', not_comparable='d', comparable2='e')
2079        Fields that differ:
2080        comparable: 'a' != 'c'
2081        comparable2: 'c' != 'e'""")
2082    with self.assertRaisesWithLiteralMatch(AssertionError, message):
2083      self.assertDataclassEqual(a, b)
2084
2085
2086class GetCommandStringTest(parameterized.TestCase):
2087
2088  @parameterized.parameters(
2089      ([], '', ''),
2090      ([''], "''", ''),
2091      (['command', 'arg-0'], "'command' 'arg-0'", 'command arg-0'),
2092      ([u'command', u'arg-0'], "'command' 'arg-0'", u'command arg-0'),
2093      (["foo'bar"], "'foo'\"'\"'bar'", "foo'bar"),
2094      (['foo"bar'], "'foo\"bar'", 'foo"bar'),
2095      ('command arg-0', 'command arg-0', 'command arg-0'),
2096      (u'command arg-0', 'command arg-0', 'command arg-0'))
2097  def test_get_command_string(
2098      self, command, expected_non_windows, expected_windows):
2099    expected = expected_windows if os.name == 'nt' else expected_non_windows
2100    self.assertEqual(expected, absltest.get_command_string(command))
2101
2102
2103class TempFileTest(BaseTestCase):
2104
2105  def assert_dir_exists(self, temp_dir):
2106    path = temp_dir.full_path
2107    self.assertTrue(os.path.exists(path), 'Dir {} does not exist'.format(path))
2108    self.assertTrue(os.path.isdir(path),
2109                    'Path {} exists, but is not a directory'.format(path))
2110
2111  def assert_file_exists(self, temp_file, expected_content=b''):
2112    path = temp_file.full_path
2113    self.assertTrue(os.path.exists(path), 'File {} does not exist'.format(path))
2114    self.assertTrue(os.path.isfile(path),
2115                    'Path {} exists, but is not a file'.format(path))
2116
2117    mode = 'rb' if isinstance(expected_content, bytes) else 'rt'
2118    with io.open(path, mode) as fp:
2119      actual = fp.read()
2120    self.assertEqual(expected_content, actual)
2121
2122  def run_tempfile_helper(self, cleanup, expected_paths):
2123    tmpdir = self.create_tempdir('helper-test-temp-dir')
2124    env = {
2125        'ABSLTEST_TEST_HELPER_TEMPFILE_CLEANUP': cleanup,
2126        'TEST_TMPDIR': tmpdir.full_path,
2127        }
2128    stdout, stderr, _ = self.run_helper(
2129        0, ['TempFileHelperTest'], env, expect_success=False
2130    )
2131    output = ('\n=== Helper output ===\n'
2132              '----- stdout -----\n{}\n'
2133              '----- end stdout -----\n'
2134              '----- stderr -----\n{}\n'
2135              '----- end stderr -----\n'
2136              '===== end helper output =====').format(stdout, stderr)
2137    self.assertIn('test_failure', stderr, output)
2138
2139    # Adjust paths to match on Windows
2140    expected_paths = {path.replace('/', os.sep) for path in expected_paths}
2141
2142    actual = {
2143        os.path.relpath(f, tmpdir.full_path)
2144        for f in _listdir_recursive(tmpdir.full_path)
2145        if f != tmpdir.full_path
2146    }
2147    self.assertEqual(expected_paths, actual, output)
2148
2149  def test_create_file_pre_existing_readonly(self):
2150    first = self.create_tempfile('foo', content='first')
2151    os.chmod(first.full_path, 0o444)
2152    second = self.create_tempfile('foo', content='second')
2153    self.assertEqual('second', first.read_text())
2154    self.assertEqual('second', second.read_text())
2155
2156  def test_create_file_fails_cleanup(self):
2157    path = self.create_tempfile().full_path
2158    # Removing the write bit from the file makes it undeletable on Windows.
2159    os.chmod(path, 0)
2160    # Removing the write bit from the whole directory makes all contained files
2161    # undeletable on unix. We also need it to be exec so that os.path.isfile
2162    # returns true, and we reach the buggy branch.
2163    os.chmod(os.path.dirname(path), stat.S_IEXEC)
2164    # The test should pass, even though that file cannot be deleted in teardown.
2165
2166  def test_temp_file_path_like(self):
2167    tempdir = self.create_tempdir('foo')
2168    tempfile_ = tempdir.create_file('bar')
2169
2170    self.assertEqual(tempfile_.read_text(), pathlib.Path(tempfile_).read_text())
2171    # assertIsInstance causes the types to be narrowed, so calling create_file
2172    # and read_text() must be done before these assertions to avoid type errors.
2173    self.assertIsInstance(tempdir, os.PathLike)
2174    self.assertIsInstance(tempfile_, os.PathLike)
2175
2176  def test_unnamed(self):
2177    td = self.create_tempdir()
2178    self.assert_dir_exists(td)
2179
2180    tdf = td.create_file()
2181    self.assert_file_exists(tdf)
2182
2183    tdd = td.mkdir()
2184    self.assert_dir_exists(tdd)
2185
2186    tf = self.create_tempfile()
2187    self.assert_file_exists(tf)
2188
2189  def test_named(self):
2190    td = self.create_tempdir('d')
2191    self.assert_dir_exists(td)
2192
2193    tdf = td.create_file('df')
2194    self.assert_file_exists(tdf)
2195
2196    tdd = td.mkdir('dd')
2197    self.assert_dir_exists(tdd)
2198
2199    tf = self.create_tempfile('f')
2200    self.assert_file_exists(tf)
2201
2202  def test_nested_paths(self):
2203    td = self.create_tempdir('d1/d2')
2204    self.assert_dir_exists(td)
2205
2206    tdf = td.create_file('df1/df2')
2207    self.assert_file_exists(tdf)
2208
2209    tdd = td.mkdir('dd1/dd2')
2210    self.assert_dir_exists(tdd)
2211
2212    tf = self.create_tempfile('f1/f2')
2213    self.assert_file_exists(tf)
2214
2215  def test_tempdir_create_file(self):
2216    td = self.create_tempdir()
2217    td.create_file(content='text')
2218
2219  def test_tempfile_text(self):
2220    tf = self.create_tempfile(content='text')
2221    self.assert_file_exists(tf, 'text')
2222    self.assertEqual('text', tf.read_text())
2223
2224    with tf.open_text() as fp:
2225      self.assertEqual('text', fp.read())
2226
2227    with tf.open_text('w') as fp:
2228      fp.write(u'text-from-open-write')
2229    self.assertEqual('text-from-open-write', tf.read_text())
2230
2231    tf.write_text('text-from-write-text')
2232    self.assertEqual('text-from-write-text', tf.read_text())
2233
2234  def test_tempfile_bytes(self):
2235    tf = self.create_tempfile(content=b'\x00\x01\x02')
2236    self.assert_file_exists(tf, b'\x00\x01\x02')
2237    self.assertEqual(b'\x00\x01\x02', tf.read_bytes())
2238
2239    with tf.open_bytes() as fp:
2240      self.assertEqual(b'\x00\x01\x02', fp.read())
2241
2242    with tf.open_bytes('wb') as fp:
2243      fp.write(b'\x03')
2244    self.assertEqual(b'\x03', tf.read_bytes())
2245
2246    tf.write_bytes(b'\x04')
2247    self.assertEqual(b'\x04', tf.read_bytes())
2248
2249  def test_tempdir_same_name(self):
2250    """Make sure the same directory name can be used."""
2251    td1 = self.create_tempdir('foo')
2252    td2 = self.create_tempdir('foo')
2253    self.assert_dir_exists(td1)
2254    self.assert_dir_exists(td2)
2255
2256  def test_tempfile_cleanup_success(self):
2257    expected = {
2258        'TempFileHelperTest',
2259        'TempFileHelperTest/test_failure',
2260        'TempFileHelperTest/test_failure/failure',
2261        'TempFileHelperTest/test_success',
2262        'TempFileHelperTest/test_subtest_failure',
2263        'TempFileHelperTest/test_subtest_failure/parent',
2264        'TempFileHelperTest/test_subtest_failure/successful_child',
2265        'TempFileHelperTest/test_subtest_failure/failed_child',
2266        'TempFileHelperTest/test_subtest_success',
2267    }
2268    self.run_tempfile_helper('SUCCESS', expected)
2269
2270  def test_tempfile_cleanup_always(self):
2271    expected = {
2272        'TempFileHelperTest',
2273        'TempFileHelperTest/test_failure',
2274        'TempFileHelperTest/test_success',
2275        'TempFileHelperTest/test_subtest_failure',
2276        'TempFileHelperTest/test_subtest_success',
2277    }
2278    self.run_tempfile_helper('ALWAYS', expected)
2279
2280  def test_tempfile_cleanup_off(self):
2281    expected = {
2282        'TempFileHelperTest',
2283        'TempFileHelperTest/test_failure',
2284        'TempFileHelperTest/test_failure/failure',
2285        'TempFileHelperTest/test_success',
2286        'TempFileHelperTest/test_success/success',
2287        'TempFileHelperTest/test_subtest_failure',
2288        'TempFileHelperTest/test_subtest_failure/parent',
2289        'TempFileHelperTest/test_subtest_failure/successful_child',
2290        'TempFileHelperTest/test_subtest_failure/failed_child',
2291        'TempFileHelperTest/test_subtest_success',
2292        'TempFileHelperTest/test_subtest_success/parent',
2293        'TempFileHelperTest/test_subtest_success/child0',
2294        'TempFileHelperTest/test_subtest_success/child1',
2295    }
2296    self.run_tempfile_helper('OFF', expected)
2297
2298
2299class SkipClassTest(absltest.TestCase):
2300
2301  def test_incorrect_decorator_call(self):
2302    with self.assertRaises(TypeError):
2303
2304      # Disabling type checking because pytype correctly picks up that
2305      # @absltest.skipThisClass is being used incorrectly.
2306      # pytype: disable=wrong-arg-types
2307      @absltest.skipThisClass
2308      class Test(absltest.TestCase):  # pylint: disable=unused-variable
2309        pass
2310      # pytype: enable=wrong-arg-types
2311
2312  def test_incorrect_decorator_subclass(self):
2313    with self.assertRaises(TypeError):
2314
2315      @absltest.skipThisClass('reason')
2316      def test_method():  # pylint: disable=unused-variable
2317        pass
2318
2319  def test_correct_decorator_class(self):
2320
2321    @absltest.skipThisClass('reason')
2322    class Test(absltest.TestCase):
2323      pass
2324
2325    with self.assertRaises(absltest.SkipTest):
2326      Test.setUpClass()
2327
2328  def test_correct_decorator_subclass(self):
2329
2330    @absltest.skipThisClass('reason')
2331    class Test(absltest.TestCase):
2332      pass
2333
2334    class Subclass(Test):
2335      pass
2336
2337    with self.subTest('Base class should be skipped'):
2338      with self.assertRaises(absltest.SkipTest):
2339        Test.setUpClass()
2340
2341    with self.subTest('Subclass should not be skipped'):
2342      Subclass.setUpClass()  # should not raise.
2343
2344  def test_setup(self):
2345
2346    @absltest.skipThisClass('reason')
2347    class Test(absltest.TestCase):
2348
2349      @classmethod
2350      def setUpClass(cls):
2351        super(Test, cls).setUpClass()
2352        cls.foo = 1
2353
2354    class Subclass(Test):
2355      pass
2356
2357    Subclass.setUpClass()
2358    self.assertEqual(Subclass.foo, 1)
2359
2360  def test_setup_chain(self):
2361
2362    @absltest.skipThisClass('reason')
2363    class BaseTest(absltest.TestCase):
2364
2365      foo: int
2366
2367      @classmethod
2368      def setUpClass(cls):
2369        super(BaseTest, cls).setUpClass()
2370        cls.foo = 1
2371
2372    @absltest.skipThisClass('reason')
2373    class SecondBaseTest(BaseTest):
2374
2375      @classmethod
2376      def setUpClass(cls):
2377        super(SecondBaseTest, cls).setUpClass()
2378        cls.bar = 2
2379
2380    class Subclass(SecondBaseTest):
2381      pass
2382
2383    Subclass.setUpClass()
2384    self.assertEqual(Subclass.foo, 1)
2385    self.assertEqual(Subclass.bar, 2)
2386
2387  def test_setup_args(self):
2388
2389    @absltest.skipThisClass('reason')
2390    class Test(absltest.TestCase):
2391      foo: str
2392      bar: Optional[str]
2393
2394      @classmethod
2395      def setUpClass(cls, foo, bar=None):
2396        super(Test, cls).setUpClass()
2397        cls.foo = foo
2398        cls.bar = bar
2399
2400    class Subclass(Test):
2401
2402      @classmethod
2403      def setUpClass(cls):
2404        super(Subclass, cls).setUpClass('foo', bar='baz')
2405
2406    Subclass.setUpClass()
2407    self.assertEqual(Subclass.foo, 'foo')
2408    self.assertEqual(Subclass.bar, 'baz')
2409
2410  def test_setup_multiple_inheritance(self):
2411
2412    # Test that skipping this class doesn't break the MRO chain and stop
2413    # RequiredBase.setUpClass from running.
2414    @absltest.skipThisClass('reason')
2415    class Left(absltest.TestCase):
2416      pass
2417
2418    class RequiredBase(absltest.TestCase):
2419      foo: str
2420
2421      @classmethod
2422      def setUpClass(cls):
2423        super(RequiredBase, cls).setUpClass()
2424        cls.foo = 'foo'
2425
2426    class Right(RequiredBase):
2427
2428      @classmethod
2429      def setUpClass(cls):
2430        super(Right, cls).setUpClass()
2431
2432    # Test will fail unless Left.setUpClass() follows mro properly
2433    # Right.setUpClass()
2434    class Subclass(Left, Right):
2435
2436      @classmethod
2437      def setUpClass(cls):
2438        super(Subclass, cls).setUpClass()
2439
2440    class Test(Subclass):
2441      pass
2442
2443    Test.setUpClass()
2444    self.assertEqual(Test.foo, 'foo')
2445
2446  def test_skip_class(self):
2447
2448    @absltest.skipThisClass('reason')
2449    class BaseTest(absltest.TestCase):
2450
2451      def test_foo(self):
2452        _ = 1 / 0
2453
2454    class Test(BaseTest):
2455
2456      def test_foo(self):
2457        self.assertEqual(1, 1)
2458
2459    with self.subTest('base class'):
2460      ts = unittest.makeSuite(BaseTest)
2461      self.assertEqual(1, ts.countTestCases())
2462
2463      res = unittest.TestResult()
2464      ts.run(res)
2465      self.assertTrue(res.wasSuccessful())
2466      self.assertLen(res.skipped, 1)
2467      self.assertEqual(0, res.testsRun)
2468      self.assertEmpty(res.failures)
2469      self.assertEmpty(res.errors)
2470
2471    with self.subTest('real test'):
2472      ts = unittest.makeSuite(Test)
2473      self.assertEqual(1, ts.countTestCases())
2474
2475      res = unittest.TestResult()
2476      ts.run(res)
2477      self.assertTrue(res.wasSuccessful())
2478      self.assertEqual(1, res.testsRun)
2479      self.assertEmpty(res.skipped)
2480      self.assertEmpty(res.failures)
2481      self.assertEmpty(res.errors)
2482
2483  def test_skip_class_unittest(self):
2484
2485    @absltest.skipThisClass('reason')
2486    class Test(unittest.TestCase):  # note: unittest not absltest
2487
2488      def test_foo(self):
2489        _ = 1 / 0
2490
2491    ts = unittest.makeSuite(Test)
2492    self.assertEqual(1, ts.countTestCases())
2493
2494    res = unittest.TestResult()
2495    ts.run(res)
2496    self.assertTrue(res.wasSuccessful())
2497    self.assertLen(res.skipped, 1)
2498    self.assertEqual(0, res.testsRun)
2499    self.assertEmpty(res.failures)
2500    self.assertEmpty(res.errors)
2501
2502
2503class ExitCodeTest(BaseTestCase):
2504
2505  def test_exits_5_when_no_tests(self):
2506    expect_success = sys.version_info < (3, 12)
2507    _, _, exit_code = self.run_helper(
2508        None,
2509        [],
2510        {},
2511        expect_success=expect_success,
2512        helper_name='absltest_test_helper_skipped',
2513    )
2514    if not expect_success:
2515      self.assertEqual(exit_code, 5)
2516
2517  def test_exits_5_when_all_skipped(self):
2518    self.run_helper(
2519        None,
2520        [],
2521        {'ABSLTEST_TEST_HELPER_DEFINE_CLASS': '1'},
2522        expect_success=True,
2523        helper_name='absltest_test_helper_skipped',
2524    )
2525
2526
2527def _listdir_recursive(path):
2528  for dirname, _, filenames in os.walk(path):
2529    yield dirname
2530    for filename in filenames:
2531      yield os.path.join(dirname, filename)
2532
2533
2534def _env_for_command_tests():
2535  if os.name == 'nt' and 'PATH' in os.environ:
2536    # get_command_stderr and assertCommandXXX don't inherit environment
2537    # variables by default. This makes sure msys commands can be found on
2538    # Windows.
2539    return {'PATH': os.environ['PATH']}
2540  else:
2541    return None
2542
2543
2544if __name__ == '__main__':
2545  absltest.main()
2546