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>
23 #include <com/sun/star/i18n/XBreakIterator.hpp>
24 #include <com/sun/star/i18n/XCollator.hpp>
26 #include <cppunit/TestAssert.h>
27 #include <cppunit/TestFixture.h>
28 #include <cppunit/extensions/HelperMacros.h>
29 #include <cppunit/plugin/TestPlugIn.h>
30 #include <rtl/string.hxx>
31 #include <rtl/ustring.hxx>
35 class TestString
: public CppUnit::TestFixture
39 void testStripStart();
43 void testTokenCount();
44 void testDecimalStringToNumber();
45 void testIsdigitAsciiString();
46 void testReverseString();
50 CPPUNIT_TEST_SUITE(TestString
);
51 CPPUNIT_TEST(testNatural
);
52 CPPUNIT_TEST(testStripStart
);
53 CPPUNIT_TEST(testStripEnd
);
54 CPPUNIT_TEST(testStrip
);
55 CPPUNIT_TEST(testToken
);
56 CPPUNIT_TEST(testTokenCount
);
57 CPPUNIT_TEST(testDecimalStringToNumber
);
58 CPPUNIT_TEST(testIsdigitAsciiString
);
59 CPPUNIT_TEST(testReverseString
);
60 CPPUNIT_TEST(testSplit
);
61 CPPUNIT_TEST(testRemoveAny
);
62 CPPUNIT_TEST_SUITE_END();
65 void TestString::testDecimalStringToNumber()
68 CPPUNIT_ASSERT_EQUAL(sal_uInt32(1234), comphelper::string::decimalStringToNumber(s1
));
70 CPPUNIT_ASSERT_EQUAL(sal_uInt32(12346), comphelper::string::decimalStringToNumber(s1
));
71 // Codepoints on 2 16bits words
72 sal_uInt32 utf16String
[] = { 0x1D7FE /* 8 */, 0x1D7F7 /* 1 */};
73 s1
= OUString(utf16String
, 2);
74 CPPUNIT_ASSERT_EQUAL(sal_uInt32(81), comphelper::string::decimalStringToNumber(s1
));
77 void TestString::testIsdigitAsciiString()
80 CPPUNIT_ASSERT_EQUAL(true, comphelper::string::isdigitAsciiString(s1
));
83 CPPUNIT_ASSERT_EQUAL(false, comphelper::string::isdigitAsciiString(s2
));
86 CPPUNIT_ASSERT_EQUAL(true, comphelper::string::isdigitAsciiString(s3
));
89 using namespace ::com::sun::star
;
91 class testCollator
: public cppu::WeakImplHelper
< i18n::XCollator
>
94 virtual sal_Int32 SAL_CALL
compareSubstring(
95 const OUString
& str1
, sal_Int32 off1
, sal_Int32 len1
,
96 const OUString
& str2
, sal_Int32 off2
, sal_Int32 len2
) override
98 return str1
.copy(off1
, len1
).compareTo(str2
.copy(off2
, len2
));
100 virtual sal_Int32 SAL_CALL
compareString(
101 const OUString
& str1
,
102 const OUString
& str2
) override
104 return str1
.compareTo(str2
);
106 virtual sal_Int32 SAL_CALL
loadDefaultCollator(const lang::Locale
&, sal_Int32
) override
{return 0;}
107 virtual sal_Int32 SAL_CALL
loadCollatorAlgorithm(const OUString
&,
108 const lang::Locale
&, sal_Int32
) override
{return 0;}
109 virtual void SAL_CALL
loadCollatorAlgorithmWithEndUserOption(const OUString
&,
110 const lang::Locale
&, const uno::Sequence
< sal_Int32
>&) override
{}
111 virtual uno::Sequence
< OUString
> SAL_CALL
listCollatorAlgorithms(const lang::Locale
&) override
113 return uno::Sequence
< OUString
>();
115 virtual uno::Sequence
< sal_Int32
> SAL_CALL
listCollatorOptions(const OUString
&) override
117 return uno::Sequence
< sal_Int32
>();
121 #define IS_DIGIT(CHAR) (((CHAR) >= 48) && ((CHAR <= 57)))
123 class testBreakIterator
: public cppu::WeakImplHelper
< i18n::XBreakIterator
>
126 virtual sal_Int32 SAL_CALL
nextCharacters( const OUString
&, sal_Int32
,
127 const lang::Locale
&, sal_Int16
, sal_Int32
, sal_Int32
& ) override
{return -1;}
128 virtual sal_Int32 SAL_CALL
previousCharacters( const OUString
&, sal_Int32
,
129 const lang::Locale
&, sal_Int16
, sal_Int32
, sal_Int32
& ) override
{return -1;}
131 virtual i18n::Boundary SAL_CALL
previousWord( const OUString
&, sal_Int32
,
132 const lang::Locale
&, sal_Int16
) override
133 { return i18n::Boundary(); }
134 virtual i18n::Boundary SAL_CALL
nextWord( const OUString
&, sal_Int32
,
135 const lang::Locale
&, sal_Int16
) override
136 { return i18n::Boundary(); }
137 virtual i18n::Boundary SAL_CALL
getWordBoundary( const OUString
&, sal_Int32
,
138 const lang::Locale
&, sal_Int16
, sal_Bool
) override
139 { return i18n::Boundary(); }
141 virtual sal_Bool SAL_CALL
isBeginWord( const OUString
&, sal_Int32
,
142 const lang::Locale
&, sal_Int16
) override
144 virtual sal_Bool SAL_CALL
isEndWord( const OUString
&, sal_Int32
,
145 const lang::Locale
& , sal_Int16
) override
147 virtual sal_Int16 SAL_CALL
getWordType( const OUString
&, sal_Int32
,
148 const lang::Locale
& ) override
151 virtual sal_Int32 SAL_CALL
beginOfSentence( const OUString
&, sal_Int32
,
152 const lang::Locale
& ) override
154 virtual sal_Int32 SAL_CALL
endOfSentence( const OUString
& rText
, sal_Int32
,
155 const lang::Locale
& ) override
156 { return rText
.getLength(); }
158 virtual i18n::LineBreakResults SAL_CALL
getLineBreak( const OUString
&, sal_Int32
,
159 const lang::Locale
&, sal_Int32
,
160 const i18n::LineBreakHyphenationOptions
&,
161 const i18n::LineBreakUserOptions
&) override
163 return i18n::LineBreakResults();
166 virtual sal_Int16 SAL_CALL
getScriptType( const OUString
&, sal_Int32
) override
{ return -1; }
167 virtual sal_Int32 SAL_CALL
beginOfScript( const OUString
&, sal_Int32
,
168 sal_Int16
) override
{ return -1; }
169 virtual sal_Int32 SAL_CALL
endOfScript( const OUString
&, sal_Int32
,
170 sal_Int16
) override
{ return -1; }
171 virtual sal_Int32 SAL_CALL
previousScript( const OUString
&, sal_Int32
,
172 sal_Int16
) override
{ return -1; }
173 virtual sal_Int32 SAL_CALL
nextScript( const OUString
&, sal_Int32
,
174 sal_Int16
) override
{ return -1; }
176 virtual sal_Int32 SAL_CALL
beginOfCharBlock( const OUString
&, sal_Int32
,
177 const lang::Locale
&, sal_Int16
) override
{ return -1; }
178 virtual sal_Int32 SAL_CALL
endOfCharBlock( const OUString
& rText
, sal_Int32 nStartPos
,
179 const lang::Locale
&, sal_Int16 CharType
) override
181 const sal_Unicode
*pStr
= rText
.getStr()+nStartPos
;
182 for (sal_Int32 nI
= nStartPos
; nI
< rText
.getLength(); ++nI
)
184 if (CharType
== i18n::CharType::DECIMAL_DIGIT_NUMBER
&& !IS_DIGIT(*pStr
))
186 else if (CharType
!= i18n::CharType::DECIMAL_DIGIT_NUMBER
&& IS_DIGIT(*pStr
))
192 virtual sal_Int32 SAL_CALL
previousCharBlock( const OUString
&, sal_Int32
,
193 const lang::Locale
&, sal_Int16
) override
{ return -1; }
194 virtual sal_Int32 SAL_CALL
nextCharBlock( const OUString
& rText
, sal_Int32 nStartPos
,
195 const lang::Locale
&, sal_Int16 CharType
) override
197 const sal_Unicode
*pStr
= rText
.getStr()+nStartPos
;
198 for (sal_Int32 nI
= nStartPos
; nI
< rText
.getLength(); ++nI
)
200 if (CharType
== i18n::CharType::DECIMAL_DIGIT_NUMBER
&& IS_DIGIT(*pStr
))
202 else if (CharType
!= i18n::CharType::DECIMAL_DIGIT_NUMBER
&& !IS_DIGIT(*pStr
))
210 void TestString::testNatural()
212 using namespace comphelper::string
;
214 uno::Reference
< i18n::XCollator
> xCollator(new testCollator
);
215 uno::Reference
< i18n::XBreakIterator
> xBI(new testBreakIterator
);
217 // --- Some generic tests to ensure we do not alter original behavior
218 // outside what we want
219 CPPUNIT_ASSERT_EQUAL(
220 static_cast<sal_Int32
>(0), compareNatural("ABC", "ABC", xCollator
, xBI
, lang::Locale())
224 compareNatural("ABC", "abc", xCollator
, xBI
, lang::Locale()) < 0
228 compareNatural("abc", "ABC", xCollator
, xBI
, lang::Locale()) > 0
232 compareNatural("alongstring", "alongerstring", xCollator
, xBI
, lang::Locale()) > 0
236 compareNatural("alongerstring", "alongstring", xCollator
, xBI
, lang::Locale()) < 0
238 // -- Here we go on natural order, each one is followed by classic compare and the reverse comparison
239 // That's why we originally made the patch
241 compareNatural("Heading 9", "Heading 10", xCollator
, xBI
, lang::Locale()) < 0
245 OUString("Heading 9").compareTo("Heading 10") > 0
248 compareNatural("Heading 10", "Heading 9", xCollator
, xBI
, lang::Locale()) > 0
252 compareNatural("July, the 4th", "July, the 10th", xCollator
, xBI
, lang::Locale()) < 0
255 OUString("July, the 4th").compareTo("July, the 10th") > 0
258 compareNatural("July, the 10th", "July, the 4th", xCollator
, xBI
, lang::Locale()) > 0
262 compareNatural("abc08", "abc010", xCollator
, xBI
, lang::Locale()) < 0
265 OUString("abc08").compareTo("abc010") > 0
268 compareNatural("abc010", "abc08", xCollator
, xBI
, lang::Locale()) > 0
270 CPPUNIT_ASSERT_EQUAL(
271 static_cast<sal_Int32
>(0), compareNatural("apple10apple", "apple10apple", xCollator
, xBI
, lang::Locale())
275 void TestString::testStripStart()
280 aOut
= ::comphelper::string::stripStart(aIn
, 'b');
281 CPPUNIT_ASSERT_EQUAL(OString("abc"), aOut
);
283 aOut
= ::comphelper::string::stripStart(aIn
, 'a');
284 CPPUNIT_ASSERT_EQUAL(OString("bc"), aOut
);
287 aOut
= ::comphelper::string::stripStart(aIn
, 'a');
288 CPPUNIT_ASSERT(aOut
.isEmpty());
291 aOut
= ::comphelper::string::stripStart(aIn
, 'a');
292 CPPUNIT_ASSERT_EQUAL(OString("ba"), aOut
);
295 void TestString::testStripEnd()
300 aOut
= ::comphelper::string::stripEnd(aIn
, 'b');
301 CPPUNIT_ASSERT_EQUAL(OString("abc"), aOut
);
303 aOut
= ::comphelper::string::stripEnd(aIn
, 'c');
304 CPPUNIT_ASSERT_EQUAL(OString("ab"), aOut
);
307 aOut
= ::comphelper::string::stripEnd(aIn
, 'a');
308 CPPUNIT_ASSERT(aOut
.isEmpty());
311 aOut
= ::comphelper::string::stripEnd(aIn
, 'a');
312 CPPUNIT_ASSERT_EQUAL(OString("ab"), aOut
);
315 void TestString::testStrip()
320 aOut
= ::comphelper::string::strip(aIn
, 'b');
321 CPPUNIT_ASSERT_EQUAL(OString("abc"), aOut
);
323 aOut
= ::comphelper::string::strip(aIn
, 'c');
324 CPPUNIT_ASSERT_EQUAL(OString("ab"), aOut
);
327 aOut
= ::comphelper::string::strip(aIn
, 'a');
328 CPPUNIT_ASSERT(aOut
.isEmpty());
331 aOut
= ::comphelper::string::strip(aIn
, 'a');
332 CPPUNIT_ASSERT_EQUAL(OString("b"), aOut
);
335 void TestString::testToken()
337 OString
aIn("10.11.12");
340 aOut
= aIn
.getToken(-1, '.');
341 CPPUNIT_ASSERT(aOut
.isEmpty());
343 aOut
= aIn
.getToken(0, '.');
344 CPPUNIT_ASSERT_EQUAL(OString("10"), aOut
);
346 aOut
= aIn
.getToken(1, '.');
347 CPPUNIT_ASSERT_EQUAL(OString("11"), aOut
);
349 aOut
= aIn
.getToken(2, '.');
350 CPPUNIT_ASSERT_EQUAL(OString("12"), aOut
);
352 aOut
= aIn
.getToken(3, '.');
353 CPPUNIT_ASSERT(aOut
.isEmpty());
356 void TestString::testTokenCount()
358 OString
aIn("10.11.12");
361 nOut
= ::comphelper::string::getTokenCount(aIn
, '.');
362 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(3), nOut
);
364 nOut
= ::comphelper::string::getTokenCount(aIn
, 'X');
365 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), nOut
);
367 nOut
= ::comphelper::string::getTokenCount(OString(), 'X');
368 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(0), nOut
);
371 void TestString::testReverseString()
374 OString aOut
= ::comphelper::string::reverseString(aIn
);
376 CPPUNIT_ASSERT_EQUAL(OString("CBA"), aOut
);
379 void TestString::testSplit()
381 OUString
aIn("CTRL+ALT+F1");
382 std::vector
<OUString
> aRet
= ::comphelper::string::split(aIn
, '+');
383 CPPUNIT_ASSERT_EQUAL(size_t(3), aRet
.size());
384 CPPUNIT_ASSERT_EQUAL(OUString("CTRL"), aRet
[0]);
385 CPPUNIT_ASSERT_EQUAL(OUString("ALT"), aRet
[1]);
386 CPPUNIT_ASSERT_EQUAL(OUString("F1"), aRet
[2]);
389 void TestString::testRemoveAny()
391 using namespace ::comphelper::string
;
392 OUString
in("abcAAAbbC");
393 sal_Unicode
const test1
[] = { 'a', 0 };
394 CPPUNIT_ASSERT_EQUAL(OUString("bcAAAbbC"), removeAny(in
, test1
));
395 sal_Unicode
const test2
[] = { 0 };
396 CPPUNIT_ASSERT_EQUAL(in
, removeAny(in
, test2
));
397 sal_Unicode
const test3
[] = { 'A', 0 };
398 CPPUNIT_ASSERT_EQUAL(OUString("abcbbC"), removeAny(in
, test3
));
399 sal_Unicode
const test4
[] = { 'A', 'a', 0 };
400 CPPUNIT_ASSERT_EQUAL(OUString("bcbbC"), removeAny(in
, test4
));
401 sal_Unicode
const test5
[] = { 'C', 0 };
402 CPPUNIT_ASSERT_EQUAL(OUString("abcAAAbb"), removeAny(in
, test5
));
403 sal_Unicode
const test6
[] = { 'X', 0 };
404 CPPUNIT_ASSERT_EQUAL(in
, removeAny(in
, test6
));
405 sal_Unicode
const test7
[] = { 'A', 'B', 'C', 'a', 'b', 'c', 0 };
406 CPPUNIT_ASSERT_EQUAL(OUString(), removeAny(in
, test7
));
409 CPPUNIT_TEST_SUITE_REGISTRATION(TestString
);
413 CPPUNIT_PLUGIN_IMPLEMENT();
415 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */