Completed
Push — develop ( 40f9fa...90b933 )
by Jace
02:51
created

TestModule.test_lines_text_item_heading_no_heading_levels()   A

Complexity

Conditions 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
dl 0
loc 9
rs 9.6666
c 1
b 0
f 1
1
"""Unit tests for the doorstop.core.publisher module."""
2
3
import unittest
4
from unittest.mock import patch, Mock, MagicMock
5
6
import os
7
8
from doorstop.common import DoorstopError
9
from doorstop.core import publisher
10
11
from doorstop.core.test import FILES, EMPTY, MockDataMixIn
12
13
14
class TestModule(MockDataMixIn, unittest.TestCase):
15
    """Unit tests for the doorstop.core.publisher module."""
16
17
    @patch('os.makedirs')
18
    @patch('builtins.open')
19
    def test_publish_document(self, mock_open, mock_makedirs):
20
        """Verify a document can be published."""
21
        dirpath = os.path.join('mock', 'directory')
22
        path = os.path.join(dirpath, 'published.html')
23
        self.document.items = []
24
        # Act
25
        path2 = publisher.publish(self.document, path)
26
        # Assert
27
        self.assertIs(path, path2)
28
        mock_makedirs.assert_called_once_with(dirpath)
29
        mock_open.assert_called_once_with(path, 'wb')
30
31
    @patch('os.makedirs')
32
    @patch('builtins.open')
33
    @patch('doorstop.core.publisher.publish_lines')
34
    def test_publish_document_html(self, mock_lines, mock_open, mock_makedirs):
35
        """Verify a (mock) HTML file can be created."""
36
        dirpath = os.path.join('mock', 'directory')
37
        path = os.path.join(dirpath, 'published.custom')
38
        # Act
39
        path2 = publisher.publish(self.document, path, '.html')
40
        # Assert
41
        self.assertIs(path, path2)
42
        mock_makedirs.assert_called_once_with(dirpath)
43
        mock_open.assert_called_once_with(path, 'wb')
44
        mock_lines.assert_called_once_with(self.document, '.html',
45
                                           linkify=False)
46
47
    def test_publish_document_unknown(self):
48
        """Verify an exception is raised when publishing unknown formats."""
49
        self.assertRaises(DoorstopError,
50
                          publisher.publish, self.document, 'a.a')
51
        self.assertRaises(DoorstopError,
52
                          publisher.publish, self.document, 'a.txt', '.a')
53
54
    @patch('doorstop.core.publisher._index')
55
    @patch('os.makedirs')
56
    @patch('builtins.open')
57
    def test_publish_tree(self, mock_open, mock_makedirs, mock_index):
58
        """Verify a tree can be published."""
59
        dirpath = os.path.join('mock', 'directory')
60
        # Act
61
        dirpath2 = publisher.publish(self.mock_tree, dirpath)
62
        # Assert
63
        self.assertIs(dirpath, dirpath2)
64
        self.assertEqual(1, mock_makedirs.call_count)
65
        self.assertEqual(2, mock_open.call_count)
66
        mock_index.assert_called_once_with(dirpath, tree=self.mock_tree)
67
68
    @patch('doorstop.core.publisher._index')
69
    @patch('os.makedirs')
70
    @patch('builtins.open')
71
    def test_publish_tree_no_index(self, mock_open, mock_makedirs, mock_index):
72
        """Verify a tree can be published."""
73
        dirpath = os.path.join('mock', 'directory')
74
        # Act
75
        dirpath2 = publisher.publish(self.mock_tree, dirpath, index=False)
76
        # Assert
77
        self.assertIs(dirpath, dirpath2)
78
        self.assertEqual(1, mock_makedirs.call_count)
79
        self.assertEqual(2, mock_open.call_count)
80
        self.assertEqual(0, mock_index.call_count)
81
82
    @patch('doorstop.core.publisher._index')
83
    def test_publish_tree_no_documents(self, mock_index):
84
        """Verify a tree can be published with no documents."""
85
        dirpath = os.path.join('mock', 'directory')
86
        mock_tree = MagicMock()
87
        mock_tree.documents = []
88
        # Act
89
        path2 = publisher.publish(mock_tree, dirpath, index=False)
90
        # Assert
91
        self.assertIs(None, path2)
92
        self.assertEqual(0, mock_index.call_count)
93
94
    def test_index(self):
95
        """Verify an HTML index can be created."""
96
        # Arrange
97
        path = os.path.join(FILES, 'index.html')
98
        # Act
99
        publisher._index(FILES)  # pylint: disable=W0212
100
        # Assert
101
        self.assertTrue(os.path.isfile(path))
102
103
    def test_index_no_files(self):
104
        """Verify an HTML index is only created when files exist."""
105
        path = os.path.join(EMPTY, 'index.html')
106
        # Act
107
        publisher._index(EMPTY)  # pylint: disable=W0212
108
        # Assert
109
        self.assertFalse(os.path.isfile(path))
110
111
    def test_index_tree(self):
112
        """Verify an HTML index can be created with a tree."""
113
        path = os.path.join(FILES, 'index2.html')
114
        mock_tree = MagicMock()
115
        mock_tree.documents = []
116
        for prefix in ('SYS', 'HLR', 'LLR', 'HLT', 'LLT'):
117
            mock_document = MagicMock()
118
            mock_document.prefix = prefix
119
            mock_tree.documents.append(mock_document)
120
        mock_tree.draw = lambda: "(mock tree structure)"
121
        mock_item = Mock()
122
        mock_item.uid = 'KNOWN-001'
123
        mock_item.document = Mock()
124
        mock_item.document.prefix = 'KNOWN'
125
        mock_item_unknown = Mock(spec=['uid'])
126
        mock_item_unknown.uid = 'UNKNOWN-002'
127
        mock_trace = [
128
            (None, mock_item, None, None, None),
129
            (None, None, None, mock_item_unknown, None),
130
            (None, None, None, None, None),
131
        ]
132
        mock_tree.get_traceability = lambda: mock_trace
133
        # Act
134
        publisher._index(FILES, index="index2.html", tree=mock_tree)  # pylint: disable=W0212
135
        # Assert
136
        self.assertTrue(os.path.isfile(path))
137
138
    def test_lines_text_item(self):
139
        """Verify text can be published from an item."""
140
        with patch.object(self.item5, 'find_ref',
141
                          Mock(return_value=('path/to/mock/file', 42))):
142
            lines = publisher.publish_lines(self.item5, '.txt')
143
            text = ''.join(line + '\n' for line in lines)
144
        self.assertIn("Reference: path/to/mock/file (line 42)", text)
145
146
    def test_lines_text_item_heading(self):
147
        """Verify text can be published from an item (heading)."""
148
        expected = "1.1     Heading\n\n"
149
        lines = publisher.publish_lines(self.item, '.txt')
150
        # Act
151
        text = ''.join(line + '\n' for line in lines)
152
        # Assert
153
        self.assertEqual(expected, text)
154
155
    @patch('doorstop.settings.PUBLISH_HEADING_LEVELS', False)
156
    def test_lines_text_item_heading_no_heading_levels(self):
157
        """Verify an item heading level can be ommitted."""
158
        expected = "Heading\n\n"
159
        lines = publisher.publish_lines(self.item, '.txt')
160
        # Act
161
        text = ''.join(line + '\n' for line in lines)
162
        # Assert
163
        self.assertEqual(expected, text)
164
165
    @patch('doorstop.settings.PUBLISH_CHILD_LINKS', False)
166
    def test_lines_text_item_normative(self):
167
        """Verify text can be published from an item (normative)."""
168
        expected = ("1.2     req4" + '\n\n'
169
                    "        This shall..." + '\n\n'
170
                    "        Reference: Doorstop.sublime-project" + '\n\n'
171
                    "        Links: sys4" + '\n\n')
172
        lines = publisher.publish_lines(self.item3, '.txt')
173
        # Act
174
        text = ''.join(line + '\n' for line in lines)
175
        # Assert
176
        self.assertEqual(expected, text)
177
178
    @patch('doorstop.settings.CHECK_REF', False)
179
    def test_lines_text_item_no_ref(self):
180
        """Verify text can be published without checking references."""
181
        lines = publisher.publish_lines(self.item5, '.txt')
182
        text = ''.join(line + '\n' for line in lines)
183
        self.assertIn("Reference: 'abc123'", text)
184
185
    @patch('doorstop.settings.PUBLISH_CHILD_LINKS', True)
186
    def test_lines_text_item_with_child_links(self):
187
        """Verify text can be published with child links."""
188
        # Act
189
        lines = publisher.publish_lines(self.item2, '.txt')
190
        text = ''.join(line + '\n' for line in lines)
191
        # Assert
192
        self.assertIn("Child links: tst1", text)
193
194
    def test_lines_markdown_item(self):
195
        """Verify Markdown can be published from an item."""
196
        with patch.object(self.item5, 'find_ref',
197
                          Mock(return_value=('path/to/mock/file', 42))):
198
            lines = publisher.publish_lines(self.item5, '.md')
199
            text = ''.join(line + '\n' for line in lines)
200
        self.assertIn("> `path/to/mock/file` (line 42)", text)
201
202
    def test_lines_markdown_item_heading(self):
203
        """Verify Markdown can be published from an item (heading)."""
204
        expected = "## 1.1 Heading {: #req3 }\n\n"
205
        # Act
206
        lines = publisher.publish_lines(self.item, '.md', linkify=True)
207
        text = ''.join(line + '\n' for line in lines)
208
        # Assert
209
        self.assertEqual(expected, text)
210
211
    @patch('doorstop.settings.PUBLISH_HEADING_LEVELS', False)
212
    def test_lines_markdown_item_heading_no_heading_levels(self):
213
        """Verify an item heading level can be ommitted."""
214
        expected = "## Heading {: #req3 }\n\n"
215
        # Act
216
        lines = publisher.publish_lines(self.item, '.md', linkify=True)
217
        text = ''.join(line + '\n' for line in lines)
218
        # Assert
219
        self.assertEqual(expected, text)
220
221
    @patch('doorstop.settings.PUBLISH_CHILD_LINKS', False)
222
    def test_lines_markdown_item_normative(self):
223
        """Verify Markdown can be published from an item (normative)."""
224
        expected = ("## 1.2 req4" + '\n\n'
225
                    "This shall..." + '\n\n'
226
                    "> `Doorstop.sublime-project`" + '\n\n'
227
                    "*Links: sys4*" + '\n\n')
228
        # Act
229
        lines = publisher.publish_lines(self.item3, '.md', linkify=False)
230
        text = ''.join(line + '\n' for line in lines)
231
        # Assert
232
        self.assertEqual(expected, text)
233
234
    @patch('doorstop.settings.PUBLISH_CHILD_LINKS', True)
235
    def test_lines_markdown_item_with_child_links(self):
236
        """Verify Markdown can be published from an item w/ child links."""
237
        # Act
238
        lines = publisher.publish_lines(self.item2, '.md')
239
        text = ''.join(line + '\n' for line in lines)
240
        # Assert
241
        self.assertIn("Child links: tst1", text)
242
243
    @patch('doorstop.settings.PUBLISH_CHILD_LINKS', False)
244
    def test_lines_markdown_item_without_child_links(self):
245
        """Verify Markdown can be published from an item w/o child links."""
246
        # Act
247
        lines = publisher.publish_lines(self.item2, '.md')
248
        text = ''.join(line + '\n' for line in lines)
249
        # Assert
250
        self.assertNotIn("Child links", text)
