Esempio n. 1
0
class TestGetManager(TestCase):
    def setUp(self):
        self.tty = MockTTY()

    def tearDown(self):
        self.tty.close()

    def test_get_manager_tty(self):

        # stdout is attached to a tty
        with redirect_output('stdout', self.tty.stdout):
            self.assertTrue(sys.stdout.isatty())
            manager = _manager.get_manager(unit='knights')
            self.assertIsInstance(manager, _manager.Manager)
            self.assertTrue('unit' in manager.defaults)
            self.assertTrue('enabled' in manager.defaults)
            self.assertTrue(manager.enabled)
            self.assertTrue(manager.defaults['enabled'])

    @unittest.skipIf(STDOUT_NO_FD, 'No file descriptor for stdout')
    def test_get_manager_notty(self):

        # stdout is not attached to a tty
        with redirect_output('stdout', OUTPUT):
            self.assertFalse(sys.stdout.isatty())
            manager = _manager.get_manager(unit='knights')
            self.assertIsInstance(manager, _manager.Manager)
            self.assertTrue('unit' in manager.defaults)
            self.assertFalse(manager.enabled)
            self.assertTrue('enabled' in manager.defaults)
            self.assertFalse(manager.defaults['enabled'])
Esempio n. 2
0
    def test_at_exit(self):

        tty = MockTTY()

        with mock.patch('%s.reset' % TERMINAL) as reset:
            manager = _manager.Manager(stream=tty.stdout, counter_class=MockCounter)
            term = manager.term

            # process_exit is False
            manager._at_exit()
            self.assertFalse(reset.called)
            # No output
            tty.stdout.write('X\n')
            self.assertEqual(tty.stdread.readline(), 'X\n')

            # process_exit is True, set_scroll False
            manager.process_exit = True
            manager.set_scroll = False
            manager._at_exit()
            self.assertFalse(reset.called)
            self.assertEqual(tty.stdread.readline(), term.move(25, 0) + term.cud1)

            # process_exit is True, set_scroll True
            manager.set_scroll = True
            manager._at_exit()
            self.assertEqual(reset.call_count, 1)
            self.assertEqual(tty.stdread.readline(), term.cud1)

            tty.close()
            manager._at_exit()
 def setUp(self):
     self.tty = MockTTY()
     self.manager = MockManager(stream=self.tty.stdout)
     self.parent = Counter(total=10,
                           desc='Test',
                           unit='ticks',
                           manager=self.manager)
 def setUp(self):
     self.tty = MockTTY()
     self.manager = MockManager(stream=self.tty.stdout)
     self.ctr = Counter(total=10,
                        desc='Test',
                        unit='ticks',
                        manager=self.manager)
     self.manager.counters[self.ctr] = 3
     self.output = r'Test   0%\|[ ]+ \|  0/10 \[00:0\d<\?, 0.00 ticks/s\]'
Esempio n. 5
0
class TestTerminal(TestCase):
    """
    This is hard to test, so, for most tests, we'll just
    make sure the codes get passed through a tty
    """

    def setUp(self):
        self.tty = MockTTY()
        self.terminal = _terminal.Terminal(stream=self.tty.stdout, kind='xterm-256color')

    def tearDown(self):
        self.tty.close()

    def test_caching(self):
        """
        Make sure cached values are held.
        Return values aren't accurate for blessed, but are sufficient for this test
        """

        handw = 'enlighten._terminal._Terminal._height_and_width'

        with mock.patch(handw, return_value=(1, 2)):
            self.assertEqual(self.terminal._height_and_width(), (1, 2))

        with mock.patch(handw, return_value=(5, 6)):
            self.assertEqual(self.terminal._height_and_width(), (1, 2))
            self.terminal.clear_cache()
            self.assertEqual(self.terminal._height_and_width(), (5, 6))

    def test_reset(self):
        self.terminal.reset()
        self.tty.stdout.write(u'X\n')
        self.assertEqual(self.tty.stdread.readline(),
                         self.terminal.normal_cursor + self.terminal.csr(0, 24) +
                         self.terminal.move(25, 0) + 'X\n')

    def test_feed(self):

        self.terminal.feed()
        self.assertEqual(self.tty.stdread.readline(), self.terminal.cud1)

    def test_change_scroll(self):

        self.terminal.change_scroll(4)
        self.tty.stdout.write(u'X\n')
        self.assertEqual(self.tty.stdread.readline(),
                         self.terminal.hide_cursor + self.terminal.csr(0, 4) +
                         self.terminal.move(4, 0) + 'X\n')

    def test_move_to(self):

        self.terminal.move_to(5, 10)
        self.tty.stdout.write(u'X\n')
        self.assertEqual(self.tty.stdread.readline(),
                         self.terminal.move(10, 5) + 'X\n')
Esempio n. 6
0
    def test_at_exit(self):

        tty = MockTTY()

        with mock.patch('%s.reset' % TERMINAL) as reset:
            with mock.patch.object(tty, 'stdout',
                                   wraps=tty.stdout) as mockstdout:
                manager = _manager.Manager(stream=tty.stdout,
                                           counter_class=MockCounter)
                term = manager.term

                # process_exit is False
                manager._at_exit()
                self.assertFalse(reset.called)
                self.assertFalse(mockstdout.flush.called)
                # No output
                tty.stdout.write(u'X\n')
                self.assertEqual(tty.stdread.readline(), 'X\n')

                # process_exit is True, set_scroll False
                manager.process_exit = True
                manager.set_scroll = False
                manager._at_exit()
                self.assertFalse(reset.called)
                self.assertEqual(mockstdout.flush.call_count, 1)
                self.assertEqual(tty.stdread.readline(),
                                 term.move(25, 0) + term.cud1)

                # process_exit is True, set_scroll True
                manager.set_scroll = True
                manager._at_exit()
                self.assertEqual(reset.call_count, 1)
                self.assertEqual(mockstdout.flush.call_count, 2)
                self.assertEqual(tty.stdread.readline(), term.cud1)

                # Ensure companion stream gets flushed
                manager.companion_stream = tty.stdout
                manager._at_exit()
                self.assertEqual(reset.call_count, 2)
                self.assertEqual(mockstdout.flush.call_count, 4)
                self.assertEqual(tty.stdread.readline(), term.cud1)

                term = manager.term

                # Ensure no errors if tty closes before _at_exit is called
                tty.close()
                manager._at_exit()
Esempio n. 7
0
    def test_at_exit(self):

        tty = MockTTY()

        try:
            with mock.patch.object(tty, 'stdout', wraps=tty.stdout) as mockstdout:
                manager = enlighten.Manager(stream=tty.stdout, counter_class=MockCounter)
                term = manager.term
                reset = (term.normal_cursor +
                         term.csr(0, term.height - 1) +
                         term.move(term.height, 0))

                # process_exit is False
                manager._at_exit()
                self.assertFalse(mockstdout.flush.called)
                # No output
                tty.stdout.write(u'X\n')
                self.assertEqual(tty.stdread.readline(), 'X\n')

                # process_exit is True, set_scroll False
                manager.process_exit = True
                manager.set_scroll = False
                manager._at_exit()
                self.assertEqual(mockstdout.flush.call_count, 1)
                self.assertEqual(tty.stdread.readline(), term.move(25, 0) + term.cud1)

                # process_exit is True, set_scroll True
                manager.set_scroll = True
                manager._at_exit()
                self.assertEqual(mockstdout.flush.call_count, 2)
                self.assertEqual(tty.stdread.readline(), reset + term.cud1)

                # Ensure companion stream gets flushed
                manager.companion_stream = tty.stdout
                manager._at_exit()
                self.assertEqual(mockstdout.flush.call_count, 4)
                self.assertEqual(tty.stdread.readline(), reset + term.cud1)

                term = manager.term

        finally:
            # Ensure no errors if tty closes before _at_exit is called
            tty.close()
            manager._at_exit()
class TestSubCounter(TestCase):
    """
    Test the BaseCounter class
    """
    def setUp(self):
        self.tty = MockTTY()
        self.manager = MockManager(stream=self.tty.stdout)
        self.parent = Counter(total=10,
                              desc='Test',
                              unit='ticks',
                              manager=self.manager)

    def tearDown(self):
        self.tty.close()

    def test_init(self):
        """Ensure initial values are set"""
        counter = enlighten._counter.SubCounter(self.parent)
        self.assertIsNone(counter.color)
        self.assertEqual(counter.count, 0)
        self.assertFalse(counter.all_fields)
        self.assertIs(counter.parent, self.parent)
        self.assertIs(counter.manager, self.manager)

        self.parent.count = 4
        counter = enlighten._counter.SubCounter(self.parent,
                                                color='green',
                                                count=4,
                                                all_fields=True)
        self.assertEqual(counter.color, 'green')
        self.assertEqual(counter.count, 4)
        self.assertTrue(counter.all_fields)

        with self.assertRaisesRegex(ValueError, 'Invalid count: 6'):
            counter = enlighten._counter.SubCounter(self.parent, count=6)

    def test_update(self):
        """Increment and update parent"""
        counter = enlighten._counter.SubCounter(self.parent)
        self.assertEqual(counter.count, 0)
        self.assertEqual(self.parent.count, 0)
        counter.update()
        self.assertEqual(counter.count, 1)
        self.assertEqual(self.parent.count, 1)
        self.parent.update(3)
        self.assertEqual(counter.count, 1)
        self.assertEqual(self.parent.count, 4)
        counter.update(2)
        self.assertEqual(counter.count, 3)
        self.assertEqual(self.parent.count, 6)

    def test_update_from_invalid_source(self):
        """Must be peer or parent"""
        counter = enlighten._counter.SubCounter(self.parent)

        notparent = Counter(manager=self.manager)
        with self.assertRaisesRegex(ValueError,
                                    'source must be parent or peer'):
            counter.update_from(notparent)

        notpeer = enlighten._counter.SubCounter(notparent)
        with self.assertRaisesRegex(ValueError,
                                    'source must be parent or peer'):
            counter.update_from(notpeer)

    def test_update_from_invalid_incr(self):
        """Increment can't make source negative"""
        counter = enlighten._counter.SubCounter(self.parent)

        with self.assertRaisesRegex(ValueError, 'Invalid increment: 1'):
            counter.update_from(self.parent)

        self.parent.count = 4
        peer = enlighten._counter.SubCounter(self.parent, count=3)
        self.parent._subcounters.append(peer)

        with self.assertRaisesRegex(ValueError, 'Invalid increment: 4'):
            counter.update_from(peer, 4)

        with self.assertRaisesRegex(ValueError, 'Invalid increment: 2'):
            counter.update_from(self.parent, 2)

    def test_update_from_parent(self):
        """
        subcounter should gain increment, parent should remain unchanged
        """
        counter = enlighten._counter.SubCounter(self.parent)
        self.parent.count = 4

        with mock.patch.object(self.parent, 'update',
                               wraps=self.parent.update) as update:
            counter.update_from(self.parent)
            update.assert_called_with(0, False)
            self.assertEqual(self.parent.count, 4)
            self.assertEqual(counter.count, 1)

            counter.update_from(self.parent, 2)
            update.assert_called_with(0, False)
            self.assertEqual(self.parent.count, 4)
            self.assertEqual(counter.count, 3)

    def test_update_from_peer(self):
        """
        Peer should lose increment, subcounter should gain increment
        """
        counter = enlighten._counter.SubCounter(self.parent)
        self.parent.count = 6
        peer = enlighten._counter.SubCounter(self.parent, count=4)

        with mock.patch.object(self.parent, 'update',
                               wraps=self.parent.update) as update:
            counter.update_from(peer)
            update.assert_called_with(0, False)
            self.assertEqual(self.parent.count, 6)
            self.assertEqual(counter.count, 1)
            self.assertEqual(peer.count, 3)

            counter.update_from(peer, 3)
            update.assert_called_with(0, False)
            self.assertEqual(self.parent.count, 6)
            self.assertEqual(counter.count, 4)
            self.assertEqual(peer.count, 0)
