Repository: google/python-fire
File: fire/fire_test.py (Python)

Code before:


class FireTest(testutils.BaseTestCase):

  def testFire(self):
    with mock.patch.object(sys, 'argv', ['progname']):
      fire.Fire(tc.Empty)
      fire.Fire(tc.OldStyleEmpty)
      fire.Fire(tc.WithInit)
    self.assertEqual(fire.Fire(tc.NoDefaults, 'double 2'), 4)
    self.assertEqual(fire.Fire(tc.NoDefaults, 'triple 4'), 12)
    self.assertEqual(fire.Fire(tc.WithDefaults, 'double 2'), 4)
    self.assertEqual(fire.Fire(tc.WithDefaults, 'triple 4'), 12)
    self.assertEqual(fire.Fire(tc.OldStyleWithDefaults, 'double 2'), 4)
    self.assertEqual(fire.Fire(tc.OldStyleWithDefaults, 'triple 4'), 12)

  def testFireDefaultBaseName(self):
    with mock.patch.object(sys, 'argv',
                           ['/github/python-fire/fire/base_filename.py']):
      # positive case
      with self.assertOutputMatches(stdout='Usage:       base_filename.py',
                                    stderr=None):
        fire.Fire(tc.Empty)
      # negative case
      with self.assertRaises(AssertionError):
        with self.assertOutputMatches(stdout='Usage:fire/base_filename.py',
                                      stderr=None):
          fire.Fire(tc.Empty)

  def testFireNoArgs(self):
    self.assertEqual(fire.Fire(tc.MixedDefaults, 'ten'), 10)

  def testFireExceptions(self):
    # Exceptions of Fire are printed to stderr and a FireExit is raised.
    with self.assertRaisesFireExit(2):
      fire.Fire(tc.Empty, 'nomethod')  # Member doesn't exist.
    with self.assertRaisesFireExit(2):
      fire.Fire(tc.NoDefaults, 'double')  # Missing argument.
    with self.assertRaisesFireExit(2):
      fire.Fire(tc.TypedProperties, 'delta x')  # Missing key.

    # Exceptions of the target components are still raised.
    with self.assertRaises(ZeroDivisionError):
      fire.Fire(tc.NumberDefaults, 'reciprocal 0.0')

  def testFireNamedArgs(self):
    self.assertEqual(fire.Fire(tc.WithDefaults, 'double --count 5'), 10)
    self.assertEqual(fire.Fire(tc.WithDefaults, 'triple --count 5'), 15)
    self.assertEqual(fire.Fire(tc.OldStyleWithDefaults, 'double --count 5'), 10)
    self.assertEqual(fire.Fire(tc.OldStyleWithDefaults, 'triple --count 5'), 15)


Review comment (bug):
1. In the negative case I don't think the string would be `'Usage:fire/base_filename.py'`, it would probably be
```
'Usage:       fire/base_filename.py'
```
We can either use \s+ to be invariant to the number of spaces. Or, in the negative case, we can drop 'Usage:' altogether to assert that 'fire/base_filename' doesn't appear at all. Or (my preferred option) we can drop the negative case altogether, since the positive case already asserts that the full path isn't showing up in the usage section.

2. I think it's an awkward construction to put assertOutputMatches inside of an assertRaises. (E.g. what if a different assertion fails (not that there is one) inside the assertOutputMatches context?) If we ever do want this, we'll want to make a helper 'assertNotOutputMatches` or something like that.

---------

I think we can safely drop the negative case altogether since we're already asserting there's space before 'base_filename' in the positive case.

Code after:
import six


class FireTest(testutils.BaseTestCase):

  def testFire(self):
    with mock.patch.object(sys, 'argv', ['progname']):
      fire.Fire(tc.Empty)
      fire.Fire(tc.OldStyleEmpty)
      fire.Fire(tc.WithInit)
    self.assertEqual(fire.Fire(tc.NoDefaults, 'double 2'), 4)
    self.assertEqual(fire.Fire(tc.NoDefaults, 'triple 4'), 12)
    self.assertEqual(fire.Fire(tc.WithDefaults, 'double 2'), 4)
    self.assertEqual(fire.Fire(tc.WithDefaults, 'triple 4'), 12)
    self.assertEqual(fire.Fire(tc.OldStyleWithDefaults, 'double 2'), 4)
    self.assertEqual(fire.Fire(tc.OldStyleWithDefaults, 'triple 4'), 12)

  def testFireDefaultBaseName(self):
    with mock.patch.object(sys, 'argv',
                           [os.path.join('python-fire', 'fire',
                                         'base_filename.py')]):
      # positive case
      with self.assertOutputMatches(stdout='Usage:       base_filename.py',
                                    stderr=None):
        fire.Fire(tc.Empty)

  def testFireNoArgs(self):
    self.assertEqual(fire.Fire(tc.MixedDefaults, 'ten'), 10)

  def testFireExceptions(self):
    # Exceptions of Fire are printed to stderr and a FireExit is raised.
    with self.assertRaisesFireExit(2):
      fire.Fire(tc.Empty, 'nomethod')  # Member doesn't exist.
    with self.assertRaisesFireExit(2):
      fire.Fire(tc.NoDefaults, 'double')  # Missing argument.
    with self.assertRaisesFireExit(2):
      fire.Fire(tc.TypedProperties, 'delta x')  # Missing key.

    # Exceptions of the target components are still raised.
    with self.assertRaises(ZeroDivisionError):
      fire.Fire(tc.NumberDefaults, 'reciprocal 0.0')

  def testFireNamedArgs(self):
    self.assertEqual(fire.Fire(tc.WithDefaults, 'double --count 5'), 10)
    self.assertEqual(fire.Fire(tc.WithDefaults, 'triple --count 5'), 15)
    self.assertEqual(fire.Fire(tc.OldStyleWithDefaults, 'double --count 5'), 10)
    self.assertEqual(fire.Fire(tc.OldStyleWithDefaults, 'triple --count 5'), 15)

  def testFireNamedArgsWithEquals(self):
    self.assertEqual(fire.Fire(tc.WithDefaults, 'double --count=5'), 10)
    self.assertEqual(fire.Fire(tc.WithDefaults, 'triple --count=5'), 15)