cid#1607171 Data race condition
[LibreOffice.git] / sal / qa / rtl / strings / test_ostring_concat.cxx
blob86d261dd57e38ae22160ee7be238242cd7b3f5c3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 // activate support for detecting errors instead of getting compile errors
11 #define RTL_STRING_UNITTEST_CONCAT
13 #include <sal/types.h>
14 #include <cppunit/TestAssert.h>
15 #include <cppunit/TestFixture.h>
16 #include <cppunit/extensions/HelperMacros.h>
18 #include <rtl/string.hxx>
19 #include <rtl/strbuf.hxx>
20 #include <rtl/ustring.hxx>
21 #include <rtl/ustrbuf.hxx>
23 #include <string>
24 #include <typeinfo>
26 bool rtl_string_unittest_invalid_concat = false;
28 using namespace rtl;
30 template<> inline std::string CppUnit::assertion_traits<std::type_info>::toString(
31 std::type_info const & x)
33 return x.name();
36 namespace test::ostring {
38 class StringConcat : public CppUnit::TestFixture
40 private:
41 void checkConcat();
42 void checkEnsureCapacity();
43 void checkAppend();
44 void checkInvalid();
46 CPPUNIT_TEST_SUITE(StringConcat);
47 CPPUNIT_TEST(checkConcat);
48 CPPUNIT_TEST(checkEnsureCapacity);
49 CPPUNIT_TEST(checkAppend);
50 CPPUNIT_TEST(checkInvalid);
51 CPPUNIT_TEST_SUITE_END();
54 void test::ostring::StringConcat::checkConcat()
56 // All the extra () are to protect commas against being treated as separators of macro arguments.
57 CPPUNIT_ASSERT_EQUAL( OString(), OString(OString() + OString()));
58 CPPUNIT_ASSERT_EQUAL( "foobar"_ostr, OString( "foo"_ostr + "bar"_ostr));
59 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OString, OString > )), typeid( "foo"_ostr + "bar"_ostr));
60 CPPUNIT_ASSERT_EQUAL( "foobar"_ostr, OString( "foo"_ostr + "bar" ));
61 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OString, const char[ 4 ] > )), typeid( "foo"_ostr + "bar" ));
62 CPPUNIT_ASSERT_EQUAL( "foobarbaz"_ostr, OString( "foo"_ostr + "bar" + "baz" ));
63 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OStringConcat< OString, const char[ 4 ] >, const char[ 4 ] > )), typeid( "foo"_ostr + "bar" + "baz" ));
64 CPPUNIT_ASSERT_EQUAL( "foobar"_ostr, OString( OStringBuffer( "foo" ) + "bar" ));
65 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OStringBuffer, const char[ 4 ] > )), typeid( OStringBuffer( "foo" ) + "bar" ));
66 CPPUNIT_ASSERT_EQUAL( "foobar"_ostr, OString( OStringLiteral( "foo" ) + "bar" ));
67 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OStringLiteral<4>, const char[ 4 ] > )), typeid( OStringLiteral( "foo" ) + "bar" ));
68 CPPUNIT_ASSERT_EQUAL( "foobar"_ostr, OString( OStringLiteral( "foo" ) + static_cast<const char*>("bar") ));
69 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OStringLiteral<4>, const char* > )), typeid( OStringLiteral( "foo" ) + static_cast<const char*>("bar") ));
70 const char d1[] = "xyz";
71 char d2[] = "abc";
72 const char* d3 = d1;
73 char* d4 = d2;
74 CPPUNIT_ASSERT_EQUAL( "fooxyz"_ostr, OString( "foo"_ostr + d1 ));
75 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OString, const char[ 4 ] > )), typeid( "foo"_ostr + d1 ));
76 CPPUNIT_ASSERT_EQUAL( "fooabc"_ostr, OString( "foo"_ostr + d2 ));
77 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OString, char[ 4 ] > )), typeid( "foo"_ostr + d2 ));
78 CPPUNIT_ASSERT_EQUAL( "fooxyz"_ostr, OString( "foo"_ostr + d3 ));
79 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OString, const char* > )), typeid( "foo"_ostr + d3 ));
80 CPPUNIT_ASSERT_EQUAL( "fooabc"_ostr, OString( "foo"_ostr + d4 ));
81 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OString, char* > )), typeid( "foo"_ostr + d4 ));
82 CPPUNIT_ASSERT_EQUAL( "fooabc"_ostr, OString( "foo"_ostr + d4 ));
83 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OString, char* > )), typeid( "foo"_ostr + d4 ));
84 CPPUNIT_ASSERT_EQUAL( "foobar"_ostr, OString( OString::Concat( "foo" ) + "bar" ));
85 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OStringConcat< OStringConcatMarker, const char[ 4 ] >, const char[ 4 ] > )), typeid( OString::Concat( "foo" ) + "bar" ));
86 CPPUNIT_ASSERT_EQUAL( "xyzbar"_ostr, OString( OString::Concat( d1 ) + "bar" ));
87 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OStringConcat< OStringConcatMarker, const char[ 4 ] >, const char[ 4 ] > )), typeid( OString::Concat( d1 ) + "bar" ));
88 CPPUNIT_ASSERT_EQUAL( "abcbar"_ostr, OString( OString::Concat( d2 ) + "bar" ));
89 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OStringConcat< OStringConcatMarker, char[ 4 ] >, const char[ 4 ] > )), typeid( OString::Concat( d2 ) + "bar" ));
90 CPPUNIT_ASSERT_EQUAL( "xyzbar"_ostr, OString( OString::Concat( d3 ) + "bar" ));
91 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OStringConcat< OStringConcatMarker, const char* >, const char[ 4 ] > )), typeid( OString::Concat( d3 ) + "bar" ));
92 CPPUNIT_ASSERT_EQUAL( "abcbar"_ostr, OString( OString::Concat( d4 ) + "bar" ));
93 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OStringConcat< OStringConcatMarker, char* >, const char[ 4 ] > )), typeid( OString::Concat( d4 ) + "bar" ));
95 CPPUNIT_ASSERT_EQUAL( "num10"_ostr, OString( "num"_ostr + OString::number( 10 )));
96 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OString, StringNumber< char, RTL_STR_MAX_VALUEOFINT32 > > )), typeid( "num"_ostr + OString::number( 10 )));
97 CPPUNIT_ASSERT_EQUAL( "num10"_ostr, OString( "num"_ostr + OString::number( 10L )));
98 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OString, StringNumber< char, RTL_STR_MAX_VALUEOFINT64 > > )), typeid( "num"_ostr + OString::number( 10L )));
99 CPPUNIT_ASSERT_EQUAL( "num10"_ostr, OString( "num"_ostr + OString::number( 10ULL )));
100 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OString, StringNumber< char, RTL_STR_MAX_VALUEOFUINT64 > > )), typeid( "num"_ostr + OString::number( 10ULL )));
101 CPPUNIT_ASSERT_EQUAL( "num10.5"_ostr, OString( "num"_ostr + OString::number( 10.5f )));
102 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OString, OString > )), typeid( "num"_ostr + OString::number( 10.5f )));
103 CPPUNIT_ASSERT_EQUAL( "num10.5"_ostr, OString( "num"_ostr + OString::number( 10.5 )));
104 CPPUNIT_ASSERT_EQUAL(( typeid( OStringConcat< OString, OString > )), typeid( "num"_ostr + OString::number( 10.5 )));
107 void test::ostring::StringConcat::checkEnsureCapacity()
109 rtl_String* str = nullptr;
110 rtl_string_newFromLiteral( &str, "test", strlen( "test" ), 0 );
111 CPPUNIT_ASSERT_EQUAL( sal_Int32( 4 ), str->length );
112 CPPUNIT_ASSERT_EQUAL( 1, int( str->refCount ));
114 rtl_String* oldStr = str;
115 rtl_string_ensureCapacity( &str, 4 ); // should be no-op
116 CPPUNIT_ASSERT_EQUAL( sal_Int32( 4 ), str->length );
117 CPPUNIT_ASSERT_EQUAL( 1, int( str->refCount ));
118 CPPUNIT_ASSERT_EQUAL( str, oldStr );
120 rtl_string_acquire( oldStr );
121 CPPUNIT_ASSERT_EQUAL( 2, int( str->refCount ));
122 rtl_string_ensureCapacity( &str, 4 );
123 CPPUNIT_ASSERT_EQUAL( sal_Int32( 4 ), str->length );
124 CPPUNIT_ASSERT_EQUAL( 1, int( str->refCount ));
125 // a copy was forced because of refcount
126 CPPUNIT_ASSERT( oldStr != str );
127 CPPUNIT_ASSERT_EQUAL( 0, strcmp( oldStr->buffer, str->buffer ) );
128 CPPUNIT_ASSERT_EQUAL( 1, int( oldStr->refCount ));
129 rtl_string_release( str );
130 str = oldStr;
132 rtl_string_acquire( oldStr );
133 rtl_string_ensureCapacity( &str, 1024 );
134 CPPUNIT_ASSERT_EQUAL( sal_Int32( 4 ), str->length ); // size is still 4
135 CPPUNIT_ASSERT_EQUAL( 1, int( str->refCount ));
136 CPPUNIT_ASSERT( oldStr != str );
137 CPPUNIT_ASSERT_EQUAL( 0, strcmp( oldStr->buffer, str->buffer ) );
138 CPPUNIT_ASSERT_EQUAL( 1, int( oldStr->refCount ));
139 strcpy( str->buffer, "01234567890123456789" ); // but there should be extra capacity
140 str->length += 20;
141 rtl_string_release( str );
142 rtl_string_release( oldStr );
145 void test::ostring::StringConcat::checkAppend()
147 OString str( "foo"_ostr );
148 str += OStringLiteral( "bar" ) + "baz";
149 CPPUNIT_ASSERT_EQUAL( "foobarbaz"_ostr, str );
150 OStringBuffer buf( "foo" );
151 buf.append( OStringLiteral( "bar" ) + "baz" );
152 CPPUNIT_ASSERT_EQUAL( "foobarbaz"_ostr, buf.makeStringAndClear());
155 #define INVALID_CONCAT( expression ) \
157 rtl_string_unittest_invalid_concat = false, \
158 ( void ) OString( expression ), \
159 rtl_string_unittest_invalid_concat )
161 void test::ostring::StringConcat::checkInvalid()
163 CPPUNIT_ASSERT( !INVALID_CONCAT( OString() + OString()));
164 CPPUNIT_ASSERT( INVALID_CONCAT( "a"_ostr + u"b"_ustr));
165 CPPUNIT_ASSERT( INVALID_CONCAT( "a"_ostr + OUStringBuffer( "b" )));
166 CPPUNIT_ASSERT( INVALID_CONCAT( "a"_ostr + OUStringLiteral( u"b" )));
167 CPPUNIT_ASSERT( INVALID_CONCAT( "a"_ostr + OUString::Concat( u"b" )));
168 CPPUNIT_ASSERT( INVALID_CONCAT( "a"_ostr + 1 ));
169 rtl_String* rs = nullptr;
170 rtl_uString* rus = nullptr;
171 CPPUNIT_ASSERT( INVALID_CONCAT( u"b"_ustr + rs ));
172 CPPUNIT_ASSERT( INVALID_CONCAT( u"b"_ustr + rus ));
173 CPPUNIT_ASSERT( INVALID_CONCAT( "a"_ostr + OUString::number( 10 )));
174 CPPUNIT_ASSERT( INVALID_CONCAT( OString::number( 0 ) + OUString::number( 10 )));
176 #if 0
177 // Should fail to compile, to avoid use of OStringConcat lvalues that
178 // contain dangling references to temporaries:
179 auto const conc = OStringLiteral("foo") + "bar";
180 (void) OString(conc);
181 #endif
184 } // namespace
186 CPPUNIT_TEST_SUITE_REGISTRATION(test::ostring::StringConcat);
188 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */