import copy import io import unittest from unittest.mock import patch from docx import Document from docx.oxml.ns import qn from document.generator import LaudoGenerator from test_evolutivo_documento import fixture, resolved class EvolutivoHierarchyTests(unittest.TestCase): def generate(self, data): imported = resolved(data) before = copy.deepcopy(imported) doc = Document() with patch('document.evolutivo.matching_local', return_value=(None, '')): LaudoGenerator()._gerar_corpo(doc, {'avaliacoes_importadas': imported}, {}) self.assertEqual(imported, before) stream = io.BytesIO() doc.save(stream) return Document(io.BytesIO(stream.getvalue())) def test_construction_subsections_preserve_parent_numbers_and_word_hierarchy(self): data = fixture((2021, 2022, 2023, 2024, 2025)) names = ['Casa principal', 'Edícula de apoio', 'Galpão de ferramentas'] for year_index, year in enumerate(data['anos']): original = year['construcao']['construcoes'][0] year['construcao']['construcoes'] = [] for index, name in enumerate(names, 1): c = copy.deepcopy(original) c.update(id=f'{year_index}-{index}', seq=index, nome=name, bdiComposicaoAdotada=[{'descricao': 'Administração', 'percentual': 5}]) year['construcao']['construcoes'].append(c) doc = self.generate(data) expected = [f'3.4.1.5.{index} Construção {index} — {name}' for index, name in enumerate(names, 1)] headings = [p for p in doc.paragraphs if p.text.startswith('3.4.1.5.')] self.assertEqual([p.text for p in headings], expected) for p in headings: self.assertEqual(p._p.pPr.find(qn('w:outlineLvl')).get(qn('w:val')), '4') self.assertTrue(p.paragraph_format.keep_with_next) self.assertEqual(p._p.getnext().tag, qn('w:tbl')) paragraphs = [p.text for p in doc.paragraphs] bdi_headings = [p.text for p in doc.paragraphs if p.text.startswith('3.4.1.3.')] self.assertEqual(bdi_headings, [f'3.4.1.3.{index} Construção {index} — {name}' for index, name in enumerate(names, 1)]) for text in ['3.4.1.1.1 Composição das áreas', '3.4.1.5 Cálculo por construção e exercício', '3.5 AVALIAÇÃO DO IMÓVEL OBJETO', '4. ESPECIFICAÇÃO DA AVALIAÇÃO', '5. CONCLUSÃO TÉCNICA']: self.assertIn(text, paragraphs) specifications = [p for p in doc.paragraphs if p.text.startswith(('4.1 ', '4.2 ', '4.3 '))] self.assertEqual(len(specifications), 3) self.assertTrue(all(p._p.pPr.find(qn('w:outlineLvl')).get(qn('w:val')) == '1' for p in specifications)) tables = [t for t in doc.tables if any(r.cells[0].text == 'Valor da construção (R$)' for r in t.rows)] self.assertEqual(len(tables), 3) self.assertTrue(all(len(t.columns) == 6 for t in tables)) def test_optional_compositions_do_not_create_empty_subsections(self): data = fixture((2021,)) c = data['anos'][0]['construcao']['construcoes'][0] c.update(areaTotal=100, areaCalculada=100, areasEquivalentes=[{'descricao': 'Área', 'area': 100, 'coeficiente': 1}]) doc = self.generate(data) paragraphs = [p.text for p in doc.paragraphs] self.assertFalse(any(p.endswith(('Composição das áreas', 'Composição do BDI')) for p in paragraphs)) self.assertEqual([p for p in paragraphs if p.startswith('3.4.1.5.')], ['3.4.1.5.1 Construção 1 — Galpão A']) self.assertIn('3.5 AVALIAÇÃO DO IMÓVEL OBJETO', paragraphs) if __name__ == '__main__': unittest.main()