1# -*- coding: utf-8 -*-
2# Copyright 2017 - 2020 Avram Lubkin, All Rights Reserved
3
4# This Source Code Form is subject to the terms of the Mozilla Public
5# License, v. 2.0. If a copy of the MPL was not distributed with this
6# file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
8"""
9Test module for enlighten._statusbar
10"""
11
12from enlighten import EnlightenWarning, Justify
13
14import tests
15from tests import TestCase, MockManager, MockTTY, MockStatusBar, PY2, unittest
16
17
18class TestStatusBar(TestCase):
19    """
20    Test the StatusBar class
21    """
22
23    def setUp(self):
24        self.tty = MockTTY()
25        self.manager = MockManager(stream=self.tty.stdout)
26
27    def tearDown(self):
28        self.tty.close()
29
30    def test_static(self):
31        """
32        Basic static status bar
33        """
34
35        sbar = self.manager.status_bar('Hello', 'World!')
36        self.assertEqual(sbar.format(), 'Hello World!' + ' ' * 68)
37
38        sbar.update('Goodbye, World!')
39        self.assertEqual(sbar.format(), 'Goodbye, World!' + ' ' * 65)
40
41    def test_static_justify(self):
42        """
43        Justified static status bar
44        """
45
46        sbar = self.manager.status_bar('Hello', 'World!', justify=Justify.LEFT)
47        self.assertEqual(sbar.format(), 'Hello World!' + ' ' * 68)
48
49        sbar = self.manager.status_bar('Hello', 'World!', justify=Justify.RIGHT)
50        self.assertEqual(sbar.format(), ' ' * 68 + 'Hello World!')
51
52        sbar = self.manager.status_bar('Hello', 'World!', justify=Justify.CENTER)
53        self.assertEqual(sbar.format(), ' ' * 34 + 'Hello World!' + ' ' * 34)
54
55    def test_formatted(self):
56        """
57        Basic formatted status bar
58        """
59
60        sbar = self.manager.status_bar(status_format=u'Stage: {stage}, Status: {status}', stage=1,
61                                       fields={'status': 'All good!'})
62        self.assertEqual(sbar.format(), 'Stage: 1, Status: All good!' + ' ' * 53)
63        sbar.update(stage=2)
64        self.assertEqual(sbar.format(), 'Stage: 2, Status: All good!' + ' ' * 53)
65        sbar.update(stage=3, status='Meh')
66        self.assertEqual(sbar.format(), 'Stage: 3, Status: Meh' + ' ' * 59)
67
68    def test_formatted_justify(self):
69        """
70        Justified formatted status bar
71        """
72
73        sbar = self.manager.status_bar(status_format=u'Stage: {stage}, Status: {status}', stage=1,
74                                       fields={'status': 'All good!'}, justify=Justify.LEFT)
75        self.assertEqual(sbar.format(), 'Stage: 1, Status: All good!' + ' ' * 53)
76
77        sbar = self.manager.status_bar(status_format=u'Stage: {stage}, Status: {status}', stage=1,
78                                       fields={'status': 'All good!'}, justify=Justify.RIGHT)
79        self.assertEqual(sbar.format(), ' ' * 53 + 'Stage: 1, Status: All good!')
80
81        sbar = self.manager.status_bar(status_format=u'Stage: {stage}, Status: {status}', stage=1,
82                                       fields={'status': 'All good'}, justify=Justify.CENTER)
83        self.assertEqual(sbar.format(), ' ' * 27 + 'Stage: 1, Status: All good' + ' ' * 27)
84
85    def test_formatted_missing_field(self):
86        """
87        ValueError raised when a field is missing when updating status bar
88        """
89
90        fields = {'status': 'All good!'}
91        sbar = self.manager.status_bar(status_format=u'Stage: {stage}, Status: {status}', stage=1,
92                                       fields=fields)
93        del fields['status']
94
95        sbar.last_update = sbar.start - 5.0
96        with self.assertRaisesRegex(ValueError, "'status' specified in format, but not provided"):
97            sbar.update()
98
99    def test_bad_justify(self):
100        """
101        ValueError raised when justify is given an invalid value
102        """
103
104        with self.assertRaisesRegex(ValueError, 'justify must be one of Justify.LEFT, '):
105            self.manager.status_bar('Hello', 'World!', justify='justice')
106
107    def test_update(self):
108        """
109        update() does not refresh is bar is disabled or min_delta hasn't passed
110        """
111
112        self.manager.status_bar_class = MockStatusBar
113        sbar = self.manager.status_bar('Hello', 'World!')
114
115        self.assertEqual(sbar.called, 1)
116        sbar.last_update = sbar.start - 1.0
117        sbar.update()
118        self.assertEqual(sbar.called, 2)
119
120        sbar.last_update = sbar.start + 5.0
121        sbar.update()
122        self.assertEqual(sbar.called, 2)
123
124        sbar.last_update = sbar.last_update - 10.0
125        sbar.enabled = False
126        sbar.update()
127        self.assertEqual(sbar.called, 2)
128
129        sbar.enabled = True
130        sbar.update()
131        self.assertEqual(sbar.called, 3)
132
133    def test_fill(self):
134        """
135        Fill uses remaining space
136        """
137
138        sbar = self.manager.status_bar(status_format=u'{fill}HI', fill='-')
139        self.assertEqual(sbar.format(), u'-' * 78 + 'HI')
140
141        sbar = self.manager.status_bar(status_format=u'{fill}HI{fill}', fill='-')
142        self.assertEqual(sbar.format(), u'-' * 39 + 'HI' + u'-' * 39)
143
144    def test_fill_uneven(self):
145        """
146        Extra fill should be equal
147        """
148
149        sbar = self.manager.status_bar(
150            status_format=u'{fill}Helloooo!{fill}Woooorld!{fill}', fill='-'
151        )
152        self.assertEqual(sbar.format(),
153                         u'-' * 20 + 'Helloooo!' + u'-' * 21 + 'Woooorld!' + u'-' * 21)
154
155    @unittest.skipIf(PY2, 'Skip warnings tests in Python 2')
156    def test_reserve_fields(self):
157        """
158        When reserved fields are used, a warning is raised
159        """
160
161        with self.assertWarnsRegex(EnlightenWarning, 'Ignoring reserved fields') as warn:
162            self.manager.status_bar(status_format=u'Stage: {stage}, Fill: {fill}', stage=1,
163                                    fields={'fill': 'Reserved field'})
164        self.assertRegex(tests.__file__, warn.filename)
165
166        with self.assertWarnsRegex(EnlightenWarning, 'Ignoring reserved fields') as warn:
167            self.manager.status_bar(status_format=u'Stage: {stage}, elapsed: {elapsed}', stage=1,
168                                    elapsed='Reserved field')
169        self.assertRegex(tests.__file__, warn.filename)
170