Esempio n. 9
0
class TestCounter(TestCase):
    """
    Test the Counter classes
    We default to using enlighten.Counter and only use enlighten._counter.Counter when necessary
    """
    def setUp(self):
        self.tty = MockTTY()
        self.manager = MockManager(stream=self.tty.stdout)
        self.ctr = Counter(total=10,
                           desc='Test',
                           unit='ticks',
                           manager=self.manager)
        self.manager.counters[self.ctr] = 3
        self.output = r'Test   0%\|[ ]+ \|  0/10 \[00:0\d<\?, 0.00 ticks/s\]'

    def tearDown(self):
        self.tty.close()

    def test_no_manager(self):
        """Raise an error if there is no manager specified"""
        with self.assertRaisesRegex(TypeError, 'manager must be specified'):
            enlighten._counter.Counter()
        enlighten._counter.Counter(manager=self.manager)

    def test_increment(self):
        counter = MockCounter(total=100, min_delta=0, manager=self.manager)
        counter.update()
        self.assertEqual(counter.count, 1)
        counter.update(5)
        self.assertEqual(counter.count, 6)

    def test_enabled(self):
        counter = MockCounter(total=100, min_delta=0, manager=self.manager)
        counter.update()
        self.assertEqual(counter.output, [1])
        counter.update()
        self.assertEqual(counter.output, [1, 2])
        counter.enabled = False
        counter.update()
        self.assertEqual(counter.output, [1, 2])

    def test_delta(self):
        counter = MockCounter(total=100, min_delta=0, manager=self.manager)
        counter.update()
        self.assertEqual(counter.output, [1])
        counter.update()
        self.assertEqual(counter.output, [1, 2])
        counter.min_delta = 500
        counter.update()
        self.assertEqual(counter.output, [1, 2])
        counter.min_delta = .01
        time.sleep(.01)
        counter.update()
        self.assertEqual(counter.output, [1, 2, 4])

    def test_force(self):
        counter = MockCounter(total=100, min_delta=0, manager=self.manager)
        counter.update()
        self.assertEqual(counter.output, [1])
        counter.min_delta = 500
        counter.update()
        self.assertEqual(counter.output, [1])
        counter.update(force=True)
        self.assertEqual(counter.output, [1, 3])

    def test_refresh_total(self):
        counter = MockCounter(total=100, min_delta=0, manager=self.manager)
        counter.update()
        self.assertEqual(counter.output, [1])
        counter.min_delta = 500
        counter.update()
        self.assertEqual(counter.output, [1])
        counter.update(98)
        self.assertEqual(counter.output, [1, 100])

    def test_position(self):
        self.assertEqual(self.ctr.position, 3)

    def test_elapsed(self):
        ctr = self.ctr
        ctr.start = time.time() - 5.0
        ctr.last_update = ctr.start + 3.0

        self.assertEqual(int(ctr.elapsed), 5)

        # Clock stops running when total is reached
        ctr.count = ctr.total
        self.assertEqual(int(ctr.elapsed), 3)

    def test_refresh(self):
        self.ctr.refresh()
        self.assertRegex(
            self.manager.output[0],
            r'write\(output=%s, flush=True, position=3\)' % self.output)

        self.manager.output = []
        self.ctr.refresh(flush=False)
        self.assertRegex(
            self.manager.output[0],
            r'write\(output=%s, flush=False, position=3\)' % self.output)

        self.manager.output = []
        self.ctr.enabled = False
        self.ctr.refresh()
        self.assertEqual(len(self.manager.output), 0)

    def test_clear(self):
        self.ctr.clear()
        self.assertRegex(self.manager.output[0],
                         r'write\(output=, flush=True, position=3\)')

        self.manager.output = []
        self.ctr.clear(flush=False)
        self.assertRegex(self.manager.output[0],
                         r'write\(output=, flush=False, position=3\)')

        self.manager.output = []
        self.ctr.enabled = False
        self.ctr.clear()
        self.assertEqual(len(self.manager.output), 0)

    def test_get_subcounter(self):
        self.ctr.count = 6
        subcounter1 = self.ctr.add_subcounter('green')
        subcounter2 = self.ctr.add_subcounter('red', all_fields=True)
        subcounter2.count = 4
        subcounter3 = self.ctr.add_subcounter('white',
                                              count=1,
                                              all_fields=True)

        subcounters, fields = self.ctr._get_subcounters(8)

        self.assertEqual(subcounters, [(subcounter1, 0.0), (subcounter2, 0.4),
                                       (subcounter3, 0.1)])
        self.assertEqual(
            fields, {
                'percentage_1': 0.0,
                'percentage_2': 40.0,
                'percentage_3': 10.0,
                'count_1': 0,
                'count_2': 4,
                'count_3': 1,
                'rate_2': 0.5,
                'eta_2': '00:12',
                'rate_3': 0.0,
                'eta_3': '?'
            })

        subcounters, fields = self.ctr._get_subcounters(0)
        self.assertEqual(subcounters, [(subcounter1, 0.0), (subcounter2, 0.4),
                                       (subcounter3, 0.1)])
        self.assertEqual(
            fields, {
                'percentage_1': 0.0,
                'percentage_2': 40.0,
                'percentage_3': 10.0,
                'count_1': 0,
                'count_2': 4,
                'count_3': 1,
                'rate_2': 0.0,
                'eta_2': '?',
                'rate_3': 0.0,
                'eta_3': '?'
            })

        self.ctr = Counter(total=0,
                           desc='Test',
                           unit='ticks',
                           manager=self.manager)
        subcounter1 = self.ctr.add_subcounter('red', all_fields=True)
        subcounters, fields = self.ctr._get_subcounters(8)
        self.assertEqual(subcounters, [(subcounter1, 0.0)])
        self.assertEqual(fields, {
            'percentage_1': 0.0,
            'count_1': 0,
            'rate_1': 0.0,
            'eta_1': '00:00'
        })

    def test_remove(self):
        self.ctr.leave = False
        self.assertTrue(self.ctr in self.manager.counters)

        self.ctr.close()
        self.assertRegex(
            self.manager.output[0],
            r'write\(output=%s, flush=True, position=3\)' % self.output)
        self.assertFalse(self.ctr in self.manager.counters)

        # If it runs again, it shouldn't throw an error
        self.ctr.close()

    def test_format_no_total(self):

        # No unit, No desc
        ctr = Counter(stream=self.tty.stdout, )
        self.assertRegex(ctr.format(width=80), r'0 \[00:0\d, 0.00/s\]')
        ctr.count = 50
        ctr.start = time.time() - 50
        self.assertRegex(ctr.format(width=80), r'50 \[00:5\d, \d.\d\d/s\]')

        # With unit and description
        ctr = Counter(stream=self.tty.stdout, desc='Test', unit='ticks')
        rtn = ctr.format(width=80)
        self.assertEqual(len(rtn), 80)
        self.assertRegex(rtn, r'Test 0 ticks \[00:0\d, 0.00 ticks/s\]')
        ctr.count = 50
        ctr.start = time.time() - 50
        rtn = ctr.format(width=80)
        self.assertEqual(len(rtn), 80)
        self.assertRegex(rtn, r'Test 50 ticks \[00:5\d, \d.\d\d ticks/s\]')

    def test_format_count_gt_total(self):
        """
        Counter should fall back to no-total format if count is greater than total
        """

        ctr = Counter(stream=self.tty.stdout,
                      total=10,
                      desc='Test',
                      unit='ticks')
        ctr.count = 50
        ctr.start = time.time() - 50
        rtn = ctr.format(width=80)
        self.assertEqual(len(rtn), 80)
        self.assertRegex(rtn, r'Test 50 ticks \[00:5\d, \d.\d\d ticks/s\]')

    def test_no_count(self):
        """
        Test for an empty counter
        """

        ctr = Counter(stream=self.tty.stdout,
                      total=10,
                      desc='Test',
                      unit='ticks')
        formatted = ctr.format(width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test   0%\|[ ]+ \|  0/10 \[00:0\d<\?, 0.00 ticks/s\]')

        # No unit, no description
        ctr = Counter(stream=self.tty.stdout, total=10)
        formatted = ctr.format(width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(formatted,
                         r'  0%\|[ ]+ \|  0/10 \[00:0\d<\?, 0.00/s\]')

    def test_full_bar(self):

        ctr = Counter(stream=self.tty.stdout,
                      total=10,
                      desc='Test',
                      unit='ticks')
        ctr.count = 10
        ctr.start = time.time() - 10
        formatted = ctr.format(width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test 100%\|' + u'█+' +
            r'\| 10/10 \[00:\d\d<00:00, \d.\d\d ticks/s\]')

    def test_zero_total(self):
        """
        If the total is 0, the bar should be full
        """

        ctr = Counter(stream=self.tty.stdout,
                      total=0,
                      desc='Test',
                      unit='ticks')
        formatted = ctr.format(width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test 100%\|'
            u'█+' + r'\| 0/0 \[00:0\d<00:00, 0.00 ticks/s\]')

    def test_auto_offset(self):
        """
        If offset is not specified, terminal codes should be automatically ignored
        when calculating bar length
        """

        barFormat = u'{desc}{desc_pad}{percentage:3.0f}%|{bar}|{count:{len_total}d}/{total:d} ' + \
                    u'[{elapsed}<{eta}, {rate:.2f}{unit_pad}{unit}/s]'
        blueBarFormat = self.manager.term.blue(barFormat)
        self.assertNotEqual(len(barFormat), len(blueBarFormat))

        ctr = self.manager.counter(stream=self.tty.stdout,
                                   total=10,
                                   desc='Test',
                                   unit='ticks',
                                   count=10,
                                   bar_format=barFormat)
        formatted1 = ctr.format(width=80)
        self.assertEqual(len(formatted1), 80)
        barLen1 = formatted1.count(u'█')

        offset = len(self.manager.term.blue(''))
        ctr = self.manager.counter(stream=self.tty.stdout,
                                   total=10,
                                   desc='Test',
                                   unit='ticks',
                                   count=10,
                                   bar_format=blueBarFormat)
        formatted2 = ctr.format(width=80)
        self.assertEqual(len(formatted2), 80 + offset)
        barLen2 = formatted2.count(u'█')

        self.assertTrue(barLen2 == barLen1)

    def test_offset(self):
        """
        Offset reduces count of printable characters when formatting
        """

        barFormat = u'{desc}{desc_pad}{percentage:3.0f}%|{bar}|{count:{len_total}d}/{total:d} ' + \
                    u'[{elapsed}<{eta}, {rate:.2f}{unit_pad}{unit}/s]'
        barFormat = self.manager.term.blue(barFormat)

        ctr = self.manager.counter(stream=self.tty.stdout,
                                   total=10,
                                   desc='Test',
                                   unit='ticks',
                                   count=10,
                                   bar_format=barFormat,
                                   offset=0)
        formatted1 = ctr.format(width=80)
        self.assertEqual(len(formatted1), 80)
        barLen1 = formatted1.count(u'█')

        offset = len(self.manager.term.blue(''))
        ctr = self.manager.counter(stream=self.tty.stdout,
                                   total=10,
                                   desc='Test',
                                   unit='ticks',
                                   count=10,
                                   bar_format=barFormat,
                                   offset=offset)
        formatted2 = ctr.format(width=80)
        self.assertEqual(len(formatted2), 80 + offset)
        barLen2 = formatted2.count(u'█')

        self.assertTrue(barLen2 == barLen1 + offset)

        # Test in counter format
        ctr = self.manager.counter(stream=self.tty.stdout,
                                   total=10,
                                   count=50,
                                   offset=0)
        formatted = ctr.format(width=80)
        self.assertEqual(len(formatted), 80)

        ctr = self.manager.counter(stream=self.tty.stdout,
                                   total=10,
                                   count=50,
                                   offset=10)
        formatted = ctr.format(width=80)
        self.assertEqual(len(formatted), 90)

    def test_partial_bar(self):

        ctr = Counter(stream=self.tty.stdout,
                      total=100,
                      desc='Test',
                      unit='ticks')
        ctr.count = 50
        formatted = ctr.format(elapsed=50, width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test  50%\|' + u'█+[▏▎▍▌▋▊▉]?' +
            r'[ ]+\|  50/100 \[00:5\d<00:5\d, \d.\d\d ticks/s\]')

        ctr.count = 13
        formatted = ctr.format(elapsed=13, width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test  13%\|' + u'█+[▏▎▍▌▋▊▉]?' +
            r'[ ]+\|  13/100 \[00:1\d<01:\d\d, \d.\d\d ticks/s\]')

        # Explicit test
        ctr.bar_format = u'{bar}'
        ctr.count = 50
        formatted = ctr.format(width=10)
        self.assertEqual(formatted, u'█████     ')

        ctr.count = 13
        formatted = ctr.format(width=10)
        self.assertEqual(formatted, u'█▎        ')

    def test_custom_series(self):
        ctr = Counter(stream=self.tty.stdout,
                      total=100,
                      desc='Test',
                      unit='ticks',
                      series=[' ', '>', '-'])
        ctr.count = 50
        formatted = ctr.format(elapsed=50, width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test  50%\|' + u'-+[>]?' +
            r'[ ]+\|  50/100 \[00:5\d<00:5\d, \d.\d\d ticks/s\]')

        ctr.count = 13
        formatted = ctr.format(elapsed=13, width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test  13%\|' + u'---->' +
            r'[ ]+\|  13/100 \[00:1\d<01:\d\d, \d.\d\d ticks/s\]')

        ctr = Counter(stream=self.tty.stdout,
                      total=100,
                      desc='Test',
                      unit='ticks',
                      series=[u'⭘', u'⬤'])
        ctr.count = 50
        formatted = ctr.format(elapsed=50, width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test  50%\|' + u'⬤+⭘+' +
            r'\|  50/100 \[00:5\d<00:5\d, \d.\d\d ticks/s\]')

    def test_direct(self):
        ctr = Counter(stream=self.tty.stdout,
                      total=100,
                      desc='Test',
                      unit='ticks')
        self.assertIsInstance(ctr.manager, Manager)
        ctr.start = time.time() - 50
        ctr.update(50, force=True)

        self.tty.stdout.write('X\n')
        value = self.tty.stdread.readline()
        if NEEDS_UNICODE_HELP:
            value = value.decode('utf-8')

        self.assertRegex(
            value, r'Test  50%\|' + u'█+[▏▎▍▌▋▊▉]?' +
            r'[ ]+\|  50/100 \[00:5\d<00:5\d, \d.\d\d ticks/s\]X\n')

        with mock.patch.object(self.tty, 'stdout',
                               wraps=self.tty.stdout) as mockstdout:
            mockstdout.encoding = None
            ctr = Counter(stream=self.tty.stdout,
                          total=100,
                          desc='Test',
                          unit='ticks')
            ctr.refresh(flush=False)
            self.assertFalse(mockstdout.flush.called)
            ctr.refresh(flush=True)
            self.assertTrue(mockstdout.flush.called)

    def test_floats(self):
        """
        Using floats for total and count is supported by the logic, but not by the
        default format strings
        """

        ctr = Counter(stream=self.tty.stdout,
                      total=100.2,
                      desc='Test',
                      unit='ticks',
                      min_delta=500)
        ctr.update(50.1)
        self.assertEqual(ctr.count, 50.1)

        # Won't work with default formatting
        with self.assertRaises(ValueError):
            formatted = ctr.format(elapsed=50.1)

        ctr.bar_format = u'{desc}{desc_pad}{percentage:3.0f}%|{bar}| {count:.1f}/{total:.1f} ' + \
                         u'[{elapsed}<{eta}, {rate:.2f}{unit_pad}{unit}/s]'

        formatted = ctr.format(elapsed=50.1, width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test  50%\|' + u'█+' +
            r'[ ]+\| 50.1/100.2 \[00:5\d<00:5\d, \d.\d\d ticks/s\]')

    def test_color(self):
        """
        Only bar characters should be colorized
        """

        ctr = Counter(stream=self.tty.stdout,
                      total=100,
                      bar_format=u'|{bar}|',
                      count=50,
                      color='red')
        terminal = ctr.manager.term
        formatted = ctr.format(width=80)
        self.assertEqual(formatted,
                         '|' + terminal.red(u'█' * 39 + ' ' * 39) + '|')

    def test_subcounter(self):
        """
        When subcounter is present, bar will be drawn in multiple colors
        """

        ctr = Counter(stream=self.tty.stdout, total=100, bar_format=u'{bar}')
        terminal = ctr.manager.term
        ctr.count = 50
        subcounter1 = ctr.add_subcounter('yellow', all_fields=True)
        subcounter1.count = 5
        ctr.add_subcounter('blue', count=10)

        formatted = ctr.format(width=80)
        bartext = terminal.blue(u'█' * 8) + terminal.yellow(
            u'█' * 4) + u'█' * 28 + ' ' * 40
        self.assertEqual(formatted, bartext)

        ctr.bar_format = u'{count_0} {percentage_0} | {count_1} {percentage_1} {rate_1} {eta_1}' + \
                         u' | {count_2} {percentage_2}'

        formatted = ctr.format(elapsed=5, width=80)
        self.assertEqual(formatted, u'35 35.0 | 5 5.0 1.0 01:35 | 10 10.0')

    def test_close(self):
        manager = mock.Mock()

        # Clear is False
        ctr = MockCounter(manager=manager)
        ctr.close()
        self.assertEqual(ctr.calls, ['refresh(flush=True, elapsed=None)'])
        self.assertEqual(manager.remove.call_count, 1)

        # Clear is True, leave is True
        ctr = MockCounter(manager=manager, leave=True)
        ctr.close(clear=True)
        self.assertEqual(ctr.calls, ['refresh(flush=True, elapsed=None)'])
        self.assertEqual(manager.remove.call_count, 2)

        # Clear is True, leave is False
        ctr = MockCounter(manager=manager, leave=False)
        ctr.close(clear=True)
        self.assertEqual(ctr.calls, ['clear(flush=True)'])
        self.assertEqual(manager.remove.call_count, 3)

    def test_context_manager(self):
        mgr = Manager(stream=self.tty.stdout, enabled=False)
        with mgr.counter(total=10, leave=False) as ctr:
            self.assertTrue(ctr in mgr.counters)
            ctr.update()

        self.assertFalse(ctr in mgr.counters)

    def test_add_subcounter(self):

        self.assertEqual(self.ctr._subcounters, [])
        subcounter1 = self.ctr.add_subcounter('blue')
        self.assertEqual(len(self.ctr._subcounters), 1)
        self.assertEqual(self.ctr.subcount, 0)
        self.assertIs(self.ctr._subcounters[0], subcounter1)
        self.assertEqual(subcounter1.count, 0)
        self.assertFalse(subcounter1.all_fields)

        with self.assertRaisesRegex(ValueError, 'Invalid count: 5'):
            self.ctr.add_subcounter('yellow', count=5, all_fields=True)

        self.ctr.count = 5
        subcounter2 = self.ctr.add_subcounter('yellow',
                                              count=5,
                                              all_fields=True)
        self.assertEqual(len(self.ctr._subcounters), 2)
        self.assertEqual(self.ctr.subcount, 5)
        self.assertIs(self.ctr._subcounters[1], subcounter2)
        self.assertEqual(subcounter2.count, 5)
        self.assertTrue(subcounter2.all_fields)
Esempio n. 10
0
class TestCounter(TestCase):
    """
    Test the Counter classes
    We default to using enlighten.Counter and only use enlighten._counter.Counter when necessary
    """
    def setUp(self):
        self.tty = MockTTY()
        self.manager = MockManager(stream=self.tty.stdout)
        self.ctr = Counter(total=10,
                           desc='Test',
                           unit='ticks',
                           manager=self.manager)
        self.manager.counters[self.ctr] = 3
        self.output = r'Test   0%\|[ ]+ \|  0/10 \[00:0\d<\?, 0.00 ticks/s\]'

    def tearDown(self):
        self.tty.close()

    def test_repr(self):
        self.assertEqual(
            repr(self.ctr),
            "Counter(desc='Test', total=10, count=0, unit='ticks')")

    def test_repr_subcounter(self):
        self.ctr.count = 2
        subcounter = self.ctr.add_subcounter('green', count=1)
        self.assertEqual(
            repr(subcounter),
            "SubCounter(count=1, color='green', all_fields=False)")

    def test_no_manager(self):
        """Raise an error if there is no manager specified"""
        with self.assertRaisesRegex(TypeError, 'manager must be specified'):
            enlighten._counter.Counter()
        enlighten._counter.Counter(manager=self.manager)

    def test_increment(self):
        counter = MockCounter(total=100, min_delta=0, manager=self.manager)
        counter.update()
        self.assertEqual(counter.count, 1)
        counter.update(5)
        self.assertEqual(counter.count, 6)

    def test_enabled(self):
        counter = MockCounter(total=100, min_delta=0, manager=self.manager)
        counter.update()
        self.assertEqual(counter.output, [1])
        counter.update()
        self.assertEqual(counter.output, [1, 2])
        counter.enabled = False
        counter.update()
        self.assertEqual(counter.output, [1, 2])

    def test_delta(self):
        counter = MockCounter(total=100, min_delta=0, manager=self.manager)
        counter.update()
        self.assertEqual(counter.output, [1])
        counter.update()
        self.assertEqual(counter.output, [1, 2])
        counter.min_delta = 500
        counter.update()
        self.assertEqual(counter.output, [1, 2])
        counter.min_delta = .01
        time.sleep(.01)
        counter.update()
        self.assertEqual(counter.output, [1, 2, 4])

    def test_force(self):
        counter = MockCounter(total=100, min_delta=0, manager=self.manager)
        counter.update()
        self.assertEqual(counter.output, [1])
        counter.min_delta = 500
        counter.update()
        self.assertEqual(counter.output, [1])
        counter.update(force=True)
        self.assertEqual(counter.output, [1, 3])

    def test_refresh_total(self):
        counter = MockCounter(total=100, min_delta=0, manager=self.manager)
        counter.update()
        self.assertEqual(counter.output, [1])
        counter.min_delta = 500
        counter.update()
        self.assertEqual(counter.output, [1])
        counter.update(98)
        self.assertEqual(counter.output, [1, 100])

    def test_position(self):
        self.assertEqual(self.ctr.position, 3)

    def test_elapsed(self):
        ctr = self.ctr
        ctr.start = time.time() - 5.0
        ctr.last_update = ctr.start + 3.0

        self.assertEqual(int(ctr.elapsed), 5)

        # Clock stops running when total is reached
        ctr.count = ctr.total
        self.assertEqual(int(ctr.elapsed), 3)

    def test_refresh(self):
        self.ctr.last_update = 0
        self.ctr.refresh()
        self.assertRegex(
            self.manager.output[0],
            r'write\(output=%s, flush=True, position=3\)' % self.output)
        self.assertAlmostEqual(self.ctr.last_update, time.time(), delta=0.3)

        self.manager.output = []
        self.ctr.refresh(flush=False)
        self.assertRegex(
            self.manager.output[0],
            r'write\(output=%s, flush=False, position=3\)' % self.output)

        self.manager.output = []
        self.ctr.enabled = False
        self.ctr.refresh()
        self.assertEqual(len(self.manager.output), 0)

    def test_clear(self):
        self.ctr.last_update = 100
        self.ctr.clear()
        self.assertRegex(self.manager.output[0],
                         r'write\(output=, flush=True, position=3\)')
        self.assertEqual(self.ctr.last_update, 0)

        self.manager.output = []
        self.ctr.clear(flush=False)
        self.assertRegex(self.manager.output[0],
                         r'write\(output=, flush=False, position=3\)')

        self.manager.output = []
        self.ctr.enabled = False
        self.ctr.clear()
        self.assertEqual(len(self.manager.output), 0)

    def test_get_subcounter(self):
        self.ctr.count = 6
        subcounter1 = self.ctr.add_subcounter('green')
        subcounter2 = self.ctr.add_subcounter('red', all_fields=True)
        subcounter2.count = 4
        subcounter3 = self.ctr.add_subcounter('white',
                                              count=1,
                                              all_fields=True)

        subcounters, fields = self.ctr._get_subcounters(8)

        self.assertEqual(subcounters, [(subcounter1, 0.0), (subcounter2, 0.4),
                                       (subcounter3, 0.1)])
        self.assertEqual(
            fields, {
                'percentage_1': 0.0,
                'percentage_2': 40.0,
                'percentage_3': 10.0,
                'count_1': 0,
                'count_2': 4,
                'count_3': 1,
                'interval_2': 2.0,
                'interval_3': 0.0,
                'rate_2': 0.5,
                'eta_2': '00:12',
                'rate_3': 0.0,
                'eta_3': '?'
            })

        subcounters, fields = self.ctr._get_subcounters(0)
        self.assertEqual(subcounters, [(subcounter1, 0.0), (subcounter2, 0.4),
                                       (subcounter3, 0.1)])
        self.assertEqual(
            fields, {
                'percentage_1': 0.0,
                'percentage_2': 40.0,
                'percentage_3': 10.0,
                'count_1': 0,
                'count_2': 4,
                'count_3': 1,
                'interval_2': 0.0,
                'interval_3': 0.0,
                'rate_2': 0.0,
                'eta_2': '?',
                'rate_3': 0.0,
                'eta_3': '?'
            })

        self.ctr = Counter(total=0,
                           desc='Test',
                           unit='ticks',
                           manager=self.manager)
        subcounter1 = self.ctr.add_subcounter('red', all_fields=True)
        subcounters, fields = self.ctr._get_subcounters(8)
        self.assertEqual(subcounters, [(subcounter1, 0.0)])
        self.assertEqual(
            fields, {
                'percentage_1': 0.0,
                'count_1': 0,
                'interval_1': 0.0,
                'rate_1': 0.0,
                'eta_1': '00:00'
            })

    def test_get_subcounter_counter_format(self):
        self.ctr.count = 12
        subcounter1 = self.ctr.add_subcounter('green')
        subcounter2 = self.ctr.add_subcounter('red', all_fields=True)
        subcounter2.count = 6
        subcounter3 = self.ctr.add_subcounter('white',
                                              count=1,
                                              all_fields=True)

        subcounters, fields = self.ctr._get_subcounters(8, bar_fields=False)
        self.assertEqual(subcounters, [(subcounter1, 0.0), (subcounter2, 0.0),
                                       (subcounter3, 0.0)])
        self.assertEqual(
            fields, {
                'count_1': 0,
                'count_2': 6,
                'count_3': 1,
                'interval_2': 0.75**-1,
                'interval_3': 0.0,
                'rate_2': 0.75,
                'rate_3': 0.0
            })

    def test_remove(self):
        self.ctr.leave = False
        self.assertTrue(self.ctr in self.manager.counters)

        self.ctr.close()
        self.assertRegex(
            self.manager.output[0],
            r'write\(output=%s, flush=True, position=3\)' % self.output)
        self.assertFalse(self.ctr in self.manager.counters)

        # If it runs again, it shouldn't throw an error
        self.ctr.close()

    def test_format_no_total(self):

        # No unit, No desc
        ctr = Counter(stream=self.tty.stdout, )
        self.assertRegex(ctr.format(width=80), r'0 \[00:0\d, 0.00/s\]')
        ctr.count = 50
        ctr.start = time.time() - 50
        self.assertRegex(ctr.format(width=80), r'50 \[00:5\d, \d.\d\d/s\]')

        # With unit and description
        ctr = Counter(stream=self.tty.stdout, desc='Test', unit='ticks')
        rtn = ctr.format(width=80)
        self.assertEqual(len(rtn), 80)
        self.assertRegex(rtn, r'Test 0 ticks \[00:0\d, 0.00 ticks/s\]')
        ctr.count = 50
        ctr.start = time.time() - 50
        rtn = ctr.format(width=80)
        self.assertEqual(len(rtn), 80)
        self.assertRegex(rtn, r'Test 50 ticks \[00:5\d, \d.\d\d ticks/s\]')

    def test_format_count_gt_total(self):
        """
        Counter should fall back to no-total format if count is greater than total
        """

        ctr = Counter(stream=self.tty.stdout,
                      total=10,
                      desc='Test',
                      unit='ticks')
        ctr.count = 50
        ctr.start = time.time() - 50
        rtn = ctr.format(width=80)
        self.assertEqual(len(rtn), 80)
        self.assertRegex(rtn, r'Test 50 ticks \[00:5\d, \d.\d\d ticks/s\]')

    def test_no_count(self):
        """
        Test for an empty counter
        """

        ctr = Counter(stream=self.tty.stdout,
                      total=10,
                      desc='Test',
                      unit='ticks')
        formatted = ctr.format(width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test   0%\|[ ]+ \|  0/10 \[00:0\d<\?, 0.00 ticks/s\]')

        # No unit, no description
        ctr = Counter(stream=self.tty.stdout, total=10)
        formatted = ctr.format(width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(formatted,
                         r'  0%\|[ ]+ \|  0/10 \[00:0\d<\?, 0.00/s\]')

    def test_full_bar(self):

        ctr = Counter(stream=self.tty.stdout,
                      total=10,
                      desc='Test',
                      unit='ticks',
                      series=SERIES_STD)
        ctr.count = 10
        ctr.start = time.time() - 10
        formatted = ctr.format(width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test 100%\|' + u'█+' +
            r'\| 10/10 \[00:\d\d<00:00, \d.\d\d ticks/s\]')

    def test_zero_total(self):
        """
        If the total is 0, the bar should be full
        """

        ctr = Counter(stream=self.tty.stdout,
                      total=0,
                      desc='Test',
                      unit='ticks',
                      series=SERIES_STD)
        formatted = ctr.format(width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test 100%\|'
            u'█+' + r'\| 0/0 \[00:0\d<00:00, 0.00 ticks/s\]')

    def test_auto_offset(self):
        """
        If offset is not specified, terminal codes should be automatically ignored
        when calculating bar length
        """

        barFormat = u'{desc}{desc_pad}{percentage:3.0f}%|{bar}|{count:{len_total}d}/{total:d} ' + \
                    u'[{elapsed}<{eta}, {rate:.2f}{unit_pad}{unit}/s]'
        blueBarFormat = self.manager.term.blue(barFormat)
        self.assertNotEqual(len(barFormat), len(blueBarFormat))

        ctr = self.manager.counter(total=10,
                                   desc='Test',
                                   unit='ticks',
                                   count=10,
                                   bar_format=barFormat)
        formatted1 = ctr.format(width=80)
        self.assertEqual(len(formatted1), 80)
        barLen1 = formatted1.count(BLOCK)

        offset = len(self.manager.term.blue(''))
        ctr = self.manager.counter(total=10,
                                   desc='Test',
                                   unit='ticks',
                                   count=10,
                                   bar_format=blueBarFormat)
        formatted2 = ctr.format(width=80)
        self.assertEqual(len(formatted2), 80 + offset)
        barLen2 = formatted2.count(BLOCK)

        self.assertTrue(barLen2 == barLen1)

    def test_offset(self):
        """
        Offset reduces count of printable characters when formatting
        """

        barFormat = u'{desc}{desc_pad}{percentage:3.0f}%|{bar}|{count:{len_total}d}/{total:d} ' + \
                    u'[{elapsed}<{eta}, {rate:.2f}{unit_pad}{unit}/s]'
        barFormat = self.manager.term.blue(barFormat)

        ctr = self.manager.counter(total=10,
                                   desc='Test',
                                   unit='ticks',
                                   count=10,
                                   bar_format=barFormat,
                                   offset=0)
        formatted1 = ctr.format(width=80)
        self.assertEqual(len(formatted1), 80)
        barLen1 = formatted1.count(BLOCK)

        offset = len(self.manager.term.blue(''))
        ctr = self.manager.counter(total=10,
                                   desc='Test',
                                   unit='ticks',
                                   count=10,
                                   bar_format=barFormat,
                                   offset=offset)
        formatted2 = ctr.format(width=80)
        self.assertEqual(len(formatted2), 80 + offset)
        barLen2 = formatted2.count(BLOCK)

        self.assertTrue(barLen2 == barLen1 + offset)

        # Test in counter format
        ctr = self.manager.counter(total=10, count=50, offset=0)
        formatted = ctr.format(width=80)
        self.assertEqual(len(formatted), 80)

        ctr = self.manager.counter(total=10, count=50, offset=10)
        formatted = ctr.format(width=80)
        self.assertEqual(len(formatted), 90)

    def test_partial_bar(self):

        ctr = Counter(stream=self.tty.stdout,
                      total=100,
                      desc='Test',
                      unit='ticks',
                      series=SERIES_STD)
        ctr.count = 50
        formatted = ctr.format(elapsed=50, width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test  50%\|' + u'█+[▏▎▍▌▋▊▉]?' +
            r'[ ]+\|  50/100 \[00:5\d<00:5\d, \d.\d\d ticks/s\]')

        ctr.count = 13
        formatted = ctr.format(elapsed=13, width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test  13%\|' + u'█+[▏▎▍▌▋▊▉]?' +
            r'[ ]+\|  13/100 \[00:1\d<01:\d\d, \d.\d\d ticks/s\]')

        # Explicit test
        ctr.bar_format = u'{bar}'
        ctr.count = 50
        formatted = ctr.format(width=10)
        self.assertEqual(formatted, u'█████     ')

        ctr.count = 13
        formatted = ctr.format(width=10)
        self.assertEqual(formatted, u'█▎        ')

    def test_custom_series(self):
        ctr = Counter(stream=self.tty.stdout,
                      total=100,
                      desc='Test',
                      unit='ticks',
                      series=[' ', '>', '-'])
        ctr.count = 50
        formatted = ctr.format(elapsed=50, width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test  50%\|' + u'-+[>]?' +
            r'[ ]+\|  50/100 \[00:5\d<00:5\d, \d.\d\d ticks/s\]')

        ctr.count = 13
        formatted = ctr.format(elapsed=13, width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test  13%\|' + u'---->' +
            r'[ ]+\|  13/100 \[00:1\d<01:\d\d, \d.\d\d ticks/s\]')

        ctr = Counter(stream=self.tty.stdout,
                      total=100,
                      desc='Test',
                      unit='ticks',
                      series=[u'⭘', u'⬤'])
        ctr.count = 50
        formatted = ctr.format(elapsed=50, width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test  50%\|' + u'⬤+⭘+' +
            r'\|  50/100 \[00:5\d<00:5\d, \d.\d\d ticks/s\]')

    def test_direct(self):
        ctr = Counter(stream=self.tty.stdout,
                      total=100,
                      desc='Test',
                      unit='ticks',
                      series=SERIES_STD)
        self.assertIsInstance(ctr.manager, Manager)
        ctr.start = time.time() - 50
        ctr.update(50, force=True)

        self.tty.stdout.write(u'X\n')
        value = self.tty.stdread.readline()

        self.assertRegex(
            value, r'Test  50%\|' + u'█+[▏▎▍▌▋▊▉]?' +
            r'[ ]+\|  50/100 \[00:5\d<00:5\d, \d.\d\d ticks/s\]X\n')

        with mock.patch.object(self.tty, 'stdout',
                               wraps=self.tty.stdout) as mockstdout:
            mockstdout.encoding = None
            ctr = Counter(stream=self.tty.stdout,
                          total=100,
                          desc='Test',
                          unit='ticks')
            ctr.refresh(flush=False)
            self.assertFalse(mockstdout.flush.called)
            ctr.refresh(flush=True)
            self.assertTrue(mockstdout.flush.called)

    def test_floats(self):
        """
        Using floats for total and count is supported by the logic, but not by the
        default format strings
        """

        ctr = Counter(stream=self.tty.stdout,
                      total=100.2,
                      desc='Test',
                      unit='ticks',
                      min_delta=500,
                      series=SERIES_STD)
        ctr.update(50.1)
        self.assertEqual(ctr.count, 50.1)

        # Won't work with default formatting
        with self.assertRaises(ValueError):
            formatted = ctr.format(elapsed=50.1)

        ctr.bar_format = u'{desc}{desc_pad}{percentage:3.0f}%|{bar}| {count:.1f}/{total:.1f} ' + \
                         u'[{elapsed}<{eta}, {rate:.2f}{unit_pad}{unit}/s]'

        formatted = ctr.format(elapsed=50.1, width=80)
        self.assertEqual(len(formatted), 80)
        self.assertRegex(
            formatted, r'Test  50%\|' + u'█+' +
            r'[ ]+\| 50.1/100.2 \[00:5\d<00:5\d, \d.\d\d ticks/s\]')

    def test_color(self):
        """
        Only bar characters should be colorized
        """

        ctr = Counter(stream=self.tty.stdout,
                      total=100,
                      bar_format=u'|{bar}|',
                      count=50,
                      color='red')
        terminal = ctr.manager.term
        formatted = ctr.format(width=80)
        self.assertEqual(formatted,
                         '|' + terminal.red(BLOCK * 39 + ' ' * 39) + '|')

    def test_subcounter(self):
        """
        When subcounter is present, bar will be drawn in multiple colors
        """

        ctr = Counter(stream=self.tty.stdout, total=100, bar_format=u'{bar}')
        terminal = ctr.manager.term
        ctr.count = 50
        subcounter1 = ctr.add_subcounter('yellow', all_fields=True)
        subcounter1.count = 5
        ctr.add_subcounter('blue', count=10)

        formatted = ctr.format(width=80)
        bartext = terminal.blue(BLOCK * 8) + terminal.yellow(
            BLOCK * 4) + BLOCK * 28 + ' ' * 40
        self.assertEqual(formatted, bartext)

        ctr.bar_format = u'{count_0} {percentage_0} | {count_1} {percentage_1} {rate_1} {eta_1}' + \
                         u' | {count_2} {percentage_2}'

        formatted = ctr.format(elapsed=5, width=80)
        self.assertEqual(formatted, u'35 35.0 | 5 5.0 1.0 01:35 | 10 10.0')

    def test_subcounter_count_gt_total(self):
        """
        When total is exceeded, subcounter fields are still populated
        """
        counter_format = u'{count_0} | {count_1} {rate_1} | {count_2}'
        ctr = Counter(stream=self.tty.stdout,
                      total=100,
                      counter_format=counter_format)

        ctr.count = 500
        subcounter1 = ctr.add_subcounter('yellow', all_fields=True)
        subcounter1.count = 50
        ctr.add_subcounter('blue', count=100)
        formatted = ctr.format(elapsed=50, width=80)
        self.assertEqual(formatted, u'350 | 50 1.0 | 100')

    def test_close(self):
        manager = MockManager()

        # Clear is False
        ctr = MockCounter(manager=manager)
        ctr.close()
        self.assertEqual(ctr.calls, ['refresh(flush=True, elapsed=None)'])
        self.assertEqual(manager.remove_calls, 1)

        # Clear is True, leave is True
        ctr = MockCounter(manager=manager, leave=True)
        ctr.close(clear=True)
        self.assertEqual(ctr.calls, ['refresh(flush=True, elapsed=None)'])
        self.assertEqual(manager.remove_calls, 2)

        # Clear is True, leave is False
        ctr = MockCounter(manager=manager, leave=False)
        ctr.close(clear=True)
        self.assertEqual(ctr.calls, ['clear(flush=True)'])
        self.assertEqual(manager.remove_calls, 3)

    def test_context_manager(self):
        mgr = Manager(stream=self.tty.stdout, enabled=False)
        with mgr.counter(total=10, leave=False) as ctr:
            self.assertTrue(ctr in mgr.counters)
            ctr.update()

        self.assertFalse(ctr in mgr.counters)

    def test_add_subcounter(self):

        self.assertEqual(self.ctr._subcounters, [])
        subcounter1 = self.ctr.add_subcounter('blue')
        self.assertEqual(len(self.ctr._subcounters), 1)
        self.assertEqual(self.ctr.subcount, 0)
        self.assertIs(self.ctr._subcounters[0], subcounter1)
        self.assertEqual(subcounter1.count, 0)
        self.assertFalse(subcounter1.all_fields)

        with self.assertRaisesRegex(ValueError, 'Invalid count: 5'):
            self.ctr.add_subcounter('yellow', count=5, all_fields=True)

        self.ctr.count = 5
        subcounter2 = self.ctr.add_subcounter('yellow',
                                              count=5,
                                              all_fields=True)
        self.assertEqual(len(self.ctr._subcounters), 2)
        self.assertEqual(self.ctr.subcount, 5)
        self.assertIs(self.ctr._subcounters[1], subcounter2)
        self.assertEqual(subcounter2.count, 5)
        self.assertTrue(subcounter2.all_fields)

    def test_additional_fields(self):
        """
        Add additional fields to format
        """

        bar_format = ctr_format = u'{arg1:s} {count:d}'

        ctr = Counter(stream=self.tty.stdout,
                      total=10,
                      count=1,
                      bar_format=bar_format,
                      fields={'arg1': 'hello'})
        self.assertEqual(ctr.format(), 'hello 1')

        ctr = Counter(stream=self.tty.stdout,
                      count=1,
                      counter_format=ctr_format,
                      fields={'arg1': 'hello'})
        self.assertEqual(ctr.format(), 'hello 1')

    def test_additional_fields_missing(self):
        """
        Raise a ValueError when a keyword is missing
        """

        bar_format = ctr_format = u'{arg1:s} {count:d}'

        ctr = Counter(stream=self.tty.stdout,
                      total=10,
                      count=1,
                      bar_format=bar_format)
        with self.assertRaisesRegex(
                ValueError, "'arg1' specified in format, but not provided"):
            ctr.format()

        ctr = Counter(stream=self.tty.stdout,
                      count=1,
                      counter_format=ctr_format)
        with self.assertRaisesRegex(
                ValueError, "'arg1' specified in format, but not provided"):
            ctr.format()

    def test_additional_fields_changed(self):
        """
        Change additional fields
        """

        bar_format = ctr_format = u'{arg1:s} {count:d}'
        additional_fields = {'arg1': 'hello'}

        ctr = Counter(stream=self.tty.stdout,
                      total=10,
                      count=1,
                      bar_format=bar_format,
                      fields=additional_fields)
        self.assertEqual(ctr.format(), 'hello 1')
        additional_fields['arg1'] = 'goodbye'
        self.assertEqual(ctr.format(), 'goodbye 1')

        ctr = Counter(stream=self.tty.stdout,
                      count=1,
                      counter_format=ctr_format,
                      fields=additional_fields)
        self.assertEqual(ctr.format(), 'goodbye 1')
        additional_fields['arg1'] = 'hello'
        self.assertEqual(ctr.format(), 'hello 1')

    def test_additional_fields_no_overwrite(self):
        """
        Additional fields can not overwrite dynamic fields
        """

        bar_format = ctr_format = u'{arg1:s} {count:d}'
        additional_fields = {'arg1': 'hello'}

        ctr = Counter(stream=self.tty.stdout,
                      total=10,
                      count=1,
                      bar_format=bar_format,
                      fields=additional_fields)
        self.assertEqual(ctr.format(), 'hello 1')

        ctr = Counter(stream=self.tty.stdout,
                      count=1,
                      counter_format=ctr_format,
                      fields=additional_fields)
        self.assertEqual(ctr.format(), 'hello 1')

    def test_kwarg_fields(self):
        """
        Additional fields to format via keyword arguments
        """

        bar_format = ctr_format = u'{arg1:s} {count:d}'

        ctr = Counter(stream=self.tty.stdout,
                      total=10,
                      count=1,
                      bar_format=bar_format,
                      arg1='hello')
        self.assertEqual(ctr.format(), 'hello 1')

        ctr.update(arg1='goodbye')
        self.assertEqual(ctr.format(), 'goodbye 2')

        ctr = Counter(stream=self.tty.stdout,
                      count=1,
                      counter_format=ctr_format,
                      arg1='hello')
        self.assertEqual(ctr.format(), 'hello 1')

        ctr.update(arg1='goodbye')
        self.assertEqual(ctr.format(), 'goodbye 2')

    def test_kwarg_fields_precedence(self):
        """
        Keyword arguments take precedence over fields
        """

        bar_format = u'{arg1:s} {count:d}'
        additional_fields = {'arg1': 'hello'}

        ctr = Counter(stream=self.tty.stdout,
                      total=10,
                      count=1,
                      bar_format=bar_format,
                      fields=additional_fields)

        self.assertEqual(ctr.format(), 'hello 1')

        ctr.update(arg1='goodbye')
        self.assertEqual(ctr.format(), 'goodbye 2')

    def test_fill_setter(self):
        """Fill must be one printable character"""

        ctr = Counter(stream=self.tty.stdout, fill='a')

        with self.assertRaisesRegex(ValueError,
                                    'fill character must be a length of 1'):
            ctr.fill = 'hello'

        with self.assertRaisesRegex(ValueError,
                                    'fill character must be a length of 1'):
            ctr.fill = ''

    def test_fill(self):
        """
        Fill uses remaining space
        """

        ctr_format = u'{fill}HI'
        ctr = Counter(stream=self.tty.stdout,
                      count=1,
                      counter_format=ctr_format,
                      fill=u'-')
        self.assertEqual(ctr.format(), u'-' * 78 + 'HI')

        ctr_format = u'{fill}HI{fill}'
        ctr = Counter(stream=self.tty.stdout,
                      count=1,
                      counter_format=ctr_format,
                      fill=u'-')
        self.assertEqual(ctr.format(), u'-' * 39 + 'HI' + u'-' * 39)

    @unittest.skipIf(PY2, 'Skip warnings tests in Python 2')
    def test_reserved_fields(self):
        """
        When reserved fields are used, a warning is raised
        """

        ctr = Counter(stream=self.tty.stdout,
                      total=10,
                      count=1,
                      fields={'elapsed': 'reserved'})
        with self.assertWarnsRegex(EnlightenWarning,
                                   'Ignoring reserved fields') as warn:
            ctr.format()
        self.assertRegex(__file__, warn.filename)

        ctr = Counter(stream=self.tty.stdout,
                      total=10,
                      fields={'elapsed': 'reserved'})
        with self.assertWarnsRegex(EnlightenWarning,
                                   'Ignoring reserved fields') as warn:
            ctr.format()
        self.assertRegex(__file__, warn.filename)

        ctr = Counter(stream=self.tty.stdout,
                      total=10,
                      count=1,
                      elapsed='reserved')
        with self.assertWarnsRegex(EnlightenWarning,
                                   'Ignoring reserved fields') as warn:
            ctr.format()
        self.assertRegex(__file__, warn.filename)

        ctr = Counter(stream=self.tty.stdout, total=10, elapsed='reserved')
        with self.assertWarns(EnlightenWarning) as warn:
            ctr.format()
        self.assertRegex(__file__, warn.filename)

    def test_builtin_bar_fields(self):
        """
        Ensure all built-in fields are populated as expected
        """

        bar_fields = tuple(field for field in enlighten._counter.COUNTER_FIELDS
                           if field != 'fill')
        bar_format = u', '.join(u'%s: {%s}' % (field, field)
                                for field in sorted(bar_fields))

        ctr = Counter(stream=self.tty.stdout,
                      total=100,
                      bar_format=bar_format,
                      unit='parsecs',
                      desc='Kessel runs')

        ctr.count = 50
        fields = 'bar: , count: 50, desc: Kessel runs, desc_pad:  , elapsed: 00:50, eta: 00:50, ' \
                 'interval: 1.0, len_total: 3, percentage: 50.0, rate: 1.0, total: 100, ' \
                 'unit: parsecs, unit_pad:  '
        self.assertEqual(ctr.format(elapsed=50, width=80), fields)
Esempio n. 11
0
class TestManager(TestCase):

    def setUp(self):
        self.tty = MockTTY()
        self.resize_sig = signal.getsignal(signal.SIGWINCH)

    def tearDown(self):
        self.tty.close()
        signal.signal(signal.SIGWINCH, self.resize_sig)

    def test_init_safe(self):
        with redirect_output('stdout', self.tty.stdout):
            # Companion stream is stderr if stream is stdout
            manager = _manager.Manager()
            self.assertIs(manager.stream, sys.stdout)
            self.assertIs(manager.term.stream, sys.stdout)

    @unittest.skipIf(STDOUT_NO_FD, 'No file descriptor for stdout')
    def test_init(self):
        # Companion stream is stderr if stream is stdout
        manager = _manager.Manager()
        self.assertIs(manager.stream, sys.stdout)
        self.assertIs(manager.term.stream, sys.stdout)
        # This will fail building rpm packages since stderr is redirected
        if sys.__stderr__.isatty():
            self.assertIs(manager.companion_stream, sys.__stderr__)
            self.assertIs(manager.companion_term.stream, sys.__stderr__)

    @unittest.skipIf(STDOUT_NO_FD, 'No file descriptor for stdout')
    def test_init_companion_hc(self):
        # Hard-coded companion stream always wins
        manager = _manager.Manager(companion_stream=OUTPUT)
        self.assertIs(manager.companion_stream, OUTPUT)
        self.assertIs(manager.companion_term.stream, OUTPUT)

    @unittest.skipIf(STDOUT_NO_FD, 'No file descriptor for stdout')
    def test_init_stderr(self):
        # Companion stream is stdout if stream is stderr
        manager = _manager.Manager(stream=sys.__stderr__)
        self.assertIs(manager.stream, sys.__stderr__)
        self.assertIs(manager.term.stream, sys.__stderr__)
        # This will fail building rpm packages since stderr is redirected
        if sys.__stdout__.isatty():
            self.assertIs(manager.companion_stream, sys.__stdout__)
            self.assertIs(manager.companion_term.stream, sys.__stdout__)

    @unittest.skipIf(STDOUT_NO_FD, 'No file descriptor for stdout')
    def test_init_redirect(self):
        # If stdout is redirected, but stderr is still a tty, use it for companion
        with redirect_output('stdout', OUTPUT):
            manager = _manager.Manager()
            self.assertIs(manager.stream, sys.stdout)
            self.assertIs(manager.term.stream, sys.stdout)
            # This will fail building rpm packages since stderr is redirected
            if sys.__stderr__.isatty():
                self.assertIs(manager.companion_stream, sys.stderr)
                self.assertIs(manager.companion_term.stream, sys.stderr)

    @unittest.skipIf(STDOUT_NO_FD, 'No file descriptor for stdout')
    def test_init_stderr_redirect(self):
        # If stderr is redirected, but stdout is still a tty, use it for companion
        with redirect_output('stderr', OUTPUT):
            manager = _manager.Manager(stream=sys.stderr)
            self.assertIs(manager.stream, sys.stderr)
            self.assertIs(manager.term.stream, sys.stderr)
            # This will fail building rpm packages since stderr is redirected
            if sys.__stdout__.isatty():
                self.assertIs(manager.companion_stream, sys.stdout)
                self.assertIs(manager.companion_term.stream, sys.stdout)

    @unittest.skipIf(STDOUT_NO_FD, 'No file descriptor for stdout')
    def test_init_stderr_companion_hc(self):

        # Hard-coded companion stream always wins
        manager = _manager.Manager(stream=sys.__stderr__, companion_stream=OUTPUT)
        self.assertIs(manager.companion_stream, OUTPUT)
        self.assertIs(manager.companion_term.stream, OUTPUT)

    @unittest.skipIf(STDOUT_NO_FD, 'No file descriptor for stdout')
    def test_init_hc(self):

        # Nonstandard stream doesn't get a companion stream by default
        manager = _manager.Manager(stream=OUTPUT)
        self.assertIs(manager.stream, OUTPUT)
        self.assertIs(manager.term.stream, OUTPUT)
        self.assertIsNone(manager.companion_stream)
        self.assertIsNone(manager.companion_term)

    def test_repr(self):
        manager = _manager.Manager()
        self.assertEqual(repr(manager), "Manager(stream=%r)" % sys.stdout)

    def test_counter_and_remove(self):
        # pylint: disable=no-member,assigning-non-slot
        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter)
        self.assertEqual(len(manager.counters), 0)

        with mock.patch.object(manager, '_set_scroll_area') as ssa:
            counter1 = manager.counter(leave=True)
        self.assertTrue(counter1.leave)
        self.assertEqual(len(manager.counters), 1)
        self.assertEqual(manager.counters[counter1], 1)
        self.assertEqual(counter1.calls, [])
        self.assertEqual(ssa.call_count, 1)

        with mock.patch.object(manager, '_set_scroll_area') as ssa:
            counter2 = manager.counter(leave=False)
        self.assertFalse(counter2.leave)
        self.assertEqual(len(manager.counters), 2)
        self.assertEqual(manager.counters[counter1], 2)
        self.assertEqual(manager.counters[counter2], 1)
        self.assertEqual(counter1.calls,
                         ['clear(flush=False)', 'refresh(flush=False, elapsed=None)'])
        self.assertEqual(counter2.calls, [])
        self.assertEqual(ssa.call_count, 1)
        counter1.calls = []

        with mock.patch.object(manager, '_set_scroll_area') as ssa:
            counter3 = manager.counter(leave=False)
        self.assertFalse(counter3.leave)
        self.assertEqual(len(manager.counters), 3)
        self.assertEqual(manager.counters[counter1], 3)
        self.assertEqual(manager.counters[counter2], 2)
        self.assertEqual(manager.counters[counter3], 1)
        self.assertEqual(counter1.calls,
                         ['clear(flush=False)', 'refresh(flush=False, elapsed=None)'])
        self.assertEqual(counter2.calls,
                         ['clear(flush=False)', 'refresh(flush=False, elapsed=None)'])
        self.assertEqual(counter3.calls, [])
        self.assertEqual(ssa.call_count, 1)
        counter1.calls = []
        counter2.calls = []

        manager.remove(counter3)
        self.assertEqual(len(manager.counters), 2)
        self.assertFalse(counter3 in manager.counters)

        # Remove again, no error
        manager.remove(counter3)
        self.assertEqual(len(manager.counters), 2)

        manager.remove(counter1)
        self.assertEqual(len(manager.counters), 2)
        self.assertTrue(counter1 in manager.counters)

        with mock.patch.object(manager, '_set_scroll_area') as ssa:
            counter4 = manager.counter(leave=False)
        self.assertFalse(counter4.leave)
        self.assertEqual(len(manager.counters), 3)
        self.assertEqual(manager.counters[counter1], 3)
        self.assertEqual(manager.counters[counter2], 2)
        self.assertEqual(manager.counters[counter4], 1)
        self.assertEqual(counter1.calls, [])
        self.assertEqual(counter2.calls, [])
        self.assertEqual(counter4.calls, [])
        self.assertEqual(ssa.call_count, 1)

    def test_counter_position(self):
        manager = _manager.Manager(stream=self.tty.stdout, set_scroll=False)
        counter1 = manager.counter(position=4)
        self.assertEqual(manager.counters[counter1], 4)

        with self.assertRaisesRegex(ValueError, 'Counter position 4 is already occupied'):
            manager.counter(position=4)

        with self.assertRaisesRegex(ValueError,
                                    'Counter position 200 is greater than terminal height'):
            manager.counter(position=200)

    def test_counter_position_pinned(self):
        """If a position is taken, use next available"""

        manager = _manager.Manager(stream=self.tty.stdout, set_scroll=False)
        counter1 = manager.counter(position=2)
        self.assertEqual(manager.counters[counter1], 2)

        counter2 = manager.counter()
        self.assertEqual(manager.counters[counter1], 2)
        self.assertEqual(manager.counters[counter2], 1)

        counter3 = manager.counter()
        self.assertEqual(manager.counters[counter1], 2)
        self.assertEqual(manager.counters[counter2], 3)
        self.assertEqual(manager.counters[counter3], 1)

        status1 = manager.status_bar(position=3)
        self.assertEqual(manager.counters[counter1], 2)
        self.assertEqual(manager.counters[counter2], 4)
        self.assertEqual(manager.counters[counter3], 1)
        self.assertEqual(manager.counters[status1], 3)

        status2 = manager.status_bar()
        self.assertEqual(manager.counters[counter1], 2)
        self.assertEqual(manager.counters[counter2], 5)
        self.assertEqual(manager.counters[counter3], 4)
        self.assertEqual(manager.counters[status1], 3)
        self.assertEqual(manager.counters[status2], 1)

    def test_inherit_kwargs(self):
        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter,
                                   unit='knights', not_real=True, desc='Default')

        self.assertTrue('unit' in manager.defaults)
        self.assertTrue('desc' in manager.defaults)
        self.assertTrue('not_real' in manager.defaults)

        with mock.patch.object(manager, '_set_scroll_area'):
            ctr = manager.counter(desc='Huzzah')

        self.assertEqual(ctr.unit, 'knights')
        self.assertEqual(ctr.desc, 'Huzzah')
        self.assertFalse(hasattr(ctr, 'not_real'))

    def test_write(self):
        msg = 'test message'

        with mock.patch('enlighten._manager.Manager._set_scroll_area') as ssa:
            manager = _manager.Manager(stream=self.tty.stdout)
            counter = manager.counter(position=3)
            term = manager.term
            manager.write(msg, counter=counter)

        self.tty.stdout.write(u'X\n')
        # Carriage return is getting converted to newline
        self.assertEqual(self.tty.stdread.readline(),
                         term.move(22, 0) + '\r' + term.clear_eol + msg + 'X\n')
        self.assertEqual(ssa.call_count, 2)

    def test_write_no_flush(self):
        """
        Output is stored in buffer, but not flushed to stream
        """

        msg = u'test message'

        with mock.patch('enlighten._manager.Manager._set_scroll_area') as ssa:
            manager = _manager.Manager(stream=self.tty.stdout, companion_stream=OUTPUT)
            counter = manager.counter(position=3)
            term = manager.term
            manager.write(msg, counter=counter, flush=False)

        self.assertEqual(manager._buffer,
                         [term.move(term.height - 3, 0), '\r', term.clear_eol, msg])
        self.assertEqual(manager._companion_buffer, [])

        self.tty.stdout.write(u'X\n')

        # No output
        self.assertEqual(self.tty.stdread.readline(), 'X\n')
        self.assertEqual(ssa.call_count, 2)

    def test_flush_companion_buffer(self):

        """
        Output is stored in buffer, but only written in companion stream is defined
        """

        manager = _manager.Manager(stream=self.tty.stdout)
        msg = u'test message'

        manager._companion_buffer = [msg]

        manager._flush_streams()

        # Companion buffer flushed, but not outputted
        self.assertEqual(manager._companion_buffer, [])
        self.tty.stdout.write(u'X\n')
        self.assertEqual(self.tty.stdread.readline(), 'X\n')

        # set companion stream and test again
        manager.companion_stream = OUTPUT
        manager._companion_buffer = [msg]
        manager._flush_streams()

        self.assertEqual(manager._companion_buffer, [])
        self.tty.stdout.write(u'X\n')
        self.assertEqual(self.tty.stdread.readline(), 'X\n')
        self.assertEqual(OUTPUT.getvalue(), msg)

    def test_autorefresh(self):
        """
        Ensure auto-refreshed counters are updated when others are
        """

        manager = _manager.Manager(stream=self.tty.stdout)
        counter1 = manager.counter(count=1, total=0, counter_format=u'counter1', autorefresh=True)
        counter2 = manager.counter(count=1, total=0, counter_format=u'counter2')
        self.tty.clear()

        # Counter 1 in auto-refresh list
        self.assertIn(counter1, manager.autorefresh)

        # If auto-refreshed counter hasn't been refreshed recently refresh
        counter1.last_update = 0
        counter2.refresh()
        self.tty.stdout.write(u'X\n')
        output = self.tty.stdread.readline()
        self.assertRegex(output, 'counter2.+counter1')

        # If auto-refreshed counter has been refreshed recently, skip
        counter1.last_update = time.time() + 5
        counter2.refresh()
        self.tty.stdout.write(u'X\n')
        output = self.tty.stdread.readline()
        self.assertRegex(output, 'counter2')
        self.assertNotRegex(output, 'counter1')

        # If already auto-refreshing, skip
        manager.refresh_lock = True
        counter1.last_update = 0
        counter2.refresh()
        # Have to explicitly flush
        manager._flush_streams()
        self.tty.stdout.write(u'X\n')
        output = self.tty.stdread.readline()
        self.assertRegex(output, 'counter2')
        self.assertNotRegex(output, 'counter1')

    def test_set_scroll_area_disabled(self):
        manager = _manager.Manager(stream=self.tty.stdout,
                                   counter_class=MockCounter, set_scroll=False)
        manager.counters['dummy'] = 3

        manager._set_scroll_area()
        self.tty.stdout.write(u'X\n')
        self.assertEqual(self.tty.stdread.readline(), 'X\n')

    def test_set_scroll_area_no_change(self):
        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter)
        manager.counters['dummy'] = 3
        manager.scroll_offset = 4

        manager._set_scroll_area()
        self.assertEqual(manager._buffer, [manager.term.move(21, 0)])

    def test_set_scroll_area_companion(self):
        """
        Ensure when no change is made, a term.move is still called for the companion stream
        """

        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter,
                                   companion_stream=self.tty.stdout)
        manager.counters['dummy'] = 3
        manager.scroll_offset = 4
        term = manager.term

        manager._set_scroll_area()

        self.assertEqual(manager._buffer, [term.move(21, 0)])
        self.assertEqual(manager._companion_buffer, [term.move(21, 0)])

    def test_set_scroll_area(self):
        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter)
        manager.counters['dummy'] = 3
        term = manager.term
        stdread = self.tty.stdread
        self.assertEqual(manager.scroll_offset, 1)
        self.assertFalse(manager.process_exit)
        self.assertNotEqual(signal.getsignal(signal.SIGWINCH), manager._stage_resize)
        old_offset = manager.scroll_offset

        with mock.patch('enlighten._manager.atexit') as atexit:
            manager._set_scroll_area()

        self.assertEqual(manager.scroll_offset, 4)
        self.assertEqual(signal.getsignal(signal.SIGWINCH), manager._stage_resize)
        self.assertTrue(manager.process_exit)
        atexit.register.assert_called_with(manager._at_exit)

        offset = manager.scroll_offset
        scroll_position = term.height - offset
        self.assertEqual(manager._buffer,
                         [term.move(term.height - old_offset, 0),
                          '\n' * (offset - old_offset),
                          term.hide_cursor, term.csr(0, scroll_position),
                          term.move(scroll_position, 0)])

        # No companion buffer defined
        self.assertEqual(manager._companion_buffer, [])

        # Make sure nothing was flushed
        self.tty.stdout.write(u'X\n')
        self.assertEqual(stdread.readline(), 'X\n')

        # Run it again and make sure exit handling isn't reset
        del manager._buffer[:]
        del manager._companion_buffer[:]
        with mock.patch('enlighten._manager.atexit') as atexit:
            manager._set_scroll_area(force=True)

        self.assertFalse(atexit.register.called)
        self.assertEqual(manager._buffer,
                         [term.hide_cursor, term.csr(0, scroll_position),
                          term.move(scroll_position, 0)])

        # Set max counter lower and make sure scroll_offset hasn't changed
        manager.counters['dummy'] = 1
        with mock.patch('enlighten._manager.atexit') as atexit:
            manager._set_scroll_area()

        self.assertEqual(manager.scroll_offset, 4)

    def test_set_scroll_area_force(self):
        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter)
        manager.counters['dummy'] = 3
        manager.scroll_offset = 4
        manager.height = 20
        scroll_position = manager.height - manager.scroll_offset
        term = manager.term

        with mock.patch('enlighten._manager.atexit') as atexit:
            manager._set_scroll_area(force=True)

            self.assertEqual(manager.scroll_offset, 4)
            self.assertTrue(manager.process_exit)

            self.assertEqual(manager._buffer,
                             [term.hide_cursor,
                              term.csr(0, scroll_position),
                              term.move(scroll_position, 0)])
            self.assertEqual(manager._companion_buffer, [])
            atexit.register.assert_called_with(manager._at_exit)

    def test_at_exit(self):

        tty = MockTTY()

        try:
            with mock.patch.object(tty, 'stdout', wraps=tty.stdout) as mockstdout:
                manager = _manager.Manager(stream=tty.stdout, counter_class=MockCounter)
                term = manager.term
                reset = (term.normal_cursor +
                         term.csr(0, term.height - 1) +
                         term.move(term.height, 0))

                # process_exit is False
                manager._at_exit()
                self.assertFalse(mockstdout.flush.called)
                # No output
                tty.stdout.write(u'X\n')
                self.assertEqual(tty.stdread.readline(), 'X\n')

                # process_exit is True, set_scroll False
                manager.process_exit = True
                manager.set_scroll = False
                manager._at_exit()
                self.assertEqual(mockstdout.flush.call_count, 1)
                self.assertEqual(tty.stdread.readline(), term.move(25, 0) + term.cud1)

                # process_exit is True, set_scroll True
                manager.set_scroll = True
                manager._at_exit()
                self.assertEqual(mockstdout.flush.call_count, 2)
                self.assertEqual(tty.stdread.readline(), reset + term.cud1)

                # Ensure companion stream gets flushed
                manager.companion_stream = tty.stdout
                manager._at_exit()
                self.assertEqual(mockstdout.flush.call_count, 4)
                self.assertEqual(tty.stdread.readline(), reset + term.cud1)

                term = manager.term

        finally:
            # Ensure no errors if tty closes before _at_exit is called
            tty.close()
            manager._at_exit()

    def test_stop(self):

        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter)
        manager.counters[MockCounter(manager=manager)] = 3
        manager.counters[MockCounter(manager=manager)] = 4
        term = manager.term
        self.assertIsNone(manager.companion_term)

        with mock.patch('enlighten._manager.atexit'):
            manager._set_scroll_area()

        self.assertEqual(manager.scroll_offset, 5)
        self.assertEqual(signal.getsignal(signal.SIGWINCH), manager._stage_resize)
        self.assertTrue(manager.process_exit)

        # Clear buffer
        del manager._buffer[:]

        manager.enabled = False
        manager.stop()

        # No output, No changes
        self.tty.stdout.write(u'X\n')
        self.assertEqual(self.tty.stdread.readline(), 'X\n')
        self.assertEqual(signal.getsignal(signal.SIGWINCH), manager._stage_resize)
        self.assertTrue(manager.process_exit)

        manager.enabled = True
        manager.stop()

        self.assertEqual(signal.getsignal(signal.SIGWINCH), manager.sigwinch_orig)

        self.tty.stdout.write(u'X\n')
        self.assertEqual(self.tty.stdread.readline(),
                         term.move(term.height - 2, 0) + term.clear_eol +
                         term.move(term.height - 1, 0) + term.clear_eol +
                         term.normal_cursor + term.csr(0, term.height - 1) +
                         term.move(term.height, 0) + 'X\n')

        self.assertFalse(manager.process_exit)
        self.assertFalse(manager.enabled)
        for counter in manager.counters:
            self.assertFalse(counter.enabled)

    def test_stop_no_set_scroll(self):
        """
        set_scroll is False
        """

        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter,
                                   set_scroll=False)
        manager.counters[MockCounter(manager=manager)] = 3
        manager.counters[MockCounter(manager=manager)] = 4
        term = manager.term

        with mock.patch('enlighten._manager.atexit'):
            with mock.patch.object(term, 'change_scroll'):
                manager._set_scroll_area()

        self.assertEqual(manager.scroll_offset, 5)
        self.assertEqual(signal.getsignal(signal.SIGWINCH), manager._stage_resize)
        self.assertTrue(manager.process_exit)

        # Stream empty
        self.tty.stdout.write(u'X\n')
        self.assertEqual(self.tty.stdread.readline(), 'X\n')

        manager.stop()

        self.assertEqual(signal.getsignal(signal.SIGWINCH), manager.sigwinch_orig)
        self.assertFalse(manager.process_exit)

        self.tty.stdout.write(u'X\n')
        self.assertEqual(self.tty.stdread.readline(),
                         term.move(term.height - 2, 0) + term.clear_eol +
                         term.move(term.height - 1, 0) + term.clear_eol +
                         term.move(25, 0) + 'X\n')

    def test_stop_never_used(self):
        """
        In this case, _set_scroll_area() was never called
        """

        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter)
        manager.counters[MockCounter(manager=manager)] = 3
        manager.counters[MockCounter(manager=manager)] = 4
        term = manager.term

        self.assertFalse(manager.process_exit)

        manager.stop()

        self.assertEqual(signal.getsignal(signal.SIGWINCH), manager.sigwinch_orig)

        # Only reset terminal
        self.tty.stdout.write(u'X\n')
        reset = term.normal_cursor + term.csr(0, term.height - 1) + term.move(term.height, 0)
        self.assertEqual(self.tty.stdread.readline(), reset + 'X\n')

    def test_stop_companion(self):
        """
        In this case, we have a companion terminal
        Just make sure we have an extra reset
        """

        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter,
                                   companion_stream=self.tty.stdout)
        manager.counters[MockCounter(manager=manager)] = 3
        manager.counters[MockCounter(manager=manager)] = 4
        term = manager.term

        with mock.patch('enlighten._manager.atexit'):
            manager._set_scroll_area()

        del manager._buffer[:]
        del manager._companion_buffer[:]

        with mock.patch.object(manager, '_flush_streams'):
            manager.stop()

        self.assertEqual(manager._buffer,
                         [term.move(term.height - 2, 0), term.clear_eol,
                          term.move(term.height - 1, 0), term.clear_eol,
                          term.normal_cursor, term.csr(0, term.height - 1),
                          term.move(term.height, 0)])

        self.assertEqual(manager._companion_buffer,
                         [term.normal_cursor, term.csr(0, term.height - 1),
                          term.move(term.height, 0)])

    def test_stop_position_1(self):
        """
        Ensure a line feed is given if there is a counter at position 1
        """

        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter)
        term = manager.term

        manager.counters[MockCounter(manager=manager)] = 3
        with mock.patch.object(manager, '_flush_streams'):
            manager.stop()

        self.assertEqual(manager._buffer,
                         [term.normal_cursor, term.csr(0, term.height - 1),
                          term.move(term.height, 0)])

        del manager._buffer[:]
        manager.enabled = True
        manager.counters[MockCounter(manager=manager)] = 1
        with mock.patch.object(manager, '_flush_streams'):
            manager.stop()

        self.assertEqual(manager._buffer,
                         [term.normal_cursor, term.csr(0, term.height - 1),
                          term.move(term.height, 0), term.cud1 or '\n'])

    def test_resize(self):
        """
        Resize lock must be False for handler to run
        Terminal size is cached unless resize handler runs
        """

        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter)
        counter3 = MockCounter(manager=manager)
        manager.counters[counter3] = 3
        manager.scroll_offset = 4
        term = manager.term

        with mock.patch('%s.width' % TERMINAL, new_callable=mock.PropertyMock) as mockwidth:
            mockwidth.return_value = 70

            manager.resize_lock = True
            with mock.patch('enlighten._manager.Manager._set_scroll_area') as ssa:
                manager._stage_resize()
                self.assertFalse(ssa.called)

            self.assertEqual(manager.width, 80)
            self.assertTrue(manager.resize_lock)

            self.tty.stdout.write(u'X\n')
            self.assertEqual(self.tty.stdread.readline(), 'X\n')

            self.assertEqual(counter3.calls, [])

            manager.resize_lock = False
            with mock.patch('enlighten._manager.Manager._set_scroll_area') as ssa:
                manager._resize_handler()
                self.assertEqual(ssa.call_count, 1)

            self.assertEqual(manager.width, 70)
            self.assertFalse(manager.resize_lock)

            self.tty.stdout.write(u'X\n')
            self.assertEqual(self.tty.stdread.readline(), term.move(21, 0) + term.clear_eos + 'X\n')

            self.assertEqual(counter3.calls, ['refresh(flush=False, elapsed=None)'])

    def test_threaded_eval(self):
        """
        Dynamic value for threaded determined when scroll area is first set
        """

        # Not dynamic if explicitly True
        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter, threaded=True)
        self.assertTrue(manager.threaded)
        with mock.patch('threading.active_count', return_value=4):
            manager.counter()
        self.assertTrue(manager.threaded)

        # Not dynamic if explicitly False
        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter,
                                   threaded=False)
        self.assertFalse(manager.threaded)
        with mock.patch('threading.active_count', return_value=4):
            manager.counter()
        self.assertFalse(manager.threaded)

        # False by default
        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter)
        self.assertIsNone(manager.threaded)
        manager.counter()
        self.assertFalse(manager.threaded)

        # True if threaded
        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter)
        self.assertIsNone(manager.threaded)
        with mock.patch('threading.active_count', return_value=4):
            manager.counter()
        self.assertTrue(manager.threaded)

        # True if has child processes
        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter)
        self.assertIsNone(manager.threaded)
        with mock.patch('multiprocessing.active_children', return_value=[1, 2]):
            manager.counter()
        self.assertTrue(manager.threaded)

        # True if is child processes
        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter)
        self.assertIsNone(manager.threaded)
        with mock.patch('multiprocessing.current_process') as c_process:
            c_process.name = 'Process1'
            manager.counter()
        self.assertTrue(manager.threaded)

    def test_resize_threaded(self):
        """
        Test a resize event threading behavior
        """
        manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter, threaded=True)
        counter3 = MockCounter(manager=manager)
        counter3.last_update = time.time()
        manager.counters[counter3] = 3
        manager.scroll_offset = 4
        term = manager.term

        # simulate resize
        manager._stage_resize()
        self.assertTrue(manager._resize)
        self.assertEqual(counter3.last_update, 0)

        with mock.patch('%s.width' % TERMINAL, new_callable=mock.PropertyMock) as mockwidth:
            mockwidth.return_value = 70

            # resize doesn't happen until a write is called
            self.assertEqual(manager.width, 80)

            with mock.patch('enlighten._manager.Manager._set_scroll_area') as ssa:
                manager.write()
                self.assertEqual(ssa.call_count, 1)

            self.assertEqual(manager.width, 70)

            self.tty.stdout.write(u'X\n')
            self.assertEqual(self.tty.stdread.readline(), term.move(21, 0) + term.clear_eos + 'X\n')
            self.assertFalse(manager.resize_lock)
            self.assertFalse(manager._resize)
            self.assertEqual(counter3.calls, ['refresh(flush=False, elapsed=None)'])

    def test_resize_handler_height_less(self):

        with mock.patch('%s.height' % TERMINAL, new_callable=mock.PropertyMock) as mockheight:
            mockheight.side_effect = [25, 23]

            manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter)
            counter3 = MockCounter(manager=manager)
            manager.counters[counter3] = 3
            manager.scroll_offset = 4

            with mock.patch('enlighten._manager.Manager._set_scroll_area') as ssa:
                manager._resize_handler()
            self.assertEqual(ssa.call_count, 1)

            self.assertEqual(manager.height, 23)

            self.assertEqual(self.tty.stdread.readline(), manager.term.move(19, 0) + '\n')
            for _ in range(5):
                self.assertEqual(self.tty.stdread.readline(), '\n')

            self.assertEqual(counter3.calls, ['refresh(flush=False, elapsed=None)'])

    def test_resize_handler_height_greater_threaded(self):

        with mock.patch('%s.height' % TERMINAL, new_callable=mock.PropertyMock) as mockheight:
            mockheight.side_effect = [25, 27]

            manager = _manager.Manager(stream=self.tty.stdout, counter_class=MockCounter,
                                       threaded=True)
            counter3 = MockCounter(manager=manager)
            manager.counters[counter3] = 3
            manager.scroll_offset = 4
            term = manager.term

            with mock.patch('enlighten._manager.Manager._set_scroll_area') as ssa:
                manager._resize_handler()
            self.assertEqual(ssa.call_count, 1)

            self.assertEqual(manager.height, 27)

            self.tty.stdout.write(u'X\n')
            self.assertEqual(self.tty.stdread.readline(), term.move(27, 0) + '\n')
            self.assertEqual(self.tty.stdread.readline(), '\n')
            self.assertEqual(self.tty.stdread.readline(), '\n')
            self.assertEqual(self.tty.stdread.readline(), term.move(23, 0) + term.clear_eos + 'X\n')

            self.assertEqual(counter3.calls, ['refresh(flush=False, elapsed=None)'])

    def test_disable(self):
        mgr = _manager.Manager(stream=self.tty.stdout, enabled=False)
        self.assertFalse(mgr.enabled)
        ctr = mgr.counter()
        self.assertIsInstance(ctr, _manager.Counter)
        self.assertFalse(ctr.enabled)

        # Make sure this doesn't error
        ctr.update()
        ctr.update(4)
        ctr.refresh()
        ctr.close()
        ctr.leave = False
        ctr.close()

        mgr.write()
        mgr.stop()

        # No Output
        self.tty.stdout.write(u'X\n')
        self.assertEqual(self.tty.stdread.readline(), 'X\n')

    def test_context_manager(self):

        mgr = None

        with _manager.Manager(stream=self.tty.stdout) as manager:
            self.assertIsInstance(manager, _manager.Manager)
            self.assertTrue(manager.enabled)
            mgr = manager

        self.assertFalse(mgr.enabled)

    def test_no_resize_signal(self):

        # Test normal case initialization
        stdmgr = _manager.Manager(stream=self.tty.stdout)
        self.assertTrue(hasattr(stdmgr, 'sigwinch_orig'))
        stdmgr.counters[MockCounter(manager=stdmgr)] = 3
        stdmgr.counters[MockCounter(manager=stdmgr)] = 4

        # Test no resize signal initialization
        with mock.patch.object(_manager, 'RESIZE_SUPPORTED', False):
            manager = _manager.Manager(stream=self.tty.stdout)
            self.assertFalse(hasattr(manager, 'sigwinch_orig'))

            manager.counters[MockCounter(manager=manager)] = 3
            manager.counters[MockCounter(manager=manager)] = 4

        # Test set_scroll_area()
        with mock.patch.object(_manager.signal, 'signal',
                               wraps=_manager.signal.signal) as mocksignal:
            with mock.patch('enlighten._manager.atexit'):

                # Test no resize signal set_scroll_area
                with mock.patch.object(_manager, 'RESIZE_SUPPORTED', False):
                    with mock.patch.object(manager.term, 'change_scroll'):
                        manager._set_scroll_area()

                self.assertFalse(mocksignal.called)

                # Test normal case set_scroll_area
                with mock.patch.object(stdmgr.term, 'change_scroll'):
                    stdmgr._set_scroll_area()
                self.assertTrue(mocksignal.called)

        # Test stop()
        with mock.patch.object(_manager.signal, 'signal',
                               wraps=_manager.signal.signal) as mocksignal:

            # Test no resize signal stop
            with mock.patch.object(_manager, 'RESIZE_SUPPORTED', False):
                manager.stop()
            self.assertFalse(mocksignal.called)

            # Test normal case stop
            stdmgr.stop()
            self.assertTrue(mocksignal.called)

    def test_no_resize(self):

        with mock.patch.object(_manager.signal, 'signal',
                               wraps=_manager.signal.signal) as mocksignal:

            manager = _manager.Manager(stream=self.tty.stdout, no_resize=True)
            self.assertFalse(hasattr(manager, 'sigwinch_orig'))
            self.assertFalse(mocksignal.called)

            manager.counters[MockCounter(manager=manager)] = 3
            manager.counters[MockCounter(manager=manager)] = 4

            with mock.patch.object(manager.term, 'change_scroll'):
                manager._set_scroll_area()

            self.assertFalse(mocksignal.called)

            manager.stop()

            self.assertFalse(mocksignal.called)
Esempio n. 12
0
 def setUp(self):
     self.tty = MockTTY()
     self.terminal = _terminal.Terminal(stream=self.tty.stdout, kind='xterm-256color')
Esempio n. 13
0
 def setUpClass(cls):
     cls.tty = MockTTY()
     cls.term = blessed.Terminal(stream=cls.tty.stdout,
                                 kind='xterm-256color',
                                 force_styling=True)
     cls.term.number_of_colors = 1 << 24
Esempio n. 14
0
class TestManager(TestCase):
    def setUp(self):
        self.tty = MockTTY()
        self.resize_sig = signal.getsignal(signal.SIGWINCH)

    def tearDown(self):
        self.tty.close()
        signal.signal(signal.SIGWINCH, self.resize_sig)

    def test_init_safe(self):
        with redirect_output('stdout', self.tty.stdout):
            # Companion stream is stderr if stream is stdout
            manager = _manager.Manager()
            self.assertIs(manager.stream, sys.stdout)
            self.assertIs(manager.term.stream, sys.stdout)

    @unittest.skipIf(STDOUT_NO_FD, 'No file descriptor for stdout')
    def test_init(self):
        # Companion stream is stderr if stream is stdout
        manager = _manager.Manager()
        self.assertIs(manager.stream, sys.stdout)
        self.assertIs(manager.term.stream, sys.stdout)
        # This will fail building rpm packages since stderr is redirected
        if sys.__stderr__.isatty():
            self.assertIs(manager.companion_stream, sys.__stderr__)
            self.assertIs(manager.companion_term.stream, sys.__stderr__)

    @unittest.skipIf(STDOUT_NO_FD, 'No file descriptor for stdout')
    def test_init_companion_hc(self):
        # Hard-coded companion stream always wins
        manager = _manager.Manager(companion_stream=OUTPUT)
        self.assertIs(manager.companion_stream, OUTPUT)
        self.assertIs(manager.companion_term.stream, OUTPUT)

    @unittest.skipIf(STDOUT_NO_FD, 'No file descriptor for stdout')
    def test_init_stderr(self):
        # Companion stream is stdout if stream is stderr
        manager = _manager.Manager(stream=sys.__stderr__)
        self.assertIs(manager.stream, sys.__stderr__)
        self.assertIs(manager.term.stream, sys.__stderr__)
        # This will fail building rpm packages since stderr is redirected
        if sys.__stdout__.isatty():
            self.assertIs(manager.companion_stream, sys.__stdout__)
            self.assertIs(manager.companion_term.stream, sys.__stdout__)

    @unittest.skipIf(STDOUT_NO_FD, 'No file descriptor for stdout')
    def test_init_redirect(self):
        # If stdout is redirected, but stderr is still a tty, use it for companion
        with redirect_output('stdout', OUTPUT):
            manager = _manager.Manager()
            self.assertIs(manager.stream, sys.stdout)
            self.assertIs(manager.term.stream, sys.stdout)
            # This will fail building rpm packages since stderr is redirected
            if sys.__stderr__.isatty():
                self.assertIs(manager.companion_stream, sys.stderr)
                self.assertIs(manager.companion_term.stream, sys.stderr)

    @unittest.skipIf(STDOUT_NO_FD, 'No file descriptor for stdout')
    def test_init_stderr_redirect(self):
        # If stderr is redirected, but stdout is still a tty, use it for companion
        with redirect_output('stderr', OUTPUT):
            manager = _manager.Manager(stream=sys.stderr)
            self.assertIs(manager.stream, sys.stderr)
            self.assertIs(manager.term.stream, sys.stderr)
            # This will fail building rpm packages since stderr is redirected
            if sys.__stdout__.isatty():
                self.assertIs(manager.companion_stream, sys.stdout)
                self.assertIs(manager.companion_term.stream, sys.stdout)

    @unittest.skipIf(STDOUT_NO_FD, 'No file descriptor for stdout')
    def test_init_stderr_companion_hc(self):

        # Hard-coded companion stream always wins
        manager = _manager.Manager(stream=sys.__stderr__,
                                   companion_stream=OUTPUT)
        self.assertIs(manager.companion_stream, OUTPUT)
        self.assertIs(manager.companion_term.stream, OUTPUT)

    @unittest.skipIf(STDOUT_NO_FD, 'No file descriptor for stdout')
    def test_init_hc(self):

        # Nonstandard stream doesn't get a companion stream by default
        manager = _manager.Manager(stream=OUTPUT)
        self.assertIs(manager.stream, OUTPUT)
        self.assertIs(manager.term.stream, OUTPUT)
        self.assertIsNone(manager.companion_stream)
        self.assertIsNone(manager.companion_term)

    def test_repr(self):
        manager = _manager.Manager()
        self.assertEqual(repr(manager), "Manager(stream=%r)" % sys.stdout)

    def test_counter_and_remove(self):
        # pylint: disable=no-member,assigning-non-slot
        manager = _manager.Manager(stream=self.tty.stdout,
                                   counter_class=MockCounter)
        self.assertEqual(len(manager.counters), 0)

        with mock.patch.object(manager, '_set_scroll_area') as ssa:
            counter1 = manager.counter(leave=True)
        self.assertTrue(counter1.leave)
        self.assertEqual(len(manager.counters), 1)
        self.assertEqual(manager.counters[counter1], 1)
        self.assertEqual(counter1.calls, [])
        self.assertEqual(ssa.call_count, 1)

        with mock.patch.object(manager, '_set_scroll_area') as ssa:
            counter2 = manager.counter(leave=False)
        self.assertFalse(counter2.leave)
        self.assertEqual(len(manager.counters), 2)
        self.assertEqual(manager.counters[counter1], 2)
        self.assertEqual(manager.counters[counter2], 1)
        self.assertEqual(
            counter1.calls,
            ['clear(flush=False)', 'refresh(flush=True, elapsed=None)'])
        self.assertEqual(counter2.calls, [])
        self.assertEqual(ssa.call_count, 1)
        counter1.calls = []

        with mock.patch.object(manager, '_set_scroll_area') as ssa:
            counter3 = manager.counter(leave=False)
        self.assertFalse(counter3.leave)
        self.assertEqual(len(manager.counters), 3)
        self.assertEqual(manager.counters[counter1], 3)
        self.assertEqual(manager.counters[counter2], 2)
        self.assertEqual(manager.counters[counter3], 1)
        self.assertEqual(
            counter1.calls,
            ['clear(flush=False)', 'refresh(flush=True, elapsed=None)'])
        self.assertEqual(
            counter2.calls,
            ['clear(flush=False)', 'refresh(flush=True, elapsed=None)'])
        self.assertEqual(counter3.calls, [])
        self.assertEqual(ssa.call_count, 1)
        counter1.calls = []
        counter2.calls = []

        manager.remove(counter3)
        self.assertEqual(len(manager.counters), 2)
        self.assertFalse(counter3 in manager.counters)

        # Remove again, no error
        manager.remove(counter3)
        self.assertEqual(len(manager.counters), 2)

        manager.remove(counter1)
        self.assertEqual(len(manager.counters), 2)
        self.assertTrue(counter1 in manager.counters)

        with mock.patch.object(manager, '_set_scroll_area') as ssa:
            counter4 = manager.counter(leave=False)
        self.assertFalse(counter4.leave)
        self.assertEqual(len(manager.counters), 3)
        self.assertEqual(manager.counters[counter1], 3)
        self.assertEqual(manager.counters[counter2], 2)
        self.assertEqual(manager.counters[counter4], 1)
        self.assertEqual(counter1.calls, [])
        self.assertEqual(counter2.calls, [])
        self.assertEqual(counter4.calls, [])
        self.assertEqual(ssa.call_count, 1)

    def test_counter_position(self):
        manager = _manager.Manager(stream=self.tty.stdout, set_scroll=False)
        counter1 = manager.counter(position=4)
        self.assertEqual(manager.counters[counter1], 4)

        with self.assertRaisesRegex(ValueError,
                                    'Counter position 4 is already occupied'):
            manager.counter(position=4)

        with self.assertRaisesRegex(
                ValueError,
                'Counter position 200 is greater than terminal height'):
            manager.counter(position=200)

    def test_counter_position_pinned(self):
        """If a position is taken, use next available"""

        manager = _manager.Manager(stream=self.tty.stdout, set_scroll=False)
        counter1 = manager.counter(position=2)
        self.assertEqual(manager.counters[counter1], 2)

        counter2 = manager.counter()
        self.assertEqual(manager.counters[counter1], 2)
        self.assertEqual(manager.counters[counter2], 1)

        counter3 = manager.counter()
        self.assertEqual(manager.counters[counter1], 2)
        self.assertEqual(manager.counters[counter2], 3)
        self.assertEqual(manager.counters[counter3], 1)

        status1 = manager.status_bar(position=3)
        self.assertEqual(manager.counters[counter1], 2)
        self.assertEqual(manager.counters[counter2], 4)
        self.assertEqual(manager.counters[counter3], 1)
        self.assertEqual(manager.counters[status1], 3)

        status2 = manager.status_bar()
        self.assertEqual(manager.counters[counter1], 2)
        self.assertEqual(manager.counters[counter2], 5)
        self.assertEqual(manager.counters[counter3], 4)
        self.assertEqual(manager.counters[status1], 3)
        self.assertEqual(manager.counters[status2], 1)

    def test_inherit_kwargs(self):
        manager = _manager.Manager(stream=self.tty.stdout,
                                   counter_class=MockCounter,
                                   unit='knights',
                                   not_real=True,
                                   desc='Default')

        self.assertTrue('unit' in manager.defaults)
        self.assertTrue('desc' in manager.defaults)
        self.assertTrue('not_real' in manager.defaults)

        with mock.patch.object(manager, '_set_scroll_area'):
            ctr = manager.counter(desc='Huzzah')

        self.assertEqual(ctr.unit, 'knights')
        self.assertEqual(ctr.desc, 'Huzzah')
        self.assertFalse(hasattr(ctr, 'not_real'))

    def test_write(self):
        msg = 'test message'

        with mock.patch('enlighten._manager.Manager._set_scroll_area') as ssa:
            manager = _manager.Manager(stream=self.tty.stdout)
            counter = manager.counter(position=3)
            term = manager.term
            manager.write(msg, counter=counter)

        self.tty.stdout.write(u'X\n')
        # Carriage return is getting converted to newline
        self.assertEqual(
            self.tty.stdread.readline(),
            term.move(22, 0) + '\r' + term.clear_eol + msg + 'X\n')
        self.assertEqual(ssa.call_count, 2)

    def test_write_no_flush(self):
        """
        No real difference in our tests because stream is flushed on each new line
        If we don't flush, reading will just hang

        But we added this for coverage and as a framework future tests
        """

        msg = 'test message'

        with mock.patch('enlighten._manager.Manager._set_scroll_area') as ssa:
            manager = _manager.Manager(stream=self.tty.stdout)
            counter = manager.counter(position=3)
            term = manager.term
            manager.write(msg, counter=counter, flush=False)

        self.tty.stdout.write(u'X\n')
        # Carriage return is getting converted to newline
        self.assertEqual(
            self.tty.stdread.readline(),
            term.move(22, 0) + '\r' + term.clear_eol + msg + 'X\n')
        self.assertEqual(ssa.call_count, 2)

    def test_autorefresh(self):
        """
        Ensure auto-refreshed counters are updated when others are
        """

        manager = _manager.Manager(stream=self.tty.stdout)
        counter1 = manager.counter(count=1,
                                   total=0,
                                   counter_format=u'counter1',
                                   autorefresh=True)
        counter2 = manager.counter(count=1,
                                   total=0,
                                   counter_format=u'counter2')
        self.tty.clear()

        # Counter 1 in auto-refresh list
        self.assertIn(counter1, manager.autorefresh)

        # If auto-refreshed counter hasn't been refreshed recently refresh
        counter1.last_update = 0
        counter2.refresh()
        self.tty.stdout.write(u'X\n')
        output = self.tty.stdread.readline()
        self.assertRegex(output, 'counter2.+counter1')

        # If auto-refreshed counter has been refreshed recently, skip
        counter1.last_update = time.time() + 5
        counter2.refresh()
        self.tty.stdout.write(u'X\n')
        output = self.tty.stdread.readline()
        self.assertRegex(output, 'counter2')
        self.assertNotRegex(output, 'counter1')

    def test_set_scroll_area_disabled(self):
        manager = _manager.Manager(stream=self.tty.stdout,
                                   counter_class=MockCounter,
                                   set_scroll=False)
        manager.counters['dummy'] = 3

        manager._set_scroll_area()
        self.tty.stdout.write(u'X\n')
        self.assertEqual(self.tty.stdread.readline(), 'X\n')

    def test_set_scroll_area_no_change(self):
        manager = _manager.Manager(stream=self.tty.stdout,
                                   counter_class=MockCounter)
        manager.counters['dummy'] = 3
        manager.scroll_offset = 4

        manager._set_scroll_area()
        self.tty.stdout.write(u'X\n')
        self.assertEqual(self.tty.stdread.readline(),
                         manager.term.move(21, 0) + 'X\n')

    def test_set_scroll_area_companion(self):
        """
        Ensure when no change is made, a term.move is still called for the companion stream
        """

        manager = _manager.Manager(stream=self.tty.stdout,
                                   counter_class=MockCounter,
                                   companion_stream=self.tty.stdout)
        manager.counters['dummy'] = 3
        manager.scroll_offset = 4
        term = manager.term

        manager._set_scroll_area()
        self.tty.stdout.write(u'X\n')
        self.assertEqual(self.tty.stdread.readline(),
                         term.move(21, 0) + term.move(21, 0) + 'X\n')

    def test_set_scroll_area(self):
        manager = _manager.Manager(stream=self.tty.stdout,
                                   counter_class=MockCounter)
        manager.counters['dummy'] = 3
        term = manager.term
        stdread = self.tty.stdread
        self.assertEqual(manager.scroll_offset, 1)
        self.assertFalse(manager.process_exit)
        self.assertNotEqual(signal.getsignal(signal.SIGWINCH),
                            manager._resize_handler)

        with mock.patch('enlighten._manager.atexit') as atexit:
            with mock.patch.object(term, 'change_scroll'):
                manager._set_scroll_area()
                self.assertEqual(term.change_scroll.call_count, 1)  # pylint: disable=no-member

            self.assertEqual(manager.scroll_offset, 4)
            self.assertEqual(signal.getsignal(signal.SIGWINCH),
                             manager._resize_handler)

            self.assertEqual(stdread.readline(), term.move(24, 0) + '\n')
            self.assertEqual(stdread.readline(), '\n')
            self.assertEqual(stdread.readline(), '\n')

            self.assertTrue(manager.process_exit)

            atexit.register.assert_called_with(manager._at_exit)

        self.tty.stdout.write(u'X\n')
        self.assertEqual(stdread.readline(), term.move(21, 0) + 'X\n')

        # Run it again and make sure exit handling isn't reset
        with mock.patch('enlighten._manager.atexit') as atexit:
            with mock.patch.object(term, 'change_scroll'):
                manager._set_scroll_area(force=True)
                self.assertEqual(term.change_scroll.call_count, 1)  # pylint: disable=no-member

            self.assertFalse(atexit.register.called)

    def test_set_scroll_area_height(self):
        manager = _manager.Manager(stream=self.tty.stdout,
                                   counter_class=MockCounter)
        manager.counters['dummy'] = 3
        manager.scroll_offset = 4
        manager.height = 20
        term = manager.term

        with mock.patch('enlighten._manager.atexit') as atexit:
            with mock.patch.object(term, 'change_scroll'):
                manager._set_scroll_area()
                self.assertEqual(term.change_scroll.call_count, 1)  # pylint: disable=no-member

            self.assertEqual(manager.scroll_offset, 4)
            self.assertEqual(manager.height, 25)
            self.assertTrue(manager.process_exit)

            term.stream.write(u'X\n')
            self.assertEqual(self.tty.stdread.readline(),
                             term.move(21, 0) + 'X\n')
            atexit.register.assert_called_with(manager._at_exit)

    def test_at_exit(self):

        tty = MockTTY()

        with mock.patch('%s.reset' % TERMINAL) as reset:
            with mock.patch.object(tty, 'stdout',
                                   wraps=tty.stdout) as mockstdout:
                manager = _manager.Manager(stream=tty.stdout,
                                           counter_class=MockCounter)
                term = manager.term

                # process_exit is False
                manager._at_exit()
                self.assertFalse(reset.called)
                self.assertFalse(mockstdout.flush.called)
                # No output
                tty.stdout.write(u'X\n')
                self.assertEqual(tty.stdread.readline(), 'X\n')

                # process_exit is True, set_scroll False
                manager.process_exit = True
                manager.set_scroll = False
                manager._at_exit()
                self.assertFalse(reset.called)
                self.assertEqual(mockstdout.flush.call_count, 1)
                self.assertEqual(tty.stdread.readline(),
                                 term.move(25, 0) + term.cud1)

                # process_exit is True, set_scroll True
                manager.set_scroll = True
                manager._at_exit()
                self.assertEqual(reset.call_count, 1)
                self.assertEqual(mockstdout.flush.call_count, 2)
                self.assertEqual(tty.stdread.readline(), term.cud1)

                # Ensure companion stream gets flushed
                manager.companion_stream = tty.stdout
                manager._at_exit()
                self.assertEqual(reset.call_count, 2)
                self.assertEqual(mockstdout.flush.call_count, 4)
                self.assertEqual(tty.stdread.readline(), term.cud1)

                term = manager.term

                # Ensure no errors if tty closes before _at_exit is called
                tty.close()
                manager._at_exit()

    def test_stop(self):

        with mock.patch('%s.reset' % TERMINAL) as reset:
            manager = _manager.Manager(stream=self.tty.stdout,
                                       counter_class=MockCounter)
            manager.counters[MockCounter(manager=manager)] = 3
            manager.counters[MockCounter(manager=manager)] = 4
            term = manager.term
            self.assertIsNone(manager.companion_term)

            with mock.patch('enlighten._manager.atexit'):
                with mock.patch.object(term, 'change_scroll'):
                    manager._set_scroll_area()

            self.assertEqual(manager.scroll_offset, 5)
            self.assertEqual(signal.getsignal(signal.SIGWINCH),
                             manager._resize_handler)
            self.assertTrue(manager.process_exit)

            # Clear stream
            self.tty.stdout.write(u'X\n')
            for num in range(4 + 1):  # pylint: disable=unused-variable
                self.tty.stdread.readline()

            self.assertFalse(reset.called)
            manager.enabled = False
            manager.stop()

            # No output, No changes
            self.tty.stdout.write(u'X\n')
            self.assertEqual(self.tty.stdread.readline(), 'X\n')
            self.assertEqual(signal.getsignal(signal.SIGWINCH),
                             manager._resize_handler)
            self.assertTrue(manager.process_exit)

            manager.enabled = True
            manager.stop()

            self.assertEqual(signal.getsignal(signal.SIGWINCH),
                             manager.sigwinch_orig)
            self.assertEqual(reset.call_count, 1)

            self.tty.stdout.write(u'X\n')
            self.assertEqual(
                self.tty.stdread.readline(),
                term.move(23, 0) + term.clear_eol + term.move(24, 0) +
                term.clear_eol + 'X\n')
            self.assertFalse(manager.process_exit)
            self.assertFalse(manager.enabled)
            for counter in manager.counters:
                self.assertFalse(counter.enabled)

    def test_stop_no_set_scroll(self):
        """
        set_scroll is False
        """

        with mock.patch('%s.reset' % TERMINAL) as reset:
            manager = _manager.Manager(stream=self.tty.stdout,
                                       counter_class=MockCounter,
                                       set_scroll=False)
            manager.counters[MockCounter(manager=manager)] = 3
            manager.counters[MockCounter(manager=manager)] = 4
            term = manager.term

            with mock.patch('enlighten._manager.atexit'):
                with mock.patch.object(term, 'change_scroll'):
                    manager._set_scroll_area()

            self.assertEqual(manager.scroll_offset, 5)
            self.assertEqual(signal.getsignal(signal.SIGWINCH),
                             manager._resize_handler)
            self.assertTrue(manager.process_exit)

            # Stream empty
            self.tty.stdout.write(u'X\n')
            self.assertEqual(self.tty.stdread.readline(), 'X\n')

            manager.stop()

            self.assertEqual(signal.getsignal(signal.SIGWINCH),
                             manager.sigwinch_orig)
            self.assertFalse(reset.called)

            self.tty.stdout.write(u'X\n')
            self.assertEqual(
                self.tty.stdread.readline(),
                term.move(23, 0) + term.clear_eol + term.move(24, 0) +
                term.clear_eol + term.move(25, 0) + 'X\n')
            self.assertFalse(manager.process_exit)

    def test_stop_never_used(self):
        """
        In this case, _set_scroll_area() was never called
        """

        with mock.patch('%s.reset' % TERMINAL) as reset:
            manager = _manager.Manager(stream=self.tty.stdout,
                                       counter_class=MockCounter)
            manager.counters[MockCounter(manager=manager)] = 3
            manager.counters[MockCounter(manager=manager)] = 4
            self.assertFalse(manager.process_exit)

            manager.stop()

            self.assertEqual(signal.getsignal(signal.SIGWINCH),
                             manager.sigwinch_orig)
            self.assertEqual(reset.call_count, 1)

        # No output
        self.tty.stdout.write(u'X\n')
        self.assertEqual(self.tty.stdread.readline(), 'X\n')

    def test_stop_companion(self):
        """
        In this case, we have a companion terminal
        Just make sure we have an extra reset
        """

        manager = _manager.Manager(stream=self.tty.stdout,
                                   counter_class=MockCounter,
                                   companion_stream=self.tty.stdout)
        manager.counters[MockCounter(manager=manager)] = 3
        manager.counters[MockCounter(manager=manager)] = 4
        term = manager.term

        with mock.patch('enlighten._manager.atexit'):
            with mock.patch.object(term, 'change_scroll'):
                manager._set_scroll_area()

        with mock.patch.object(manager.companion_term, 'reset') as compReset:
            manager.stop()

            self.assertEqual(compReset.call_count, 1)

    def test_stop_position_1(self):
        """
        Ensure a line feed is given if there is a counter at position 1
        """

        manager = _manager.Manager(stream=self.tty.stdout,
                                   counter_class=MockCounter)

        manager.counters[MockCounter(manager=manager)] = 3
        with mock.patch.object(manager.term, 'feed') as termfeed:
            manager.stop()
            self.assertFalse(termfeed.called)

        manager.enabled = True
        manager.counters[MockCounter(manager=manager)] = 1
        with mock.patch.object(manager.term, 'feed') as termfeed:
            manager.stop()
            self.assertTrue(termfeed.called)

    def test_resize_handler(self):

        with mock.patch('%s.width' % TERMINAL,
                        new_callable=mock.PropertyMock) as mockheight:
            mockheight.side_effect = [80, 85, 87, 70, 70]

            manager = _manager.Manager(stream=self.tty.stdout,
                                       counter_class=MockCounter)
            counter3 = MockCounter(manager=manager)
            manager.counters[counter3] = 3
            manager.scroll_offset = 4
            term = manager.term

            manager.resize_lock = True
            with mock.patch(
                    'enlighten._manager.Manager._set_scroll_area') as ssa:
                manager._resize_handler()
                self.assertFalse(ssa.called)

            self.assertEqual(manager.width, 80)
            self.assertTrue(manager.resize_lock)

            self.tty.stdout.write(u'X\n')
            self.assertEqual(self.tty.stdread.readline(), 'X\n')

            self.assertEqual(counter3.calls, [])

            manager.resize_lock = False
            mockheight.side_effect = [80, 85, 87, 70, 70]
            with mock.patch(
                    'enlighten._manager.Manager._set_scroll_area') as ssa:
                manager._resize_handler()
                self.assertEqual(ssa.call_count, 1)

            self.assertEqual(manager.width, 70)
            self.assertFalse(manager.resize_lock)

            self.tty.stdout.write(u'X\n')
            self.assertEqual(self.tty.stdread.readline(),
                             term.move(19, 0) + term.clear_eos + 'X\n')

            self.assertEqual(counter3.calls,
                             ['refresh(flush=False, elapsed=None)'])

    def test_resize_handler_no_change(self):

        with mock.patch('%s.width' % TERMINAL,
                        new_callable=mock.PropertyMock) as mockheight:
            mockheight.side_effect = [80, 85, 87, 80, 80]

            manager = _manager.Manager(stream=self.tty.stdout,
                                       counter_class=MockCounter)
            counter3 = MockCounter(manager=manager)
            manager.counters[counter3] = 3
            manager.scroll_offset = 4

            with mock.patch(
                    'enlighten._manager.Manager._set_scroll_area') as ssa:
                manager._resize_handler()
                self.assertEqual(ssa.call_count, 1)

            self.assertEqual(manager.width, 80)

            self.tty.stdout.write(u'X\n')
            self.assertEqual(self.tty.stdread.readline(), 'X\n')

            self.assertEqual(counter3.calls,
                             ['refresh(flush=False, elapsed=None)'])

    def test_resize_handler_height_only(self):

        with mock.patch('%s.height' % TERMINAL,
                        new_callable=mock.PropertyMock) as mockheight:
            mockheight.side_effect = [25, 23, 28, 30, 30]

            manager = _manager.Manager(stream=self.tty.stdout,
                                       counter_class=MockCounter)
            counter3 = MockCounter(manager=manager)
            manager.counters[counter3] = 3
            manager.scroll_offset = 4

            with mock.patch(
                    'enlighten._manager.Manager._set_scroll_area') as ssa:
                manager._resize_handler()
            self.assertEqual(ssa.call_count, 1)

            # Height is set in _set_scroll_area which is mocked
            self.assertEqual(manager.height, 25)

            self.tty.stdout.write(u'X\n')
            self.assertEqual(self.tty.stdread.readline(), 'X\n')

            self.assertEqual(counter3.calls,
                             ['refresh(flush=False, elapsed=None)'])

    def test_disable(self):
        mgr = _manager.Manager(stream=self.tty.stdout, enabled=False)
        self.assertFalse(mgr.enabled)
        ctr = mgr.counter()
        self.assertIsInstance(ctr, _manager.Counter)
        self.assertFalse(ctr.enabled)

        # Make sure this doesn't error
        ctr.update()
        ctr.update(4)
        ctr.refresh()
        ctr.close()
        ctr.leave = False
        ctr.close()

        mgr.write()
        mgr.stop()

        # No Output
        self.tty.stdout.write(u'X\n')
        self.assertEqual(self.tty.stdread.readline(), 'X\n')

    def test_context_manager(self):

        mgr = None

        with _manager.Manager(stream=self.tty.stdout) as manager:
            self.assertIsInstance(manager, _manager.Manager)
            self.assertTrue(manager.enabled)
            mgr = manager

        self.assertFalse(mgr.enabled)

    def test_no_resize_signal(self):

        # Test normal case initialization
        stdmgr = _manager.Manager(stream=self.tty.stdout)
        self.assertTrue(hasattr(stdmgr, 'sigwinch_orig'))
        stdmgr.counters[MockCounter(manager=stdmgr)] = 3
        stdmgr.counters[MockCounter(manager=stdmgr)] = 4

        # Test no resize signal initialization
        with mock.patch.object(_manager, 'RESIZE_SUPPORTED', False):
            manager = _manager.Manager(stream=self.tty.stdout)
            self.assertFalse(hasattr(manager, 'sigwinch_orig'))

            manager.counters[MockCounter(manager=manager)] = 3
            manager.counters[MockCounter(manager=manager)] = 4

        # Test set_scroll_area()
        with mock.patch.object(_manager.signal,
                               'signal',
                               wraps=_manager.signal.signal) as mocksignal:
            with mock.patch('enlighten._manager.atexit'):

                # Test no resize signal set_scroll_area
                with mock.patch.object(_manager, 'RESIZE_SUPPORTED', False):
                    with mock.patch.object(manager.term, 'change_scroll'):
                        manager._set_scroll_area()

                self.assertFalse(mocksignal.called)

                # Test normal case set_scroll_area
                with mock.patch.object(stdmgr.term, 'change_scroll'):
                    stdmgr._set_scroll_area()
                self.assertTrue(mocksignal.called)

        # Test stop()
        with mock.patch.object(_manager.signal,
                               'signal',
                               wraps=_manager.signal.signal) as mocksignal:

            with mock.patch('%s.reset' % TERMINAL):

                # Test no resize signal stop
                with mock.patch.object(_manager, 'RESIZE_SUPPORTED', False):
                    manager.stop()
                self.assertFalse(mocksignal.called)

                # Test normal case stop
                stdmgr.stop()
                self.assertTrue(mocksignal.called)

    def test_no_resize(self):

        with mock.patch.object(_manager.signal,
                               'signal',
                               wraps=_manager.signal.signal) as mocksignal:

            manager = _manager.Manager(stream=self.tty.stdout, no_resize=True)
            self.assertFalse(hasattr(manager, 'sigwinch_orig'))
            self.assertFalse(mocksignal.called)

            manager.counters[MockCounter(manager=manager)] = 3
            manager.counters[MockCounter(manager=manager)] = 4

            with mock.patch.object(manager.term, 'change_scroll'):
                manager._set_scroll_area()

            self.assertFalse(mocksignal.called)

            with mock.patch('%s.reset' % TERMINAL):
                manager.stop()

            self.assertFalse(mocksignal.called)
Esempio n. 15
0
class TestStatusBar(TestCase):
    """
    Test the StatusBar class
    """

    def setUp(self):
        self.tty = MockTTY()
        self.manager = MockManager(stream=self.tty.stdout)

    def tearDown(self):
        self.tty.close()

    def test_static(self):
        """
        Basic static status bar
        """

        sbar = self.manager.status_bar('Hello', 'World!')
        self.assertEqual(sbar.format(), 'Hello World!' + ' ' * 68)

        sbar.update('Goodbye, World!')
        self.assertEqual(sbar.format(), 'Goodbye, World!' + ' ' * 65)

    def test_static_justify(self):
        """
        Justified static status bar
        """

        sbar = self.manager.status_bar('Hello', 'World!', justify=Justify.LEFT)
        self.assertEqual(sbar.format(), 'Hello World!' + ' ' * 68)

        sbar = self.manager.status_bar('Hello', 'World!', justify=Justify.RIGHT)
        self.assertEqual(sbar.format(), ' ' * 68 + 'Hello World!')

        sbar = self.manager.status_bar('Hello', 'World!', justify=Justify.CENTER)
        self.assertEqual(sbar.format(), ' ' * 34 + 'Hello World!' + ' ' * 34)

    def test_formatted(self):
        """
        Basic formatted status bar
        """

        sbar = self.manager.status_bar(status_format=u'Stage: {stage}, Status: {status}', stage=1,
                                       fields={'status': 'All good!'})
        self.assertEqual(sbar.format(), 'Stage: 1, Status: All good!' + ' ' * 53)
        sbar.update(stage=2)
        self.assertEqual(sbar.format(), 'Stage: 2, Status: All good!' + ' ' * 53)
        sbar.update(stage=3, status='Meh')
        self.assertEqual(sbar.format(), 'Stage: 3, Status: Meh' + ' ' * 59)

    def test_formatted_justify(self):
        """
        Justified formatted status bar
        """

        sbar = self.manager.status_bar(status_format=u'Stage: {stage}, Status: {status}', stage=1,
                                       fields={'status': 'All good!'}, justify=Justify.LEFT)
        self.assertEqual(sbar.format(), 'Stage: 1, Status: All good!' + ' ' * 53)

        sbar = self.manager.status_bar(status_format=u'Stage: {stage}, Status: {status}', stage=1,
                                       fields={'status': 'All good!'}, justify=Justify.RIGHT)
        self.assertEqual(sbar.format(), ' ' * 53 + 'Stage: 1, Status: All good!')

        sbar = self.manager.status_bar(status_format=u'Stage: {stage}, Status: {status}', stage=1,
                                       fields={'status': 'All good'}, justify=Justify.CENTER)
        self.assertEqual(sbar.format(), ' ' * 27 + 'Stage: 1, Status: All good' + ' ' * 27)

    def test_formatted_missing_field(self):
        """
        ValueError raised when a field is missing when updating status bar
        """

        fields = {'status': 'All good!'}
        sbar = self.manager.status_bar(status_format=u'Stage: {stage}, Status: {status}', stage=1,
                                       fields=fields)
        del fields['status']

        sbar.last_update = sbar.start - 5.0
        with self.assertRaisesRegex(ValueError, "'status' specified in format, but not provided"):
            sbar.update()

    def test_bad_justify(self):
        """
        ValueError raised when justify is given an invalid value
        """

        with self.assertRaisesRegex(ValueError, 'justify must be one of Justify.LEFT, '):
            self.manager.status_bar('Hello', 'World!', justify='justice')

    def test_update(self):
        """
        update() does not refresh is bar is disabled or min_delta hasn't passed
        """

        self.manager.status_bar_class = MockStatusBar
        sbar = self.manager.status_bar('Hello', 'World!')

        self.assertEqual(sbar.called, 1)
        sbar.last_update = sbar.start - 1.0
        sbar.update()
        self.assertEqual(sbar.called, 2)

        sbar.last_update = sbar.start + 5.0
        sbar.update()
        self.assertEqual(sbar.called, 2)

        sbar.last_update = sbar.last_update - 10.0
        sbar.enabled = False
        sbar.update()
        self.assertEqual(sbar.called, 2)

        sbar.enabled = True
        sbar.update()
        self.assertEqual(sbar.called, 3)

    def test_fill(self):
        """
        Fill uses remaining space
        """

        sbar = self.manager.status_bar(status_format=u'{fill}HI', fill='-')
        self.assertEqual(sbar.format(), u'-' * 78 + 'HI')

        sbar = self.manager.status_bar(status_format=u'{fill}HI{fill}', fill='-')
        self.assertEqual(sbar.format(), u'-' * 39 + 'HI' + u'-' * 39)

    def test_fill_uneven(self):
        """
        Extra fill should be equal
        """

        print(self.manager.term.width)
        sbar = self.manager.status_bar(
            status_format=u'{fill}Helloooo!{fill}Woooorld!{fill}', fill='-'
        )
        self.assertEqual(sbar.format(),
                         u'-' * 20 + 'Helloooo!' + u'-' * 21 + 'Woooorld!' + u'-' * 21)
Esempio n. 16
0
class TestBaseCounter(TestCase):
    """
    Test the BaseCounter class
    """
    def setUp(self):
        self.tty = MockTTY()
        self.manager = MockManager(stream=self.tty.stdout)

    def tearDown(self):
        self.tty.close()

    def test_init_default(self):
        """Ensure default values are set"""
        counter = BaseCounter(manager=self.manager)
        self.assertIsNone(counter.color)
        self.assertIsNone(counter.color)
        self.assertIs(counter.manager, self.manager)
        self.assertEqual(counter.count, 0)
        self.assertEqual(counter.start_count, 0)

    def test_no_manager(self):
        """Raise an error if there is no manager specified"""
        with self.assertRaisesRegex(TypeError, 'manager must be specified'):
            BaseCounter()

    def test_color_invalid(self):
        """Color must be a valid string, RGB, or int 0 - 255"""
        # Unsupported type
        with self.assertRaisesRegex(AttributeError,
                                    'Invalid color specified: 1.0'):
            BaseCounter(manager=self.manager, color=1.0)

        # Invalid String
        with self.assertRaisesRegex(AttributeError,
                                    'Invalid color specified: buggersnot'):
            BaseCounter(manager=self.manager, color='buggersnot')

        # Invalid integer
        with self.assertRaisesRegex(AttributeError,
                                    'Invalid color specified: -1'):
            BaseCounter(manager=self.manager, color=-1)
        with self.assertRaisesRegex(AttributeError,
                                    'Invalid color specified: 256'):
            BaseCounter(manager=self.manager, color=256)

        # Invalid iterable
        with self.assertRaisesRegex(AttributeError,
                                    r'Invalid color specified: \[\]'):
            BaseCounter(manager=self.manager, color=[])
        with self.assertRaisesRegex(AttributeError,
                                    r'Invalid color specified: \[1\]'):
            BaseCounter(manager=self.manager, color=[1])
        with self.assertRaisesRegex(AttributeError,
                                    r'Invalid color specified: \(1, 2\)'):
            BaseCounter(manager=self.manager, color=(1, 2))
        with self.assertRaisesRegex(
                AttributeError, r'Invalid color specified: \(1, 2, 3, 4\)'):
            BaseCounter(manager=self.manager, color=(1, 2, 3, 4))

    def test_colorize_none(self):
        """If color is None, return content unchanged"""
        counter = BaseCounter(manager=self.manager)
        self.assertEqual(counter._colorize('test'), 'test')

    def test_colorize_string(self):
        """Return string formatted with color (string)"""
        counter = BaseCounter(manager=self.manager, color='red')
        self.assertEqual(counter.color, 'red')
        self.assertEqual(counter._color, ('red', self.manager.term.red))
        self.assertNotEqual(counter._colorize('test'), 'test')
        self.assertEqual(counter._colorize('test'),
                         self.manager.term.red('test'))

    def test_colorize_string_compound(self):
        """Return string formatted with compound color (string)"""
        counter = BaseCounter(manager=self.manager, color='bold_red_on_blue')
        self.assertEqual(counter.color, 'bold_red_on_blue')
        self.assertEqual(
            counter._color,
            ('bold_red_on_blue', self.manager.term.bold_red_on_blue))
        self.assertNotEqual(counter._colorize('test'), 'test')
        self.assertEqual(counter._colorize('test'),
                         self.manager.term.bold_red_on_blue('test'))

    def test_colorize_int(self):
        """Return string formatted with color (int)"""
        counter = BaseCounter(manager=self.manager, color=40)
        self.assertEqual(counter.color, 40)
        self.assertEqual(counter._color, (40, self.manager.term.color(40)))
        self.assertNotEqual(counter._colorize('test'), 'test')
        self.assertEqual(counter._colorize('test'),
                         self.manager.term.color(40)('test'))

    def test_colorize_rgb(self):
        """Return string formatted with color (RGB)"""
        counter = BaseCounter(manager=self.manager, color=(50, 40, 60))
        self.assertEqual(counter.color, (50, 40, 60))
        self.assertEqual(
            counter._color,
            ((50, 40, 60), self.manager.term.color_rgb(50, 40, 60)))
        self.assertNotEqual(counter._colorize('test'), 'test')
        self.assertEqual(counter._colorize('test'),
                         self.manager.term.color_rgb(50, 40, 60)('test'))

    def test_call(self):
        """Returns generator when used as a function"""

        # Bad arguments
        counter = MockBaseCounter(manager=self.manager)
        with self.assertRaisesRegex(TypeError,
                                    'Argument type int is not iterable'):
            list(counter(1))
        with self.assertRaisesRegex(TypeError,
                                    'Argument type bool is not iterable'):
            list(counter([1, 2, 3], True))

        # Expected
        counter = MockBaseCounter(manager=self.manager)
        rtn = counter([1, 2, 3])
        self.assertIsInstance(rtn, GeneratorType)
        self.assertEqual(list(rtn), [1, 2, 3])
        self.assertEqual(counter.count, 3)

        # Multiple arguments
        counter = MockBaseCounter(manager=self.manager)
        rtn = counter([1, 2, 3], (3, 2, 1))
        self.assertIsInstance(rtn, GeneratorType)
        self.assertEqual(tuple(rtn), (1, 2, 3, 3, 2, 1))
        self.assertEqual(counter.count, 6)
Esempio n. 17
0
 def setUp(self):
     self.tty = MockTTY()
Esempio n. 18
0
 def setUp(self):
     self.tty = MockTTY()
     self.resize_sig = signal.getsignal(signal.SIGWINCH)
Esempio n. 19
0
 def setUp(self):
     self.tty = MockTTY()
     self.manager = MockManager(stream=self.tty.stdout)
Esempio n. 20
0
class TestBaseCounter(TestCase):
    """
    Test the BaseCounter class
    """
    def setUp(self):
        self.tty = MockTTY()
        self.manager = MockManager(stream=self.tty.stdout)

    def tearDown(self):
        self.tty.close()

    def test_init_default(self):
        """Ensure default values are set"""
        counter = enlighten._counter.BaseCounter(manager=self.manager)
        self.assertIsNone(counter.color)
        self.assertIsNone(counter.color)
        self.assertIs(counter.manager, self.manager)
        self.assertEqual(counter.count, 0)
        self.assertEqual(counter.start_count, 0)

    def test_no_manager(self):
        """Raise an error if there is no manager specified"""
        with self.assertRaisesRegex(TypeError, 'manager must be specified'):
            enlighten._counter.BaseCounter()

    def test_color(self):
        """Color must be a valid string or int 0 - 255"""
        # Unsupported type
        with self.assertRaisesRegex(TypeError,
                                    'color must be a string or integer'):
            enlighten._counter.BaseCounter(manager=self.manager, color=[])

        # Color is a string
        counter = enlighten._counter.BaseCounter(manager=self.manager,
                                                 color='red')
        self.assertEqual(counter.color, 'red')
        with self.assertRaisesRegex(ValueError, 'Unsupported color: banana'):
            enlighten._counter.BaseCounter(manager=self.manager,
                                           color='banana')

        # Color is an integer
        counter = enlighten._counter.BaseCounter(manager=self.manager,
                                                 color=15)
        self.assertEqual(counter.color, 15)
        with self.assertRaisesRegex(ValueError, 'Unsupported color: -1'):
            enlighten._counter.BaseCounter(manager=self.manager, color=-1)
        with self.assertRaisesRegex(ValueError, 'Unsupported color: 256'):
            enlighten._counter.BaseCounter(manager=self.manager, color=256)

    def test_colorize_none(self):
        """If color is None, return content unchanged"""
        counter = enlighten._counter.BaseCounter(manager=self.manager)
        self.assertEqual(counter._colorize('test'), 'test')

    def test_colorize(self):
        """Return string formatted with color"""
        # Color is a string
        counter = enlighten._counter.BaseCounter(manager=self.manager,
                                                 color='red')
        self.assertIsNone(counter._color)
        self.assertNotEqual(counter._colorize('test'), 'test')
        cache = counter._color
        self.assertEqual(counter._colorize('test'),
                         self.manager.term.red('test'))
        self.assertEqual(counter._color[0], 'red')
        self.assertIs(counter._color[1], self.manager.term.red)
        self.assertIs(counter._color, cache)

        # Color is an integer
        counter = enlighten._counter.BaseCounter(manager=self.manager,
                                                 color=40)
        self.assertIsNone(counter._color)
        self.assertNotEqual(counter._colorize('test'), 'test')
        cache = counter._color
        self.assertEqual(counter._colorize('test'),
                         self.manager.term.color(40)('test'))
        self.assertEqual(counter._color[0], 40)
        # New instance is generated each time, so just compare strings
        self.assertEqual(counter._color[1], self.manager.term.color(40))
        self.assertIs(counter._color, cache)

    def test_call(self):
        """Returns generator when used as a function"""

        # Bad arguments
        counter = MockBaseCounter(manager=self.manager)
        with self.assertRaisesRegex(TypeError,
                                    'Argument type int is not iterable'):
            list(counter(1))
        with self.assertRaisesRegex(TypeError,
                                    'Argument type bool is not iterable'):
            list(counter([1, 2, 3], True))

        # Expected
        counter = MockBaseCounter(manager=self.manager)
        rtn = counter([1, 2, 3])
        self.assertIsInstance(rtn, GeneratorType)
        self.assertEqual(list(rtn), [1, 2, 3])
        self.assertEqual(counter.count, 3)

        # Multiple arguments
        counter = MockBaseCounter(manager=self.manager)
        rtn = counter([1, 2, 3], (3, 2, 1))
        self.assertIsInstance(rtn, GeneratorType)
        self.assertEqual(tuple(rtn), (1, 2, 3, 3, 2, 1))
        self.assertEqual(counter.count, 6)