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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <cppuhelper/bootstrap.hxx>
21 #include <cppuhelper/basemutex.hxx>
22 #include <com/sun/star/util/SearchFlags.hpp>
23 #include <com/sun/star/util/SearchOptions.hpp>
24 #include <com/sun/star/util/SearchAlgorithms2.hpp>
25 #include <com/sun/star/util/XTextSearch2.hpp>
26 #include <com/sun/star/i18n/Transliteration.hpp>
27 #include <unotest/bootstrapfixturebase.hxx>
28 #include <i18nutil/transliteration.hxx>
30 #include <unicode/regex.h>
32 #include <rtl/strbuf.hxx>
33 #include <rtl/ustrbuf.hxx>
35 using namespace ::com::sun::star
;
36 using namespace U_ICU_NAMESPACE
;
37 typedef U_ICU_NAMESPACE::UnicodeString IcuUniString
;
39 class TestTextSearch
: public test::BootstrapFixtureBase
42 virtual void setUp() override
;
43 virtual void tearDown() override
;
47 void testWildcardSearch();
49 CPPUNIT_TEST_SUITE(TestTextSearch
);
50 CPPUNIT_TEST(testICU
);
51 CPPUNIT_TEST(testSearches
);
52 CPPUNIT_TEST(testWildcardSearch
);
53 CPPUNIT_TEST_SUITE_END();
55 uno::Reference
<util::XTextSearch
> m_xSearch
;
56 uno::Reference
<util::XTextSearch2
> m_xSearch2
;
59 // Sanity check our ICU first ...
60 void TestTextSearch::testICU()
62 UErrorCode nErr
= U_ZERO_ERROR
;
63 RegexMatcher
* pRegexMatcher
;
64 sal_uInt32 nSearchFlags
= UREGEX_UWORD
| UREGEX_CASE_INSENSITIVE
;
66 OUString
aString( "abcdefgh" );
67 OUString
aPattern( "e" );
68 IcuUniString
aSearchPat( reinterpret_cast<const UChar
*>(aPattern
.getStr()), aPattern
.getLength() );
70 pRegexMatcher
= new RegexMatcher( aSearchPat
, nSearchFlags
, nErr
);
72 IcuUniString
aSource( reinterpret_cast<const UChar
*>(aString
.getStr()), aString
.getLength() );
73 pRegexMatcher
->reset( aSource
);
75 CPPUNIT_ASSERT( pRegexMatcher
->find( 0, nErr
) );
76 CPPUNIT_ASSERT_EQUAL( U_ZERO_ERROR
, nErr
);
77 CPPUNIT_ASSERT_EQUAL( static_cast<int32_t>(4), pRegexMatcher
->start( nErr
) );
78 CPPUNIT_ASSERT_EQUAL( U_ZERO_ERROR
, nErr
);
79 CPPUNIT_ASSERT_EQUAL( static_cast<int32_t>(5), pRegexMatcher
->end( nErr
) );
80 CPPUNIT_ASSERT_EQUAL( U_ZERO_ERROR
, nErr
);
84 OUString
aString2( "acababaabcababadcdaa" );
85 OUString
aPattern2( "a" );
87 IcuUniString
aSearchPat2( reinterpret_cast<const UChar
*>(aPattern2
.getStr()), aPattern2
.getLength() );
88 pRegexMatcher
= new RegexMatcher( aSearchPat2
, nSearchFlags
, nErr
);
90 IcuUniString
aSource2( reinterpret_cast<const UChar
*>(aString2
.getStr()), aString2
.getLength() );
91 pRegexMatcher
->reset( aSource2
);
93 CPPUNIT_ASSERT( pRegexMatcher
->find( 0, nErr
) );
94 CPPUNIT_ASSERT_EQUAL( U_ZERO_ERROR
, nErr
);
95 CPPUNIT_ASSERT_EQUAL( static_cast<int32_t>(0), pRegexMatcher
->start( nErr
) );
96 CPPUNIT_ASSERT_EQUAL( U_ZERO_ERROR
, nErr
);
97 CPPUNIT_ASSERT_EQUAL( static_cast<int32_t>(1), pRegexMatcher
->end( nErr
) );
98 CPPUNIT_ASSERT_EQUAL( U_ZERO_ERROR
, nErr
);
102 void TestTextSearch::testSearches()
104 OUString
str( "acababaabcababadcdaa" );
105 sal_Int32 startPos
= 2, endPos
= 20 ;
106 OUString
searchStr( "(ab)*a(c|d)+" );
107 sal_Int32 fStartRes
= 10, fEndRes
= 18 ;
108 sal_Int32 bStartRes
= 18, bEndRes
= 10 ;
111 util::SearchOptions aOptions
;
112 aOptions
.algorithmType
= util::SearchAlgorithms_REGEXP
;
113 aOptions
.searchFlag
= util::SearchFlags::ALL_IGNORE_CASE
;
114 aOptions
.searchString
= searchStr
;
115 m_xSearch
->setOptions( aOptions
);
117 util::SearchResult aRes
;
120 aRes
= m_xSearch
->searchForward( str
, startPos
, endPos
);
121 CPPUNIT_ASSERT( aRes
.subRegExpressions
> 0 );
122 CPPUNIT_ASSERT_EQUAL( fStartRes
, aRes
.startOffset
[0] );
123 CPPUNIT_ASSERT_EQUAL( fEndRes
, aRes
.endOffset
[0] );
126 aRes
= m_xSearch
->searchBackward( str
, endPos
, startPos
);
127 CPPUNIT_ASSERT( aRes
.subRegExpressions
> 0 );
128 CPPUNIT_ASSERT_EQUAL( bStartRes
, aRes
.startOffset
[0] );
129 CPPUNIT_ASSERT_EQUAL( bEndRes
, aRes
.endOffset
[0] );
131 aOptions
.transliterateFlags
= (int) (TransliterationFlags::IGNORE_CASE
132 | TransliterationFlags::IGNORE_WIDTH
);
133 aOptions
.searchString
= "([^ ]*)[ ]*([^ ]*)";
134 m_xSearch
->setOptions(aOptions
);
135 aRes
= m_xSearch
->searchForward("11 22 33", 2, 7);
136 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(3), aRes
.subRegExpressions
);
137 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 2) && (aRes
.endOffset
[0] == 5));
138 CPPUNIT_ASSERT((aRes
.startOffset
[1] == 2) && (aRes
.endOffset
[1] == 2));
139 CPPUNIT_ASSERT((aRes
.startOffset
[2] == 3) && (aRes
.endOffset
[2] == 5));
142 void TestTextSearch::testWildcardSearch()
144 util::SearchOptions2 aOptions
;
146 util::SearchResult aRes
;
148 aOptions
.AlgorithmType2
= util::SearchAlgorithms2::WILDCARD
;
149 aOptions
.WildcardEscapeCharacter
= '~';
150 // aOptions.searchFlag = ::css::util::SearchFlags::WILD_MATCH_SELECTION;
151 // is not set, so substring match is allowed.
152 aOptions
.transliterateFlags
= (sal_Int32
)::css::i18n::TransliterationModules::TransliterationModules_IGNORE_CASE
;
155 aOptions
.searchString
= "a";
156 m_xSearch2
->setOptions2( aOptions
);
157 // match first "a", [0,1)
158 aRes
= m_xSearch2
->searchForward( aText
, 0, aText
.getLength());
159 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
160 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 0) && (aRes
.endOffset
[0] == 1));
161 // match last "a", (5,4]
162 aRes
= m_xSearch2
->searchBackward( aText
, aText
.getLength(), 0);
163 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
164 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 5) && (aRes
.endOffset
[0] == 4));
166 aOptions
.searchString
= "a?";
167 m_xSearch2
->setOptions2( aOptions
);
169 aRes
= m_xSearch2
->searchForward( aText
, 0, aText
.getLength());
170 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
171 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 0) && (aRes
.endOffset
[0] == 2));
173 aRes
= m_xSearch2
->searchBackward( aText
, aText
.getLength(), 0);
174 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
175 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 4) && (aRes
.endOffset
[0] == 2));
177 aOptions
.searchString
= "a*c";
178 m_xSearch2
->setOptions2( aOptions
);
179 // match "abac", [0,4) XXX NOTE: first match forward
180 aRes
= m_xSearch2
->searchForward( aText
, 0, aText
.getLength());
181 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
182 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 0) && (aRes
.endOffset
[0] == 4));
183 // match "ac", (4,2] XXX NOTE: first match backward, not greedy
184 aRes
= m_xSearch2
->searchBackward( aText
, aText
.getLength(), 0);
185 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
186 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 4) && (aRes
.endOffset
[0] == 2));
188 aOptions
.searchString
= "b*a";
189 m_xSearch2
->setOptions2( aOptions
);
190 // match "ba", [1,3) XXX NOTE: first match forward, not greedy
191 aRes
= m_xSearch2
->searchForward( aText
, 0, aText
.getLength());
192 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
193 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 1) && (aRes
.endOffset
[0] == 3));
194 // match "baca", (5,1] XXX NOTE: first match backward
195 aRes
= m_xSearch2
->searchBackward( aText
, aText
.getLength(), 0);
196 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
197 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 5) && (aRes
.endOffset
[0] == 1));
201 aOptions
.searchString
= "?~??";
202 m_xSearch2
->setOptions2( aOptions
);
203 // match "b?c", [1,4)
204 aRes
= m_xSearch2
->searchForward( aText
, 0, aText
.getLength());
205 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
206 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 1) && (aRes
.endOffset
[0] == 4));
207 // match "b?c", (4,1]
208 aRes
= m_xSearch2
->searchBackward( aText
, aText
.getLength(), 0);
209 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
210 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 4) && (aRes
.endOffset
[0] == 1));
214 aOptions
.searchString
= "?~*?";
215 m_xSearch2
->setOptions2( aOptions
);
216 // match "b?c", [1,4)
217 aRes
= m_xSearch2
->searchForward( aText
, 0, aText
.getLength());
218 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
219 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 1) && (aRes
.endOffset
[0] == 4));
220 // match "b?c", (4,1]
221 aRes
= m_xSearch2
->searchBackward( aText
, aText
.getLength(), 0);
222 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
223 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 4) && (aRes
.endOffset
[0] == 1));
225 aOptions
.searchString
= "ca?";
226 m_xSearch2
->setOptions2( aOptions
);
228 aRes
= m_xSearch2
->searchForward( aText
, 0, aText
.getLength());
229 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(0), aRes
.subRegExpressions
);
231 aRes
= m_xSearch2
->searchBackward( aText
, aText
.getLength(), 0);
232 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(0), aRes
.subRegExpressions
);
234 aOptions
.searchString
= "ca*";
235 m_xSearch2
->setOptions2( aOptions
);
237 aRes
= m_xSearch2
->searchForward( aText
, 0, aText
.getLength());
238 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
239 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 3) && (aRes
.endOffset
[0] == 5));
241 aRes
= m_xSearch2
->searchBackward( aText
, aText
.getLength(), 0);
242 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
243 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 5) && (aRes
.endOffset
[0] == 3));
245 aOptions
.searchString
= "*ca*";
246 m_xSearch2
->setOptions2( aOptions
);
247 // match "abaca", [0,5)
248 aRes
= m_xSearch2
->searchForward( aText
, 0, aText
.getLength());
249 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
250 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 0) && (aRes
.endOffset
[0] == 5));
251 // match "abaca", (5,0]
252 aRes
= m_xSearch2
->searchBackward( aText
, aText
.getLength(), 0);
253 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
254 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 5) && (aRes
.endOffset
[0] == 0));
257 aOptions
.searchString
= "*2?";
258 m_xSearch2
->setOptions2( aOptions
);
259 // match first "123", [0,3)
260 aRes
= m_xSearch2
->searchForward( aText
, 0, aText
.getLength());
261 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
262 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 0) && (aRes
.endOffset
[0] == 3));
263 // match "123123", (6,0] Yes this looks odd, but it is as searching "?2*" forward.
264 aRes
= m_xSearch2
->searchBackward( aText
, aText
.getLength(), 0);
265 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
266 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 6) && (aRes
.endOffset
[0] == 0));
268 aOptions
.searchFlag
|= util::SearchFlags::WILD_MATCH_SELECTION
;
269 m_xSearch2
->setOptions2( aOptions
);
270 // match "123123", [0,6) with greedy '*'
271 aRes
= m_xSearch2
->searchForward( aText
, 0, aText
.getLength());
272 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
273 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 0) && (aRes
.endOffset
[0] == 6));
274 // match "123123", (6,0]
275 aRes
= m_xSearch2
->searchBackward( aText
, aText
.getLength(), 0);
276 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aRes
.subRegExpressions
);
277 CPPUNIT_ASSERT((aRes
.startOffset
[0] == 6) && (aRes
.endOffset
[0] == 0));
280 void TestTextSearch::setUp()
282 BootstrapFixtureBase::setUp();
283 m_xSearch
.set(m_xSFactory
->createInstance("com.sun.star.util.TextSearch"), uno::UNO_QUERY_THROW
);
284 m_xSearch2
.set(m_xSFactory
->createInstance("com.sun.star.util.TextSearch2"), uno::UNO_QUERY_THROW
);
287 void TestTextSearch::tearDown()
291 BootstrapFixtureBase::tearDown();
294 CPPUNIT_TEST_SUITE_REGISTRATION(TestTextSearch
);
296 CPPUNIT_PLUGIN_IMPLEMENT();
298 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */