|
1 | 1 | # Copyright The IETF Trust 2020, All Rights Reserved |
2 | 2 | import datetime |
| 3 | +import debug # pyflakes:ignore |
| 4 | + |
| 5 | +from unittest.mock import patch |
3 | 6 |
|
4 | 7 | from django.db import IntegrityError |
5 | 8 |
|
6 | 9 | from ietf.group.factories import GroupFactory, RoleFactory |
7 | 10 | from ietf.name.models import DocTagName |
8 | 11 | from ietf.person.factories import PersonFactory |
9 | | -from ietf.utils.test_utils import TestCase |
| 12 | +from ietf.utils.test_utils import TestCase, name_of_file_containing |
10 | 13 | from ietf.person.models import Person |
11 | | -from ietf.doc.factories import DocumentFactory, WgRfcFactory |
| 14 | +from ietf.doc.factories import DocumentFactory, WgRfcFactory, WgDraftFactory |
12 | 15 | from ietf.doc.models import State, DocumentActionHolder, DocumentAuthor, Document |
13 | | -from ietf.doc.utils import update_action_holders, add_state_change_event, update_documentauthors, fuzzy_find_documents |
| 16 | +from ietf.doc.utils import (update_action_holders, add_state_change_event, update_documentauthors, |
| 17 | + fuzzy_find_documents, rebuild_reference_relations) |
| 18 | +from ietf.utils.draft import Draft, PlaintextDraft |
| 19 | +from ietf.utils.xmldraft import XMLDraft |
14 | 20 |
|
15 | 21 |
|
16 | 22 | class ActionHoldersTests(TestCase): |
@@ -285,3 +291,140 @@ def test_fuzzy_find_documents(self): |
285 | 291 | self.do_fuzzy_find_documents_rfc_test('draft-name-with-number-01') |
286 | 292 | self.do_fuzzy_find_documents_rfc_test('draft-name-that-has-two-02-04') |
287 | 293 | self.do_fuzzy_find_documents_rfc_test('draft-wild-01-numbers-0312') |
| 294 | + |
| 295 | + |
| 296 | +class RebuildReferenceRelationsTests(TestCase): |
| 297 | + def setUp(self): |
| 298 | + super().setUp() |
| 299 | + self.doc = WgDraftFactory() # document under test |
| 300 | + # Other documents that should be found by rebuild_reference_relations |
| 301 | + self.normative, self.informative, self.unknown = WgRfcFactory.create_batch(3) |
| 302 | + for relationship in ['refnorm', 'refinfo', 'refunk', 'refold']: |
| 303 | + self.doc.relateddocument_set.create( |
| 304 | + target=WgRfcFactory().docalias.first(), |
| 305 | + relationship_id=relationship, |
| 306 | + ) |
| 307 | + self.updated = WgRfcFactory() # related document that should be left alone |
| 308 | + self.doc.relateddocument_set.create(target=self.updated.docalias.first(), relationship_id='updates') |
| 309 | + self.assertCountEqual(self.doc.relateddocument_set.values_list('relationship__slug', flat=True), |
| 310 | + ['refnorm', 'refinfo', 'refold', 'refunk', 'updates'], |
| 311 | + 'Test conditions set up incorrectly: wrong prior document relationships') |
| 312 | + for other_doc in [self.normative, self.informative, self.unknown]: |
| 313 | + self.assertEqual( |
| 314 | + self.doc.relateddocument_set.filter(target__name=other_doc.canonical_name()).count(), |
| 315 | + 0, |
| 316 | + 'Test conditions set up incorrectly: new documents already related', |
| 317 | + ) |
| 318 | + |
| 319 | + def _get_refs_return_value(self): |
| 320 | + return { |
| 321 | + self.normative.canonical_name(): Draft.REF_TYPE_NORMATIVE, |
| 322 | + self.informative.canonical_name(): Draft.REF_TYPE_INFORMATIVE, |
| 323 | + self.unknown.canonical_name(): Draft.REF_TYPE_UNKNOWN, |
| 324 | + 'draft-not-found': Draft.REF_TYPE_NORMATIVE, |
| 325 | + } |
| 326 | + |
| 327 | + def test_requires_txt_or_xml(self): |
| 328 | + result = rebuild_reference_relations(self.doc, {}) |
| 329 | + self.assertCountEqual(result.keys(), ['errors']) |
| 330 | + self.assertEqual(len(result['errors']), 1) |
| 331 | + self.assertIn('No draft text available', result['errors'][0], |
| 332 | + 'Error should be reported if no draft file is given') |
| 333 | + |
| 334 | + result = rebuild_reference_relations(self.doc, {'md': 'cant-do-this.md'}) |
| 335 | + self.assertCountEqual(result.keys(), ['errors']) |
| 336 | + self.assertEqual(len(result['errors']), 1) |
| 337 | + self.assertIn('No draft text available', result['errors'][0], |
| 338 | + 'Error should be reported if no XML or plaintext file is given') |
| 339 | + |
| 340 | + @patch.object(XMLDraft, 'get_refs') |
| 341 | + @patch.object(XMLDraft, '__init__', return_value=None) |
| 342 | + def test_xml(self, mock_init, mock_get_refs): |
| 343 | + """Should build reference relations with only XML""" |
| 344 | + mock_get_refs.return_value = self._get_refs_return_value() |
| 345 | + |
| 346 | + result = rebuild_reference_relations(self.doc, {'xml': 'file.xml'}) |
| 347 | + |
| 348 | + # if the method of calling the XMLDraft() constructor changes, this will need to be updated |
| 349 | + xmldraft_init_args, _ = mock_init.call_args |
| 350 | + self.assertEqual(xmldraft_init_args, ('file.xml',), 'XMLDraft initialized with unexpected arguments') |
| 351 | + self.assertEqual( |
| 352 | + result, |
| 353 | + { |
| 354 | + 'warnings': ['There were 1 references with no matching DocAlias'], |
| 355 | + 'unfound': ['draft-not-found'], |
| 356 | + } |
| 357 | + ) |
| 358 | + |
| 359 | + self.assertCountEqual( |
| 360 | + self.doc.relateddocument_set.values_list('target__name', 'relationship__slug'), |
| 361 | + [ |
| 362 | + (self.normative.canonical_name(), 'refnorm'), |
| 363 | + (self.informative.canonical_name(), 'refinfo'), |
| 364 | + (self.unknown.canonical_name(), 'refunk'), |
| 365 | + (self.updated.docalias.first().name, 'updates'), |
| 366 | + ] |
| 367 | + ) |
| 368 | + |
| 369 | + @patch.object(PlaintextDraft, 'get_refs') |
| 370 | + @patch.object(PlaintextDraft, '__init__', return_value=None) |
| 371 | + def test_plaintext(self, mock_init, mock_get_refs): |
| 372 | + """Should build reference relations with only plaintext""" |
| 373 | + mock_get_refs.return_value = self._get_refs_return_value() |
| 374 | + |
| 375 | + with name_of_file_containing('contents') as temp_file_name: |
| 376 | + result = rebuild_reference_relations(self.doc, {'txt': temp_file_name}) |
| 377 | + |
| 378 | + # if the method of calling the PlaintextDraft() constructor changes, this test will need to be updated |
| 379 | + _, mock_init_kwargs = mock_init.call_args |
| 380 | + self.assertEqual(mock_init_kwargs, {'text': 'contents', 'source': temp_file_name}, |
| 381 | + 'PlaintextDraft initialized with unexpected arguments') |
| 382 | + self.assertEqual( |
| 383 | + result, |
| 384 | + { |
| 385 | + 'warnings': ['There were 1 references with no matching DocAlias'], |
| 386 | + 'unfound': ['draft-not-found'], |
| 387 | + } |
| 388 | + ) |
| 389 | + |
| 390 | + self.assertCountEqual( |
| 391 | + self.doc.relateddocument_set.values_list('target__name', 'relationship__slug'), |
| 392 | + [ |
| 393 | + (self.normative.canonical_name(), 'refnorm'), |
| 394 | + (self.informative.canonical_name(), 'refinfo'), |
| 395 | + (self.unknown.canonical_name(), 'refunk'), |
| 396 | + (self.updated.docalias.first().name, 'updates'), |
| 397 | + ] |
| 398 | + ) |
| 399 | + |
| 400 | + @patch.object(PlaintextDraft, '__init__') |
| 401 | + @patch.object(XMLDraft, 'get_refs') |
| 402 | + @patch.object(XMLDraft, '__init__', return_value=None) |
| 403 | + def test_xml_and_plaintext(self, mock_init, mock_get_refs, mock_plaintext_init): |
| 404 | + """Should build reference relations with XML when plaintext also available""" |
| 405 | + mock_get_refs.return_value = self._get_refs_return_value() |
| 406 | + |
| 407 | + result = rebuild_reference_relations(self.doc, {'txt': 'file.txt', 'xml': 'file.xml'}) |
| 408 | + |
| 409 | + self.assertFalse(mock_plaintext_init.called, 'PlaintextDraft should not be used when XML is available') |
| 410 | + |
| 411 | + # if the method of calling the XMLDraft() constructor changes, this will need to be updated |
| 412 | + xmldraft_init_args, _ = mock_init.call_args |
| 413 | + self.assertEqual(xmldraft_init_args, ('file.xml',), 'XMLDraft initialized with unexpected arguments') |
| 414 | + self.assertEqual( |
| 415 | + result, |
| 416 | + { |
| 417 | + 'warnings': ['There were 1 references with no matching DocAlias'], |
| 418 | + 'unfound': ['draft-not-found'], |
| 419 | + } |
| 420 | + ) |
| 421 | + |
| 422 | + self.assertCountEqual( |
| 423 | + self.doc.relateddocument_set.values_list('target__name', 'relationship__slug'), |
| 424 | + [ |
| 425 | + (self.normative.canonical_name(), 'refnorm'), |
| 426 | + (self.informative.canonical_name(), 'refinfo'), |
| 427 | + (self.unknown.canonical_name(), 'refunk'), |
| 428 | + (self.updated.docalias.first().name, 'updates'), |
| 429 | + ] |
| 430 | + ) |
0 commit comments