251
252
    @patch('doorstop.settings.PUBLISH_BODY_LEVELS', False)
253
    @patch('doorstop.settings.PUBLISH_CHILD_LINKS', False)
254
    def test_lines_markdown_item_without_body_levels(self):
255
        """Verify Markdown can be published from an item (no body levels)."""
256
        expected = ("## req4" + '\n\n'
257
                    "This shall..." + '\n\n'
258
                    "> `Doorstop.sublime-project`" + '\n\n'
259
                    "*Links: sys4*" + '\n\n')
260
        # Act
261
        lines = publisher.publish_lines(self.item3, '.md', linkify=False)
262
        text = ''.join(line + '\n' for line in lines)
263
        # Assert
264
        self.assertEqual(expected, text)
265
266
    @patch('doorstop.settings.CHECK_REF', False)
267
    def test_lines_markdown_item_no_ref(self):
268
        """Verify Markdown can be published without checking references."""
269
        lines = publisher.publish_lines(self.item5, '.md')
270
        text = ''.join(line + '\n' for line in lines)
271
        self.assertIn("> 'abc123'", text)
272
273
    def test_lines_html_item(self):
274
        """Verify HTML can be published from an item."""
275
        expected = '<h2>1.1 Heading</h2>\n'
276
        # Act
277
        lines = publisher.publish_lines(self.item, '.html')
278
        text = ''.join(line + '\n' for line in lines)
279
        # Assert
280
        self.assertEqual(expected, text)
281
282
    @patch('doorstop.settings.PUBLISH_HEADING_LEVELS', False)
283
    def test_lines_html_item_no_heading_levels(self):
284
        """Verify an item heading level can be ommitted."""
285
        expected = '<h2>Heading</h2>\n'
286
        # Act
287
        lines = publisher.publish_lines(self.item, '.html')
288
        text = ''.join(line + '\n' for line in lines)
289
        # Assert
290
        self.assertEqual(expected, text)
291
292
    def test_lines_html_item_linkify(self):
293
        """Verify HTML (hyper) can be published from an item."""
294
        expected = '<h2 id="req3">1.1 Heading</h2>\n'
295
        # Act
296
        lines = publisher.publish_lines(self.item, '.html', linkify=True)
297
        text = ''.join(line + '\n' for line in lines)
298
        # Assert
299
        self.assertEqual(expected, text)
300
301
    @patch('doorstop.settings.PUBLISH_CHILD_LINKS', True)
302
    def test_lines_html_item_with_child_links(self):
303
        """Verify HTML can be published from an item w/ child links."""
304
        # Act
305
        lines = publisher.publish_lines(self.item2, '.html')
306
        text = ''.join(line + '\n' for line in lines)
307
        # Assert
308
        self.assertIn("Child links: tst1", text)
309
310
    @patch('doorstop.settings.PUBLISH_CHILD_LINKS', False)
311
    def test_lines_html_item_without_child_links(self):
312
        """Verify HTML can be published from an item w/o child links."""
313
        # Act
314
        lines = publisher.publish_lines(self.item2, '.html')
315
        text = ''.join(line + '\n' for line in lines)
316
        # Assert
317
        self.assertNotIn("Child links", text)
318
319
    @patch('doorstop.settings.PUBLISH_CHILD_LINKS', True)
320
    def test_lines_html_item_with_child_links_linkify(self):
321
        """Verify HTML (hyper) can be published from an item w/ child links."""
322
        # Act
323
        lines = publisher.publish_lines(self.item2, '.html', linkify=True)
324
        text = ''.join(line + '\n' for line in lines)
325
        # Assert
326
        self.assertIn("Child links:", text)
327
        self.assertIn("tst.html#tst1", text)
328
329
    def test_lines_unknown(self):
330
        """Verify an exception is raised when iterating an unknown format."""
331
        # Act
332
        gen = publisher.publish_lines(self.document, '.a')
333
        # Assert
334
        self.assertRaises(DoorstopError, list, gen)
335