File: test_blkcntnr.py

package info (click to toggle)
python-docx 1.2.0%2Bdfsg-1~exp1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 7,216 kB
  • sloc: xml: 25,323; python: 23,414; makefile: 175
file content (151 lines) | stat: -rw-r--r-- 4,953 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# pyright: reportPrivateUsage=false

"""Test suite for the docx.blkcntnr (block item container) module."""

from __future__ import annotations

from typing import cast

import pytest

import docx
from docx.blkcntnr import BlockItemContainer
from docx.document import Document
from docx.oxml.document import CT_Body
from docx.shared import Inches
from docx.table import Table
from docx.text.paragraph import Paragraph

from .unitutil.cxml import element, xml
from .unitutil.file import snippet_seq, test_file
from .unitutil.mock import FixtureRequest, Mock, call, instance_mock, method_mock


class DescribeBlockItemContainer:
    """Unit-test suite for `docx.blkcntnr.BlockItemContainer`."""

    @pytest.mark.parametrize(
        ("text", "style"), [("", None), ("Foo", None), ("", "Bar"), ("Foo", "Bar")]
    )
    def it_can_add_a_paragraph(
        self,
        text: str,
        style: str | None,
        blkcntnr: BlockItemContainer,
        _add_paragraph_: Mock,
        paragraph_: Mock,
    ):
        paragraph_.style = None
        _add_paragraph_.return_value = paragraph_

        paragraph = blkcntnr.add_paragraph(text, style)

        _add_paragraph_.assert_called_once_with(blkcntnr)
        assert paragraph_.add_run.call_args_list == ([call(text)] if text else [])
        assert paragraph.style == style
        assert paragraph is paragraph_

    def it_can_add_a_table(self, blkcntnr: BlockItemContainer):
        rows, cols, width = 2, 2, Inches(2)

        table = blkcntnr.add_table(rows, cols, width)

        assert isinstance(table, Table)
        assert table._element.xml == snippet_seq("new-tbl")[0]
        assert table._parent is blkcntnr

    def it_can_iterate_its_inner_content(self):
        document = docx.Document(test_file("blk-inner-content.docx"))

        inner_content = document.iter_inner_content()

        para = next(inner_content)
        assert isinstance(para, Paragraph)
        assert para.text == "P1"
        # --
        t = next(inner_content)
        assert isinstance(t, Table)
        assert t.rows[0].cells[0].text == "T2"
        # --
        para = next(inner_content)
        assert isinstance(para, Paragraph)
        assert para.text == "P3"
        # --
        with pytest.raises(StopIteration):
            next(inner_content)

    @pytest.mark.parametrize(
        ("blkcntnr_cxml", "expected_count"),
        [
            ("w:body", 0),
            ("w:body/w:p", 1),
            ("w:body/(w:p,w:p)", 2),
            ("w:body/(w:p,w:tbl)", 1),
            ("w:body/(w:p,w:tbl,w:p)", 2),
        ],
    )
    def it_provides_access_to_the_paragraphs_it_contains(
        self, blkcntnr_cxml: str, expected_count: int, document_: Mock
    ):
        blkcntnr = BlockItemContainer(cast(CT_Body, element(blkcntnr_cxml)), document_)

        paragraphs = blkcntnr.paragraphs

        # -- supports len() --
        assert len(paragraphs) == expected_count
        # -- is iterable --
        assert all(isinstance(p, Paragraph) for p in paragraphs)
        # -- is indexable --
        assert all(p is paragraphs[idx] for idx, p in enumerate(paragraphs))

    @pytest.mark.parametrize(
        ("blkcntnr_cxml", "expected_count"),
        [
            ("w:body", 0),
            ("w:body/w:tbl", 1),
            ("w:body/(w:tbl,w:tbl)", 2),
            ("w:body/(w:p,w:tbl)", 1),
            ("w:body/(w:tbl,w:tbl,w:p)", 2),
        ],
    )
    def it_provides_access_to_the_tables_it_contains(
        self, blkcntnr_cxml: str, expected_count: int, document_: Mock
    ):
        blkcntnr = BlockItemContainer(cast(CT_Body, element(blkcntnr_cxml)), document_)

        tables = blkcntnr.tables

        # -- supports len() --
        assert len(tables) == expected_count
        # -- is iterable --
        assert all(isinstance(t, Table) for t in tables)
        # -- is indexable --
        assert all(t is tables[idx] for idx, t in enumerate(tables))

    def it_adds_a_paragraph_to_help(self, document_: Mock):
        blkcntnr = BlockItemContainer(cast(CT_Body, element("w:body")), document_)

        new_paragraph = blkcntnr._add_paragraph()

        assert isinstance(new_paragraph, Paragraph)
        assert new_paragraph._parent == blkcntnr
        assert blkcntnr._element.xml == xml("w:body/w:p")

    # -- fixtures --------------------------------------------------------------------------------

    @pytest.fixture
    def _add_paragraph_(self, request: FixtureRequest):
        return method_mock(request, BlockItemContainer, "_add_paragraph")

    @pytest.fixture
    def blkcntnr(self, document_: Mock):
        blkcntnr_elm = cast(CT_Body, element("w:body"))
        return BlockItemContainer(blkcntnr_elm, document_)

    @pytest.fixture
    def document_(self, request: FixtureRequest):
        return instance_mock(request, Document)

    @pytest.fixture
    def paragraph_(self, request: FixtureRequest):
        return instance_mock(request, Paragraph)