1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <swmodeltestbase.hxx>
11 #include <AccessibilityCheck.hxx>
12 #include <AccessibilityIssue.hxx>
13 #include <OnlineAccessibilityCheck.hxx>
15 #include <vcl/scheduler.hxx>
16 #include <comphelper/propertysequence.hxx>
18 #include <comphelper/scopeguard.hxx>
19 #include <officecfg/Office/Common.hxx>
21 class AccessibilityCheckTest
: public SwModelTestBase
24 AccessibilityCheckTest()
25 : SwModelTestBase("/sw/qa/core/accessibilitycheck/data/")
30 CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest
, testCheckDocumentIssues
)
32 createSwDoc("DocumentTest.odt");
33 SwDoc
* pDoc
= getSwDoc();
35 sw::AccessibilityCheck
aCheck(pDoc
);
37 auto& aIssues
= aCheck
.getIssueCollection().getIssues();
38 CPPUNIT_ASSERT_EQUAL(size_t(2), aIssues
.size());
39 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::DOCUMENT_LANGUAGE
, aIssues
[0]->m_eIssueID
);
40 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::DOCUMENT_TITLE
, aIssues
[1]->m_eIssueID
);
43 CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest
, testTableSplitMergeAndAltText
)
45 createSwDoc("AccessibilityTests1.odt");
46 SwDoc
* pDoc
= getSwDoc();
48 sw::AccessibilityCheck
aCheck(pDoc
);
50 auto& aIssues
= aCheck
.getIssueCollection().getIssues();
51 CPPUNIT_ASSERT_EQUAL(size_t(6), aIssues
.size());
53 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::NO_ALT_GRAPHIC
, aIssues
[0]->m_eIssueID
);
54 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TABLE_MERGE_SPLIT
, aIssues
[1]->m_eIssueID
);
55 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TABLE_MERGE_SPLIT
, aIssues
[2]->m_eIssueID
);
56 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TABLE_MERGE_SPLIT
, aIssues
[3]->m_eIssueID
);
57 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TABLE_MERGE_SPLIT
, aIssues
[4]->m_eIssueID
);
58 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::NO_ALT_SHAPE
, aIssues
[5]->m_eIssueID
);
61 CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest
, testCheckParagraphIssues
)
63 // Tests whether formatting issues are detected when the whole paragraph has them instead of
64 // some text inside the paragraph
65 createSwDoc("ParagraphTest.odt");
66 SwDoc
* pDoc
= getSwDoc();
68 sw::AccessibilityCheck
aCheck(pDoc
);
70 auto& aIssues
= aCheck
.getIssueCollection().getIssues();
71 CPPUNIT_ASSERT_EQUAL(size_t(1), aIssues
.size());
72 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[0]->m_eIssueID
);
75 CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest
, testCheckBackgroundImage
)
77 createSwDoc("BackgroundImageTest.odt");
78 SwDoc
* pDoc
= getSwDoc();
80 sw::AccessibilityCheck
aCheck(pDoc
);
82 auto& aIssues
= aCheck
.getIssueCollection().getIssues();
83 CPPUNIT_ASSERT_EQUAL(size_t(1), aIssues
.size());
84 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::DOCUMENT_BACKGROUND
, aIssues
[0]->m_eIssueID
);
87 CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest
, testCheckNewlineSpace
)
89 createSwDoc("NewlineTest.odt");
90 SwDoc
* pDoc
= getSwDoc();
92 sw::AccessibilityCheck
aCheck(pDoc
);
94 auto& aIssues
= aCheck
.getIssueCollection().getIssues();
95 CPPUNIT_ASSERT_EQUAL(size_t(2), aIssues
.size());
96 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[0]->m_eIssueID
);
97 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[1]->m_eIssueID
);
100 CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest
, testCheckSpacebarSpace
)
102 createSwDoc("SpaceTest.odt");
103 SwDoc
* pDoc
= getSwDoc();
104 CPPUNIT_ASSERT(pDoc
);
105 sw::AccessibilityCheck
aCheck(pDoc
);
107 auto& aIssues
= aCheck
.getIssueCollection().getIssues();
108 CPPUNIT_ASSERT_EQUAL(size_t(1), aIssues
.size());
109 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[0]->m_eIssueID
);
112 CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest
, testHyperlinks
)
114 createSwDoc("HyperlinkTest.odt");
115 SwDoc
* pDoc
= getSwDoc();
116 CPPUNIT_ASSERT(pDoc
);
117 sw::AccessibilityCheck
aCheck(pDoc
);
119 auto& aIssues
= aCheck
.getIssueCollection().getIssues();
120 CPPUNIT_ASSERT_EQUAL(size_t(2), aIssues
.size());
121 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::HYPERLINK_SHORT
, aIssues
[0]->m_eIssueID
);
122 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::HYPERLINK_IS_TEXT
, aIssues
[1]->m_eIssueID
);
125 CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest
, testCheckHighlightedText
)
127 createSwDoc("HighlightTest.odt");
128 SwDoc
* pDoc
= getSwDoc();
129 CPPUNIT_ASSERT(pDoc
);
130 sw::AccessibilityCheck
aCheck(pDoc
);
132 auto& aIssues
= aCheck
.getIssueCollection().getIssues();
133 CPPUNIT_ASSERT_EQUAL(size_t(1), aIssues
.size());
134 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[0]->m_eIssueID
);
137 CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest
, testNumberingCheck
)
139 createSwDoc("AccessibilityTests_NumberingCheck.odt");
140 SwDoc
* pDoc
= getSwDoc();
141 CPPUNIT_ASSERT(pDoc
);
142 sw::AccessibilityCheck
aCheck(pDoc
);
144 auto& aIssues
= aCheck
.getIssueCollection().getIssues();
145 CPPUNIT_ASSERT_EQUAL(size_t(5), aIssues
.size());
146 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::MANUAL_NUMBERING
, aIssues
[0]->m_eIssueID
);
147 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::MANUAL_NUMBERING
, aIssues
[1]->m_eIssueID
);
148 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::MANUAL_NUMBERING
, aIssues
[2]->m_eIssueID
);
149 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::MANUAL_NUMBERING
, aIssues
[3]->m_eIssueID
);
150 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::MANUAL_NUMBERING
, aIssues
[4]->m_eIssueID
);
153 CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest
, testCheckFakeFootnote
)
155 createSwDoc("FakeFootnoteTest.odt");
156 SwDoc
* pDoc
= getSwDoc();
157 CPPUNIT_ASSERT(pDoc
);
158 sw::AccessibilityCheck
aCheck(pDoc
);
160 auto& aIssues
= aCheck
.getIssueCollection().getIssues();
161 CPPUNIT_ASSERT_EQUAL(size_t(2), aIssues
.size());
162 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::FAKE_FOOTNOTE
, aIssues
[0]->m_eIssueID
);
163 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::FAKE_FOOTNOTE
, aIssues
[1]->m_eIssueID
);
166 CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest
, testCheckFakeCaption
)
168 createSwDoc("FakeCaptionTest.odt");
169 SwDoc
* pDoc
= getSwDoc();
170 CPPUNIT_ASSERT(pDoc
);
171 sw::AccessibilityCheck
aCheck(pDoc
);
173 auto& aIssues
= aCheck
.getIssueCollection().getIssues();
174 CPPUNIT_ASSERT_EQUAL(size_t(1), aIssues
.size());
175 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::FAKE_CAPTION
, aIssues
[0]->m_eIssueID
);
178 CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest
, testCheckTableFormatting
)
180 createSwDoc("TableFormattingTest.odt");
181 SwDoc
* pDoc
= getSwDoc();
182 CPPUNIT_ASSERT(pDoc
);
183 sw::AccessibilityCheck
aCheck(pDoc
);
185 auto& aIssues
= aCheck
.getIssueCollection().getIssues();
186 CPPUNIT_ASSERT_EQUAL(size_t(1), aIssues
.size());
187 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TABLE_FORMATTING
, aIssues
[0]->m_eIssueID
);
190 CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest
, testCheckTabsFormatting
)
192 createSwDoc("TabsTest.odt");
193 SwDoc
* pDoc
= getSwDoc();
194 CPPUNIT_ASSERT(pDoc
);
195 sw::AccessibilityCheck
aCheck(pDoc
);
197 auto& aIssues
= aCheck
.getIssueCollection().getIssues();
198 CPPUNIT_ASSERT_EQUAL(size_t(4), aIssues
.size());
199 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[0]->m_eIssueID
);
200 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[1]->m_eIssueID
);
201 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[2]->m_eIssueID
);
202 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[3]->m_eIssueID
);
207 std::vector
<std::shared_ptr
<sfx::AccessibilityIssue
>>
208 scanAccessibilityIssuesOnNodes(SwDoc
* pDocument
)
210 std::vector
<std::shared_ptr
<sfx::AccessibilityIssue
>> aIssues
;
211 auto const& pNodes
= pDocument
->GetNodes();
212 for (SwNodeOffset
n(0); n
< pNodes
.Count(); ++n
)
214 SwNode
* pNode
= pNodes
[n
];
215 auto& pCollection
= pNode
->getAccessibilityCheckStatus().pCollection
;
218 for (auto& pIssue
: pCollection
->getIssues())
220 aIssues
.push_back(pIssue
);
227 void checkIssuePosition(std::shared_ptr
<sfx::AccessibilityIssue
> const& pIssue
, int nLine
,
228 sal_Int32 nStart
, sal_Int32 nEnd
, SwNodeOffset nIndex
)
230 auto* pSwIssue
= static_cast<sw::AccessibilityIssue
*>(pIssue
.get());
232 OString sFailMessage
= OString::Concat("Start doesn't match at line: ")
233 + OString::Concat(OString::number(nLine
));
234 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailMessage
.getStr(), nStart
, pSwIssue
->getStart());
237 = OString::Concat("End doesn't match at line: ") + OString::Concat(OString::number(nLine
));
238 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailMessage
.getStr(), nEnd
, pSwIssue
->getEnd());
240 sFailMessage
= OString::Concat("Offset doesn't match at line: ")
241 + OString::Concat(OString::number(nLine
));
242 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailMessage
.getStr(), nIndex
, pSwIssue
->getNode()->GetIndex());
245 } // end anonymous ns
247 CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest
, testOnlineNodeSplitAppend
)
249 // Checks the a11y checker is setting the a11y issues to the nodes
250 // correctly when splitting and appending nodes (through undo), which
251 // happen on editing all the time.
252 // When a node is split, it can happen that both nodes get a11y issues
253 // if the node splits the area of direct formatting.
255 createSwDoc("OnlineCheck.odt");
256 SwDoc
* pDoc
= getSwDoc();
257 CPPUNIT_ASSERT(pDoc
);
258 SwWrtShell
* pWrtShell
= pDoc
->GetDocShell()->GetWrtShell();
259 CPPUNIT_ASSERT(pWrtShell
);
261 // Enable online a11y checker
263 auto pBatch(comphelper::ConfigurationChanges::create());
264 officecfg::Office::Common::Accessibility::OnlineAccessibilityCheck::set(true, pBatch
);
267 comphelper::ScopeGuard
g([] {
268 auto pBatch(comphelper::ConfigurationChanges::create());
269 officecfg::Office::Common::Accessibility::OnlineAccessibilityCheck::set(false, pBatch
);
273 Scheduler::ProcessEventsToIdle();
275 // Check we have 2 a11y issue
276 CPPUNIT_ASSERT_EQUAL(sal_Int32(2),
277 pDoc
->getOnlineAccessibilityCheck()->getNumberOfAccessibilityIssues());
278 auto aIssues
= scanAccessibilityIssuesOnNodes(pDoc
);
279 CPPUNIT_ASSERT_EQUAL(size_t(2), aIssues
.size());
280 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[0]->m_eIssueID
);
281 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[1]->m_eIssueID
);
282 checkIssuePosition(aIssues
[0], __LINE__
, 0, 32, SwNodeOffset(9));
283 checkIssuePosition(aIssues
[1], __LINE__
, 33, 136, SwNodeOffset(9));
285 // Position the cursor and hit "enter" (trigger split-node action)
286 pWrtShell
->Right(SwCursorSkipMode::Chars
, /*bSelect=*/false, 33, /*bBasicCall=*/false);
287 pWrtShell
->SplitNode();
290 CPPUNIT_ASSERT_EQUAL(OUString("He heard quiet steps behind him. "),
291 getParagraph(1)->getString());
292 CPPUNIT_ASSERT_EQUAL(OUString("That didn't bode well. Who could be following him this late at "
293 "night and in this deadbeat part of town?"),
294 getParagraph(2)->getString());
295 CPPUNIT_ASSERT_EQUAL(sal_Int32(2),
296 pDoc
->getOnlineAccessibilityCheck()->getNumberOfAccessibilityIssues());
298 aIssues
= scanAccessibilityIssuesOnNodes(pDoc
);
299 CPPUNIT_ASSERT_EQUAL(size_t(2), aIssues
.size());
300 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[0]->m_eIssueID
);
301 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[1]->m_eIssueID
);
302 checkIssuePosition(aIssues
[0], __LINE__
, 0, 32, SwNodeOffset(9));
303 checkIssuePosition(aIssues
[1], __LINE__
, 0, 103, SwNodeOffset(10));
305 // Position cursor and split again
306 pWrtShell
->Down(/*bSelect*/ false, /*nCount*/ 0);
307 pWrtShell
->Right(SwCursorSkipMode::Chars
, /*bSelect=*/false, 23, /*bBasicCall=*/false);
308 pWrtShell
->SplitNode();
311 CPPUNIT_ASSERT_EQUAL(OUString("He heard quiet steps behind him. "),
312 getParagraph(1)->getString());
313 CPPUNIT_ASSERT_EQUAL(OUString("That didn't bode well. "), getParagraph(2)->getString());
314 CPPUNIT_ASSERT_EQUAL(
316 "Who could be following him this late at night and in this deadbeat part of town?"),
317 getParagraph(3)->getString());
318 CPPUNIT_ASSERT_EQUAL(sal_Int32(3),
319 pDoc
->getOnlineAccessibilityCheck()->getNumberOfAccessibilityIssues());
320 aIssues
= scanAccessibilityIssuesOnNodes(pDoc
);
321 CPPUNIT_ASSERT_EQUAL(size_t(3), aIssues
.size());
322 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[0]->m_eIssueID
);
323 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[1]->m_eIssueID
);
324 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[2]->m_eIssueID
);
325 checkIssuePosition(aIssues
[0], __LINE__
, 0, 32, SwNodeOffset(9));
326 checkIssuePosition(aIssues
[1], __LINE__
, 0, 23, SwNodeOffset(10));
327 checkIssuePosition(aIssues
[2], __LINE__
, 0, 80, SwNodeOffset(11));
329 // Undo second change
330 dispatchCommand(mxComponent
, ".uno:Undo", {});
331 CPPUNIT_ASSERT_EQUAL(OUString("He heard quiet steps behind him. "),
332 getParagraph(1)->getString());
333 CPPUNIT_ASSERT_EQUAL(OUString("That didn't bode well. Who could be following him this late at "
334 "night and in this deadbeat part of town?"),
335 getParagraph(2)->getString());
336 CPPUNIT_ASSERT_EQUAL(sal_Int32(2),
337 pDoc
->getOnlineAccessibilityCheck()->getNumberOfAccessibilityIssues());
338 aIssues
= scanAccessibilityIssuesOnNodes(pDoc
);
339 CPPUNIT_ASSERT_EQUAL(size_t(2), aIssues
.size());
340 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[0]->m_eIssueID
);
341 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[1]->m_eIssueID
);
342 checkIssuePosition(aIssues
[0], __LINE__
, 0, 32, SwNodeOffset(9));
343 checkIssuePosition(aIssues
[1], __LINE__
, 0, 103, SwNodeOffset(10));
346 dispatchCommand(mxComponent
, ".uno:Undo", {});
347 CPPUNIT_ASSERT_EQUAL(sal_Int32(2),
348 pDoc
->getOnlineAccessibilityCheck()->getNumberOfAccessibilityIssues());
349 CPPUNIT_ASSERT_EQUAL(
350 OUString("He heard quiet steps behind him. That didn't bode well. Who could be following "
351 "him this late at night and in this deadbeat part of town?"),
352 getParagraph(1)->getString());
353 aIssues
= scanAccessibilityIssuesOnNodes(pDoc
);
354 CPPUNIT_ASSERT_EQUAL(size_t(2), aIssues
.size());
355 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[0]->m_eIssueID
);
356 CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING
, aIssues
[1]->m_eIssueID
);
357 checkIssuePosition(aIssues
[0], __LINE__
, 0, 32, SwNodeOffset(9));
358 checkIssuePosition(aIssues
[1], __LINE__
, 33, 136, SwNodeOffset(9));
361 CPPUNIT_PLUGIN_IMPLEMENT();
363 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */