summaryrefslogtreecommitdiffstats
path: root/sal/qa/rtl/strings/test_oustring_concat.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /sal/qa/rtl/strings/test_oustring_concat.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sal/qa/rtl/strings/test_oustring_concat.cxx')
-rw-r--r--sal/qa/rtl/strings/test_oustring_concat.cxx194
1 files changed, 194 insertions, 0 deletions
diff --git a/sal/qa/rtl/strings/test_oustring_concat.cxx b/sal/qa/rtl/strings/test_oustring_concat.cxx
new file mode 100644
index 000000000..bae7b65be
--- /dev/null
+++ b/sal/qa/rtl/strings/test_oustring_concat.cxx
@@ -0,0 +1,194 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+// activate support for detecting errors instead of getting compile errors
+#define RTL_STRING_UNITTEST_CONCAT
+extern bool rtl_string_unittest_invalid_concat;
+
+#include <sal/types.h>
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include <rtl/ustring.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/string.hxx>
+#include <rtl/strbuf.hxx>
+
+#include <string>
+#include <typeinfo>
+
+using namespace rtl;
+
+namespace CppUnit
+{
+template<> struct assertion_traits<std::type_info>
+{
+ static bool equal(std::type_info const & x, std::type_info const & y) { return x == y; }
+
+ static std::string toString(std::type_info const & x) { return x.name(); }
+};
+} // namespace
+
+namespace test::oustring {
+
+class StringConcat : public CppUnit::TestFixture
+{
+private:
+ void checkConcat();
+ void checkConcatAsciiL();
+ void checkEnsureCapacity();
+ void checkAppend();
+ void checkInvalid();
+
+CPPUNIT_TEST_SUITE(StringConcat);
+CPPUNIT_TEST(checkConcat);
+CPPUNIT_TEST(checkConcatAsciiL);
+CPPUNIT_TEST(checkEnsureCapacity);
+CPPUNIT_TEST(checkAppend);
+CPPUNIT_TEST(checkInvalid);
+CPPUNIT_TEST_SUITE_END();
+};
+
+void test::oustring::StringConcat::checkConcat()
+{
+// All the extra () are to protect commas against being treated as separators of macro arguments.
+ CPPUNIT_ASSERT_EQUAL( OUString(), OUString(OUString() + OUString()));
+ CPPUNIT_ASSERT_EQUAL( OUString( "foobar" ), OUString( OUString( "foo" ) + OUString( "bar" )));
+ CPPUNIT_ASSERT_EQUAL(( typeid( OUStringConcat< OUString, OUString > )), typeid( OUString( "foo" ) + OUString( "bar" )));
+ CPPUNIT_ASSERT_EQUAL( OUString( "foobar" ), OUString( OUString( "foo" ) + "bar" ));
+ CPPUNIT_ASSERT_EQUAL(( typeid( OUStringConcat< OUString, const char[ 4 ] > )), typeid( OUString( "foo" ) + "bar" ));
+ CPPUNIT_ASSERT_EQUAL( OUString( "foobarbaz" ), OUString( OUString( "foo" ) + "bar" + "baz" ));
+ CPPUNIT_ASSERT_EQUAL(( typeid( OUStringConcat< OUStringConcat< OUString, const char[ 4 ] >, const char[ 4 ] > )), typeid( OUString( "foo" ) + "bar" + "baz" ));
+ CPPUNIT_ASSERT_EQUAL( OUString( "foobar" ), OUString( OUStringLiteral( "foo" ) + "bar" ));
+ CPPUNIT_ASSERT_EQUAL(( typeid( OUStringConcat< OUStringLiteral, const char[ 4 ] > )), typeid( OUStringLiteral( "foo" ) + "bar" ));
+ const char d1[] = "xyz";
+ CPPUNIT_ASSERT_EQUAL( OUString( "fooxyz" ), OUString( OUString( "foo" ) + d1 ));
+ CPPUNIT_ASSERT_EQUAL(( typeid( OUStringConcat< OUString, const char[ 4 ] > )), typeid( OUString( "foo" ) + d1 ));
+ const sal_Unicode* d2 = u"xyz";
+ CPPUNIT_ASSERT_EQUAL( OUString( "fooxyz" ), OUString( OUString( "foo" ) + d2 ));
+ CPPUNIT_ASSERT_EQUAL(( typeid( OUStringConcat< OUString, const sal_Unicode* > )), typeid( OUString( "foo" ) + d2 ));
+ CPPUNIT_ASSERT_EQUAL( OUString( "fooxyz" ), OUString( rtl::OUStringView( u"foo" ) + d2 ));
+ CPPUNIT_ASSERT_EQUAL(( typeid( OUStringConcat< rtl::OUStringView, const sal_Unicode* > )), typeid( rtl::OUStringView( u"foo" ) + d2 ));
+
+ CPPUNIT_ASSERT_EQUAL( OUString( "num10" ), OUString( OUString( "num" ) + OUString::number( 10 )));
+ CPPUNIT_ASSERT_EQUAL(( typeid( OUStringConcat< OUString, OUStringNumber< int > > )), typeid( OUString( "num" ) + OUString::number( 10 )));
+ CPPUNIT_ASSERT_EQUAL( OUString( "num10" ), OUString( OUString( "num" ) + OUString::number( 10L )));
+ CPPUNIT_ASSERT_EQUAL(( typeid( OUStringConcat< OUString, OUStringNumber< long long > > )), typeid( OUString( "num" ) + OUString::number( 10L )));
+ CPPUNIT_ASSERT_EQUAL( OUString( "num10" ), OUString( OUString( "num" ) + OUString::number( 10ULL )));
+ CPPUNIT_ASSERT_EQUAL(( typeid( OUStringConcat< OUString, OUStringNumber< unsigned long long > > )), typeid( OUString( "num" ) + OUString::number( 10ULL )));
+ CPPUNIT_ASSERT_EQUAL( OUString( "num10.5" ), OUString( OUString( "num" ) + OUString::number( 10.5f )));
+ CPPUNIT_ASSERT_EQUAL(( typeid( OUStringConcat< OUString, OUStringNumber< float > > )), typeid( OUString( "num" ) + OUString::number( 10.5f )));
+ CPPUNIT_ASSERT_EQUAL( OUString( "num10.5" ), OUString( OUString( "num" ) + OUString::number( 10.5 )));
+ CPPUNIT_ASSERT_EQUAL(( typeid( OUStringConcat< OUString, OUStringNumber< double > > )), typeid( OUString( "num" ) + OUString::number( 10.5 )));
+}
+
+void test::oustring::StringConcat::checkConcatAsciiL()
+{
+ {
+ OUString s("foo");
+ CPPUNIT_ASSERT_EQUAL(OUString("foo"), s += "");
+ }
+ {
+ OUString s("foo");
+ CPPUNIT_ASSERT_EQUAL(OUString("foobar"), s += "bar");
+ }
+}
+
+void test::oustring::StringConcat::checkEnsureCapacity()
+{
+ rtl_uString* str = nullptr;
+ rtl_uString_newFromLiteral( &str, "test", strlen( "test" ), 0 );
+ CPPUNIT_ASSERT_EQUAL( sal_Int32( 4 ), str->length );
+ CPPUNIT_ASSERT_EQUAL( 1, int( str->refCount ));
+
+ rtl_uString* oldStr = str;
+ rtl_uString_ensureCapacity( &str, 4 ); // should be no-op
+ CPPUNIT_ASSERT_EQUAL( sal_Int32( 4 ), str->length );
+ CPPUNIT_ASSERT_EQUAL( 1, int( str->refCount ));
+ CPPUNIT_ASSERT_EQUAL( str, oldStr );
+
+ rtl_uString_acquire( oldStr );
+ CPPUNIT_ASSERT_EQUAL( 2, int( str->refCount ));
+ rtl_uString_ensureCapacity( &str, 4 );
+ CPPUNIT_ASSERT_EQUAL( sal_Int32( 4 ), str->length );
+ CPPUNIT_ASSERT_EQUAL( 1, int( str->refCount ));
+ // a copy was forced because of refcount
+ CPPUNIT_ASSERT( oldStr != str );
+ CPPUNIT_ASSERT_EQUAL( static_cast<sal_Int32>(0), rtl_ustr_compare( oldStr->buffer, str->buffer ) );
+ CPPUNIT_ASSERT_EQUAL( 1, int( oldStr->refCount ));
+ rtl_uString_release( str );
+ str = oldStr;
+
+ rtl_uString_acquire( oldStr );
+ rtl_uString_ensureCapacity( &str, 1024 );
+ CPPUNIT_ASSERT_EQUAL( sal_Int32( 4 ), str->length ); // size is still 4
+ CPPUNIT_ASSERT_EQUAL( 1, int( str->refCount ));
+ CPPUNIT_ASSERT( oldStr != str );
+ CPPUNIT_ASSERT_EQUAL( static_cast<sal_Int32>(0), rtl_ustr_compare( oldStr->buffer, str->buffer ) );
+ CPPUNIT_ASSERT_EQUAL( 1, int( oldStr->refCount ));
+ // but there should be extra capacity
+ for( int i = 0;
+ i < 20;
+ ++i )
+ str->buffer[ str->length + i ] = '0';
+ str->length += 20;
+ rtl_uString_release( str );
+ rtl_uString_release( oldStr );
+}
+
+void test::oustring::StringConcat::checkAppend()
+{
+ OUString str( "foo" );
+ str += OUStringLiteral( "bar" ) + "baz";
+ CPPUNIT_ASSERT_EQUAL( OUString( "foobarbaz" ), str );
+ OUStringBuffer buf( "foo" );
+ buf.append( OUStringLiteral( "bar" ) + "baz" );
+ CPPUNIT_ASSERT_EQUAL( OUString( "foobarbaz" ), buf.makeStringAndClear());
+}
+
+#define INVALID_CONCAT( expression ) \
+ ( \
+ rtl_string_unittest_invalid_concat = false, \
+ ( void ) OUString( expression ), \
+ rtl_string_unittest_invalid_concat )
+
+void test::oustring::StringConcat::checkInvalid()
+{
+ CPPUNIT_ASSERT( !INVALID_CONCAT( OUString() + OUString()));
+ CPPUNIT_ASSERT( INVALID_CONCAT( OUString( "a" ) + OUStringBuffer( "b" )));
+ CPPUNIT_ASSERT( INVALID_CONCAT( OUString( "a" ) + OString( "b" )));
+ CPPUNIT_ASSERT( INVALID_CONCAT( OUString( "a" ) + OStringBuffer( "b" )));
+ CPPUNIT_ASSERT( INVALID_CONCAT( OUString( "a" ) + static_cast<const char*>("b") ));
+ char d[] = "b";
+ CPPUNIT_ASSERT( INVALID_CONCAT( OUString( "a" ) + d ));
+ CPPUNIT_ASSERT( INVALID_CONCAT( OUString( "a" ) + static_cast<char*>(d) ));
+ CPPUNIT_ASSERT( INVALID_CONCAT( OUString( "a" ) + OStringLiteral( "b" )));
+ CPPUNIT_ASSERT( INVALID_CONCAT( OUString( "a" ) + rtl::OStringView( "b" )));
+ CPPUNIT_ASSERT( INVALID_CONCAT( OUString( "a" ) + 1 ));
+ rtl_String* rs = nullptr;
+ rtl_uString* rus = nullptr;
+ CPPUNIT_ASSERT( INVALID_CONCAT( OUString( "b" ) + rs ));
+ CPPUNIT_ASSERT( INVALID_CONCAT( OUString( "b" ) + rus ));
+ CPPUNIT_ASSERT( INVALID_CONCAT( OUString( "a" ) + OString::number( 10 )));
+ CPPUNIT_ASSERT( INVALID_CONCAT( OUString::number( 0 ) + OString::number( 10 )));
+
+#if 0
+ // Should fail to compile, to avoid use of OUStringConcat lvalues that
+ // contain dangling references to temporaries:
+ auto const conc = OUStringLiteral("foo") + "bar";
+ (void) OUString(conc);
+#endif
+}
+
+} // namespace
+
+CPPUNIT_TEST_SUITE_REGISTRATION(test::oustring::StringConcat);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */