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 <comphelper/string.hxx>
21 #include <cppuhelper/implbase.hxx>
22 #include <com/sun/star/i18n/CharType.hpp>
24 #include <cppunit/TestAssert.h>
25 #include <cppunit/TestFixture.h>
26 #include <cppunit/extensions/HelperMacros.h>
27 #include <cppunit/plugin/TestPlugIn.h>
28 #include <rtl/string.hxx>
29 #include <rtl/ustring.hxx>
33 class TestString
: public CppUnit::TestFixture
37 void testStripStart();
41 void testTokenCount();
42 void testDecimalStringToNumber();
43 void testIsdigitAsciiString();
44 void testReverseString();
48 CPPUNIT_TEST_SUITE(TestString
);
49 CPPUNIT_TEST(testNatural
);
50 CPPUNIT_TEST(testStripStart
);
51 CPPUNIT_TEST(testStripEnd
);
52 CPPUNIT_TEST(testStrip
);
53 CPPUNIT_TEST(testToken
);
54 CPPUNIT_TEST(testTokenCount
);
55 CPPUNIT_TEST(testDecimalStringToNumber
);
56 CPPUNIT_TEST(testIsdigitAsciiString
);
57 CPPUNIT_TEST(testReverseString
);
58 CPPUNIT_TEST(testSplit
);
59 CPPUNIT_TEST(testRemoveAny
);
60 CPPUNIT_TEST_SUITE_END();
63 void TestString::testDecimalStringToNumber()
66 CPPUNIT_ASSERT_EQUAL((sal_uInt32
)1234, comphelper::string::decimalStringToNumber(s1
));
67 s1
+= OUStringLiteral1(0x07C6);
68 CPPUNIT_ASSERT_EQUAL((sal_uInt32
)12346, comphelper::string::decimalStringToNumber(s1
));
69 // Codepoints on 2 16bits words
70 sal_uInt32 utf16String
[] = { 0x1D7FE /* 8 */, 0x1D7F7 /* 1 */};
71 s1
= OUString(utf16String
, 2);
72 CPPUNIT_ASSERT_EQUAL((sal_uInt32
)81, comphelper::string::decimalStringToNumber(s1
));
75 void TestString::testIsdigitAsciiString()
78 CPPUNIT_ASSERT_EQUAL(comphelper::string::isdigitAsciiString(s1
), true);
81 CPPUNIT_ASSERT_EQUAL(comphelper::string::isdigitAsciiString(s2
), false);
84 CPPUNIT_ASSERT_EQUAL(comphelper::string::isdigitAsciiString(s3
), true);
87 using namespace ::com::sun::star
;
89 class testCollator
: public cppu::WeakImplHelper
< i18n::XCollator
>
92 virtual sal_Int32 SAL_CALL
compareSubstring(
93 const OUString
& str1
, sal_Int32 off1
, sal_Int32 len1
,
94 const OUString
& str2
, sal_Int32 off2
, sal_Int32 len2
) override
96 return str1
.copy(off1
, len1
).compareTo(str2
.copy(off2
, len2
));
98 virtual sal_Int32 SAL_CALL
compareString(
100 const OUString
& str2
) override
102 return str1
.compareTo(str2
);
104 virtual sal_Int32 SAL_CALL
loadDefaultCollator(const lang::Locale
&, sal_Int32
) override
{return 0;}
105 virtual sal_Int32 SAL_CALL
loadCollatorAlgorithm(const OUString
&,
106 const lang::Locale
&, sal_Int32
) override
{return 0;}
107 virtual void SAL_CALL
loadCollatorAlgorithmWithEndUserOption(const OUString
&,
108 const lang::Locale
&, const uno::Sequence
< sal_Int32
>&) override
{}
109 virtual uno::Sequence
< OUString
> SAL_CALL
listCollatorAlgorithms(const lang::Locale
&) override
111 return uno::Sequence
< OUString
>();
113 virtual uno::Sequence
< sal_Int32
> SAL_CALL
listCollatorOptions(const OUString
&) override
115 return uno::Sequence
< sal_Int32
>();
119 #define IS_DIGIT(CHAR) (((CHAR) >= 48) && ((CHAR <= 57)))
121 class testBreakIterator
: public cppu::WeakImplHelper
< i18n::XBreakIterator
>
124 virtual sal_Int32 SAL_CALL
nextCharacters( const OUString
&, sal_Int32
,
125 const lang::Locale
&, sal_Int16
, sal_Int32
, sal_Int32
& ) override
{return -1;}
126 virtual sal_Int32 SAL_CALL
previousCharacters( const OUString
&, sal_Int32
,
127 const lang::Locale
&, sal_Int16
, sal_Int32
, sal_Int32
& ) override
{return -1;}
129 virtual i18n::Boundary SAL_CALL
previousWord( const OUString
&, sal_Int32
,
130 const lang::Locale
&, sal_Int16
) override
131 { return i18n::Boundary(); }
132 virtual i18n::Boundary SAL_CALL
nextWord( const OUString
&, sal_Int32
,
133 const lang::Locale
&, sal_Int16
) override
134 { return i18n::Boundary(); }
135 virtual i18n::Boundary SAL_CALL
getWordBoundary( const OUString
&, sal_Int32
,
136 const lang::Locale
&, sal_Int16
, sal_Bool
) override
137 { return i18n::Boundary(); }
139 virtual sal_Bool SAL_CALL
isBeginWord( const OUString
&, sal_Int32
,
140 const lang::Locale
&, sal_Int16
) override
142 virtual sal_Bool SAL_CALL
isEndWord( const OUString
&, sal_Int32
,
143 const lang::Locale
& , sal_Int16
) override
145 virtual sal_Int16 SAL_CALL
getWordType( const OUString
&, sal_Int32
,
146 const lang::Locale
& ) override
149 virtual sal_Int32 SAL_CALL
beginOfSentence( const OUString
&, sal_Int32
,
150 const lang::Locale
& ) override
152 virtual sal_Int32 SAL_CALL
endOfSentence( const OUString
& rText
, sal_Int32
,
153 const lang::Locale
& ) override
154 { return rText
.getLength(); }
156 virtual i18n::LineBreakResults SAL_CALL
getLineBreak( const OUString
&, sal_Int32
,
157 const lang::Locale
&, sal_Int32
,
158 const i18n::LineBreakHyphenationOptions
&,
159 const i18n::LineBreakUserOptions
&) override
161 return i18n::LineBreakResults();
164 virtual sal_Int16 SAL_CALL
getScriptType( const OUString
&, sal_Int32
) override
{ return -1; }
165 virtual sal_Int32 SAL_CALL
beginOfScript( const OUString
&, sal_Int32
,
166 sal_Int16
) override
{ return -1; }
167 virtual sal_Int32 SAL_CALL
endOfScript( const OUString
&, sal_Int32
,
168 sal_Int16
) override
{ return -1; }
169 virtual sal_Int32 SAL_CALL
previousScript( const OUString
&, sal_Int32
,
170 sal_Int16
) override
{ return -1; }
171 virtual sal_Int32 SAL_CALL
nextScript( const OUString
&, sal_Int32
,
172 sal_Int16
) override
{ return -1; }
174 virtual sal_Int32 SAL_CALL
beginOfCharBlock( const OUString
&, sal_Int32
,
175 const lang::Locale
&, sal_Int16
) override
{ return -1; }
176 virtual sal_Int32 SAL_CALL
endOfCharBlock( const OUString
& rText
, sal_Int32 nStartPos
,
177 const lang::Locale
&, sal_Int16 CharType
) override
179 const sal_Unicode
*pStr
= rText
.getStr()+nStartPos
;
180 for (sal_Int32 nI
= nStartPos
; nI
< rText
.getLength(); ++nI
)
182 if (CharType
== i18n::CharType::DECIMAL_DIGIT_NUMBER
&& !IS_DIGIT(*pStr
))
184 else if (CharType
!= i18n::CharType::DECIMAL_DIGIT_NUMBER
&& IS_DIGIT(*pStr
))
190 virtual sal_Int32 SAL_CALL
previousCharBlock( const OUString
&, sal_Int32
,
191 const lang::Locale
&, sal_Int16
) override
{ return -1; }
192 virtual sal_Int32 SAL_CALL
nextCharBlock( const OUString
& rText
, sal_Int32 nStartPos
,
193 const lang::Locale
&, sal_Int16 CharType
) override
195 const sal_Unicode
*pStr
= rText
.getStr()+nStartPos
;
196 for (sal_Int32 nI
= nStartPos
; nI
< rText
.getLength(); ++nI
)
198 if (CharType
== i18n::CharType::DECIMAL_DIGIT_NUMBER
&& IS_DIGIT(*pStr
))
200 else if (CharType
!= i18n::CharType::DECIMAL_DIGIT_NUMBER
&& !IS_DIGIT(*pStr
))
208 void TestString::testNatural()
210 using namespace comphelper::string
;
212 uno::Reference
< i18n::XCollator
> xCollator(new testCollator
);
213 uno::Reference
< i18n::XBreakIterator
> xBI(new testBreakIterator
);
215 // --- Some generic tests to ensure we do not alter original behavior
216 // outside what we want
217 CPPUNIT_ASSERT_EQUAL(
218 static_cast<sal_Int32
>(0), compareNatural("ABC", "ABC", xCollator
, xBI
, lang::Locale())
222 compareNatural("ABC", "abc", xCollator
, xBI
, lang::Locale()) < 0
226 compareNatural("abc", "ABC", xCollator
, xBI
, lang::Locale()) > 0
230 compareNatural("alongstring", "alongerstring", xCollator
, xBI
, lang::Locale()) > 0
234 compareNatural("alongerstring", "alongstring", xCollator
, xBI
, lang::Locale()) < 0
236 // -- Here we go on natural order, each one is followed by classic compare and the reverse comparison
237 // That's why we originally made the patch
239 compareNatural("Heading 9", "Heading 10", xCollator
, xBI
, lang::Locale()) < 0
243 OUString("Heading 9").compareTo("Heading 10") > 0
246 compareNatural("Heading 10", "Heading 9", xCollator
, xBI
, lang::Locale()) > 0
250 compareNatural("July, the 4th", "July, the 10th", xCollator
, xBI
, lang::Locale()) < 0
253 OUString("July, the 4th").compareTo("July, the 10th") > 0
256 compareNatural("July, the 10th", "July, the 4th", xCollator
, xBI
, lang::Locale()) > 0
260 compareNatural("abc08", "abc010", xCollator
, xBI
, lang::Locale()) < 0
263 OUString("abc08").compareTo("abc010") > 0
266 compareNatural("abc010", "abc08", xCollator
, xBI
, lang::Locale()) > 0
268 CPPUNIT_ASSERT_EQUAL(
269 static_cast<sal_Int32
>(0), compareNatural("apple10apple", "apple10apple", xCollator
, xBI
, lang::Locale())
273 void TestString::testStripStart()
278 aOut
= ::comphelper::string::stripStart(aIn
, 'b');
279 CPPUNIT_ASSERT_EQUAL(OString("abc"), aOut
);
281 aOut
= ::comphelper::string::stripStart(aIn
, 'a');
282 CPPUNIT_ASSERT_EQUAL(OString("bc"), aOut
);
285 aOut
= ::comphelper::string::stripStart(aIn
, 'a');
286 CPPUNIT_ASSERT(aOut
.isEmpty());
289 aOut
= ::comphelper::string::stripStart(aIn
, 'a');
290 CPPUNIT_ASSERT_EQUAL(OString("ba"), aOut
);
293 void TestString::testStripEnd()
298 aOut
= ::comphelper::string::stripEnd(aIn
, 'b');
299 CPPUNIT_ASSERT_EQUAL(OString("abc"), aOut
);
301 aOut
= ::comphelper::string::stripEnd(aIn
, 'c');
302 CPPUNIT_ASSERT_EQUAL(OString("ab"), aOut
);
305 aOut
= ::comphelper::string::stripEnd(aIn
, 'a');
306 CPPUNIT_ASSERT(aOut
.isEmpty());
309 aOut
= ::comphelper::string::stripEnd(aIn
, 'a');
310 CPPUNIT_ASSERT_EQUAL(OString("ab"), aOut
);
313 void TestString::testStrip()
318 aOut
= ::comphelper::string::strip(aIn
, 'b');
319 CPPUNIT_ASSERT_EQUAL(OString("abc"), aOut
);
321 aOut
= ::comphelper::string::strip(aIn
, 'c');
322 CPPUNIT_ASSERT_EQUAL(OString("ab"), aOut
);
325 aOut
= ::comphelper::string::strip(aIn
, 'a');
326 CPPUNIT_ASSERT(aOut
.isEmpty());
329 aOut
= ::comphelper::string::strip(aIn
, 'a');
330 CPPUNIT_ASSERT_EQUAL(OString("b"), aOut
);
333 void TestString::testToken()
335 OString
aIn("10.11.12");
338 aOut
= aIn
.getToken(-1, '.');
339 CPPUNIT_ASSERT(aOut
.isEmpty());
341 aOut
= aIn
.getToken(0, '.');
342 CPPUNIT_ASSERT_EQUAL(OString("10"), aOut
);
344 aOut
= aIn
.getToken(1, '.');
345 CPPUNIT_ASSERT_EQUAL(OString("11"), aOut
);
347 aOut
= aIn
.getToken(2, '.');
348 CPPUNIT_ASSERT_EQUAL(OString("12"), aOut
);
350 aOut
= aIn
.getToken(3, '.');
351 CPPUNIT_ASSERT(aOut
.isEmpty());
354 void TestString::testTokenCount()
356 OString
aIn("10.11.12");
359 nOut
= ::comphelper::string::getTokenCount(aIn
, '.');
360 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(3), nOut
);
362 nOut
= ::comphelper::string::getTokenCount(aIn
, 'X');
363 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), nOut
);
365 nOut
= ::comphelper::string::getTokenCount(OString(), 'X');
366 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(0), nOut
);
369 void TestString::testReverseString()
372 OString aOut
= ::comphelper::string::reverseString(aIn
);
374 CPPUNIT_ASSERT_EQUAL(OString("CBA"), aOut
);
377 void TestString::testSplit()
379 OUString
aIn("CTRL+ALT+F1");
380 std::vector
<OUString
> aRet
= ::comphelper::string::split(aIn
, '+');
381 CPPUNIT_ASSERT_EQUAL(size_t(3), aRet
.size());
382 CPPUNIT_ASSERT_EQUAL(OUString("CTRL"), aRet
[0]);
383 CPPUNIT_ASSERT_EQUAL(OUString("ALT"), aRet
[1]);
384 CPPUNIT_ASSERT_EQUAL(OUString("F1"), aRet
[2]);
387 void TestString::testRemoveAny()
389 using namespace ::comphelper::string
;
390 OUString
in("abcAAAbbC");
391 sal_Unicode
const test1
[] = { 'a', 0 };
392 CPPUNIT_ASSERT_EQUAL(OUString("bcAAAbbC"), removeAny(in
, test1
));
393 sal_Unicode
const test2
[] = { 0 };
394 CPPUNIT_ASSERT_EQUAL(in
, removeAny(in
, test2
));
395 sal_Unicode
const test3
[] = { 'A', 0 };
396 CPPUNIT_ASSERT_EQUAL(OUString("abcbbC"), removeAny(in
, test3
));
397 sal_Unicode
const test4
[] = { 'A', 'a', 0 };
398 CPPUNIT_ASSERT_EQUAL(OUString("bcbbC"), removeAny(in
, test4
));
399 sal_Unicode
const test5
[] = { 'C', 0 };
400 CPPUNIT_ASSERT_EQUAL(OUString("abcAAAbb"), removeAny(in
, test5
));
401 sal_Unicode
const test6
[] = { 'X', 0 };
402 CPPUNIT_ASSERT_EQUAL(in
, removeAny(in
, test6
));
403 sal_Unicode
const test7
[] = { 'A', 'B', 'C', 'a', 'b', 'c', 0 };
404 CPPUNIT_ASSERT_EQUAL(OUString(), removeAny(in
, test7
));
407 CPPUNIT_TEST_SUITE_REGISTRATION(TestString
);
411 CPPUNIT_PLUGIN_IMPLEMENT();
413 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */