/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include using namespace utils; TEST(CString, EmptyString) { CString const emptyString(""); EXPECT_STREQ("", emptyString.c_str_safe()); EXPECT_EQ(0, emptyString.length()); EXPECT_TRUE(emptyString.empty()); } TEST(CString, Constructors) { // CString() { CString str; EXPECT_EQ(nullptr, str.c_str()); EXPECT_STREQ("", str.c_str_safe()); EXPECT_EQ(0, str.length()); EXPECT_TRUE(str.empty()); } // CString(const char* cstr, size_t length) { CString str("foobar", 3); EXPECT_STREQ("foo", str.c_str()); EXPECT_EQ(3, str.length()); } // CString(size_t length) { CString str(5); EXPECT_EQ(5, str.length()); // The memory is zero-initialized EXPECT_EQ(0, str.c_str()[0]); EXPECT_EQ(0, str.c_str()[4]); } // CString(const char* cstr) { const char* hello_cstr = "hello"; CString str(hello_cstr); EXPECT_STREQ("hello", str.c_str()); EXPECT_EQ(5, str.length()); } // CString(StringLiteral) { CString str("literal"); // this uses the template constructor EXPECT_STREQ("literal", str.c_str()); EXPECT_EQ(7, str.length()); } // Copy constructor { CString s1("copy me"); CString s2(s1); EXPECT_STREQ("copy me", s2.c_str()); EXPECT_NE(s1.c_str(), s2.c_str()); // should be a deep copy } // Move constructor { CString s1("move me"); const char* original_cstr = s1.c_str(); CString s2(std::move(s1)); EXPECT_STREQ("move me", s2.c_str()); EXPECT_EQ(original_cstr, s2.c_str()); // pointer should be moved EXPECT_EQ(nullptr, s1.c_str()); // original should be empty } } TEST(CString, LiteralConstructor) { // This test verifies that CString can be constructed from a string literal, // and that this uses the desired template constructor, not the explicit // (and costly) `const char*` constructor. // Test copy-initialization. CString should be convertible from a string literal. // This works because "literal" has type `const char[N]` which matches // `StringLiteral` and calls the non-explicit template constructor. static_assert(std::is_convertible_v, "CString should be convertible from a string literal."); CString s_copy = "literal"; EXPECT_STREQ("literal", s_copy.c_str()); EXPECT_EQ(7, s_copy.length()); // Test direct-initialization. This should also use the same efficient constructor. static_assert(std::is_constructible_v, "CString should be constructible from a string literal."); CString s_direct("literal"); EXPECT_STREQ("literal", s_direct.c_str()); EXPECT_EQ(7, s_direct.length()); // Verify that direct-initialization uses the sized constructor by using an embedded null. // If the strlen() constructor were used, the length would be 3. // The size of "abc\0def" is 8 (including the terminating null). The constructor // calculates the length as N-1 = 7. CString const s_direct_null("abc\0def"); EXPECT_EQ(7, s_direct_null.length()); // CString should NOT be convertible from a `const char*`. // This is because the `const char*` constructor is explicit. static_assert(!std::is_convertible_v, "CString should not be convertible from a const char*."); // This demonstrates the non-convertibility. The following line would fail to compile: // const char* cstr = "hello"; // CString s2 = cstr; // Explicit construction from a const char* should still work (via direct-initialization). const char* cstr = "explicit"; CString s2(cstr); EXPECT_STREQ("explicit", s2.c_str()); EXPECT_EQ(8, s2.length()); } TEST(CString, Assignment) { // Copy assignment { CString s1("copy"); CString s2; s2 = s1; EXPECT_STREQ("copy", s2.c_str()); EXPECT_NE(s1.c_str(), s2.c_str()); } // Move assignment { CString s1("move"); const char* original_cstr = s1.c_str(); CString s2; s2 = std::move(s1); EXPECT_STREQ("move", s2.c_str()); EXPECT_EQ(original_cstr, s2.c_str()); EXPECT_EQ(nullptr, s1.c_str()); } // self-assignment { CString s1("self"); const char* original_cstr = s1.c_str(); s1 = s1; EXPECT_STREQ("self", s1.c_str()); EXPECT_EQ(original_cstr, s1.c_str()); } } TEST(CString, Swap) { CString s1("first"); CString s2("second"); const char* p1 = s1.c_str(); const char* p2 = s2.c_str(); size_t l1 = s1.length(); size_t l2 = s2.length(); s1.swap(s2); EXPECT_STREQ("second", s1.c_str()); EXPECT_STREQ("first", s2.c_str()); EXPECT_EQ(p2, s1.c_str()); EXPECT_EQ(p1, s2.c_str()); EXPECT_EQ(l2, s1.length()); EXPECT_EQ(l1, s2.length()); } TEST(CString, Concatenation) { // operator+= { CString s("hello"); s += CString(" world"); EXPECT_STREQ("hello world", s.c_str()); } { CString s("hello"); s += " world"; EXPECT_STREQ("hello world", s.c_str()); } { CString s("hello"); const char* world = " world"; s += world; EXPECT_STREQ("hello world", s.c_str()); } { CString s("hello"); s += ""; EXPECT_STREQ("hello", s.c_str()); } { CString s; s += "world"; EXPECT_STREQ("world", s.c_str()); } // operator+ { CString s1("hello"); CString s2(" world"); CString s3 = s1 + s2; EXPECT_STREQ("hello world", s3.c_str()); } { CString s1("hello"); CString s2 = s1 + " world"; EXPECT_STREQ("hello world", s2.c_str()); } { CString s1(" world"); CString s2 = "hello" + s1; EXPECT_STREQ("hello world", s2.c_str()); } { CString s1("hello"); const char* world = " world"; CString s2 = s1 + world; EXPECT_STREQ("hello world", s2.c_str()); } { CString s1(" world"); const char* hello = "hello"; CString s2 = hello + s1; EXPECT_STREQ("hello world", s2.c_str()); } { CString s = CString("a") + CString("b") + "c" + "d"; EXPECT_STREQ("abcd", s.c_str()); } } TEST(CString, Comparison) { CString s1("abc"); CString s2("abc"); CString s3("def"); CString s4("ab"); EXPECT_TRUE(s1 == s2); EXPECT_FALSE(s1 == s3); EXPECT_TRUE(s1 != s3); EXPECT_FALSE(s1 != s2); EXPECT_TRUE(s1 < s3); EXPECT_FALSE(s3 < s1); EXPECT_TRUE(s3 > s1); EXPECT_FALSE(s1 > s3); EXPECT_TRUE(s1 <= s2); EXPECT_TRUE(s1 <= s3); EXPECT_FALSE(s3 <= s1); EXPECT_TRUE(s2 >= s1); EXPECT_TRUE(s3 >= s1); EXPECT_FALSE(s1 >= s3); EXPECT_TRUE(s4 < s1); EXPECT_TRUE(s1 > s4); } TEST(CString, ElementAccess) { CString str("01234"); const CString cstr("const"); EXPECT_EQ('0', str.front()); EXPECT_EQ('4', str.back()); EXPECT_EQ('c', cstr.front()); EXPECT_EQ('t', cstr.back()); EXPECT_EQ('2', str[2]); EXPECT_EQ('n', cstr[2]); str[0] = 'A'; EXPECT_STREQ("A1234", str.c_str()); EXPECT_EQ('3', str.at(3)); EXPECT_EQ('t', cstr.at(4)); // iterators std::string s(str.begin(), str.end()); EXPECT_EQ("A1234", s); EXPECT_TRUE(std::equal(cstr.begin(), cstr.end(), "const")); } TEST(CString, Append) { // Append CString { CString str("foo"); str.append(CString("bar")); EXPECT_STREQ("foobar", str.c_str()); } // Append string literal { CString str("foo"); str.append("bar"); EXPECT_STREQ("foobar", str.c_str()); } // Append const char* { CString str("foo"); const char* bar = "bar"; str.append(bar); EXPECT_STREQ("foobar", str.c_str()); } // Append nullptr { CString str("foo"); const char* bar = nullptr; str.append(bar); EXPECT_STREQ("foo", str.c_str()); } // Append to empty { CString str; str.append("foo"); EXPECT_STREQ("foo", str.c_str()); } { CString str; str.append(CString("foo")); EXPECT_STREQ("foo", str.c_str()); } { CString str; const char* foo = "foo"; str.append(foo); EXPECT_STREQ("foo", str.c_str()); } // Append empty { CString str("foo"); str.append(""); EXPECT_STREQ("foo", str.c_str()); } { CString str("foo"); str.append(CString("")); EXPECT_STREQ("foo", str.c_str()); } { CString str("foo"); const char* empty = ""; str.append(empty); EXPECT_STREQ("foo", str.c_str()); } // Chaining { CString str; str.append("foo").append("bar").append(CString("baz")); EXPECT_STREQ("foobarbaz", str.c_str()); } // r-value appends { CString str = CString("foo").append("bar"); EXPECT_STREQ("foobar", str.c_str()); } } TEST(CString, Insert) { // with CString { CString str("foobaz"); str.insert(3, CString("bar")); EXPECT_STREQ("foobarbaz", str.c_str()); } // with string literal { CString str("world"); str.insert(0, "hello "); EXPECT_STREQ("hello world", str.c_str()); } // with const char* { CString str("foo"); const char* bar = "bar"; str.insert(3, bar); EXPECT_STREQ("foobar", str.c_str()); } // with nullptr { CString str("foo"); const char* bar = nullptr; str.insert(1, bar); EXPECT_STREQ("foo", str.c_str()); } // r-value insert { const char* bar = "bar"; CString str = CString("foo").insert(3, bar); EXPECT_STREQ("foobar", str.c_str()); } } TEST(CString, Replace) { // with CString { CString str("foo bar baz"); str.replace(4, 3, CString("dpa")); EXPECT_STREQ("foo dpa baz", str.c_str()); } // with string literal { CString str("foo bar baz"); str.replace(4, 3, "dpa"); EXPECT_STREQ("foo dpa baz", str.c_str()); } // with const char* { CString str("foo bar baz"); const char* dpa = "dpa"; str.replace(4, 3, dpa); EXPECT_STREQ("foo dpa baz", str.c_str()); } // with nullptr { CString str("foo bar baz"); const char* dpa = nullptr; str.replace(4, 3, dpa); EXPECT_STREQ("foo baz", str.c_str()); } // with empty string { CString str("foo bar baz"); str.replace(4, 3, ""); EXPECT_STREQ("foo baz", str.c_str()); } // replace that grows the string { CString str("foo bar baz"); str.replace(4, 3, "abcdef"); EXPECT_STREQ("foo abcdef baz", str.c_str()); } // replace that shrinks the string { CString str("foo bar baz"); str.replace(4, 3, "a"); EXPECT_STREQ("foo a baz", str.c_str()); } // replace at the beginning { CString str("foo bar baz"); str.replace(0, 3, "lkj"); EXPECT_STREQ("lkj bar baz", str.c_str()); } // replace at the end { CString str("foo bar baz"); str.replace(8, 3, "lkj"); EXPECT_STREQ("foo bar lkj", str.c_str()); } // replace all { CString str("foo bar baz"); str.replace(0, 11, "lkj"); EXPECT_STREQ("lkj", str.c_str()); } // r-value replace { const char* dpa = "dpa"; CString str = CString("foo bar baz").replace(4, 3, dpa); EXPECT_STREQ("foo dpa baz", str.c_str()); } } TEST(CString, ReplaceInPlace) { // Shrinking replacement { CString str("0123456789"); const char* const original_cstr = str.c_str(); str.replace(3, 3, "ab"); EXPECT_STREQ("012ab6789", str.c_str()); EXPECT_EQ(9, str.length()); EXPECT_EQ(original_cstr, str.c_str()); } { CString str("0123456789"); const char* const original_cstr = str.c_str(); str.replace(0, 3, "ab"); EXPECT_STREQ("ab3456789", str.c_str()); EXPECT_EQ(9, str.length()); EXPECT_EQ(original_cstr, str.c_str()); } { CString str("0123456789"); const char* const original_cstr = str.c_str(); str.replace(7, 3, "ab"); EXPECT_STREQ("0123456ab", str.c_str()); EXPECT_EQ(9, str.length()); EXPECT_EQ(original_cstr, str.c_str()); } { CString str("0123456789"); const char* const original_cstr = str.c_str(); str.replace(0, 10, "ab"); EXPECT_STREQ("ab", str.c_str()); EXPECT_EQ(2, str.length()); EXPECT_EQ(original_cstr, str.c_str()); } // Same size replacement { CString str("0123456789"); const char* const original_cstr = str.c_str(); str.replace(0, 10, "abcdefghij"); EXPECT_STREQ("abcdefghij", str.c_str()); EXPECT_EQ(10, str.length()); EXPECT_EQ(original_cstr, str.c_str()); } // Shrink to empty { CString str("0123456789"); const char* const original_cstr = str.c_str(); str.replace(3, 3, ""); EXPECT_STREQ("0126789", str.c_str()); EXPECT_EQ(7, str.length()); EXPECT_EQ(original_cstr, str.c_str()); } } TEST(CString, ReplaceZeroLength) { { std::string str("foobar"); str.replace(6, 0, "abc"); EXPECT_STREQ("foobarabc", str.c_str()); } { CString str; str.replace(0, 0, CString("far")); EXPECT_STREQ("far", str.c_str()); } } TEST(CString, ReplacePastEndOfString) { { CString str("foo bar baz"); str.replace(0, 100, CString("bat")); EXPECT_STREQ("bat", str.c_str()); } { CString str("foo bar baz"); str.replace(8, 100, CString("bat")); EXPECT_STREQ("foo bar bat", str.c_str()); } } TEST(CString, ToString) { EXPECT_STREQ("0", to_string(0).c_str()); EXPECT_STREQ("123", to_string(123).c_str()); EXPECT_STREQ("-456", to_string(-456).c_str()); EXPECT_STREQ("2147483647", to_string(INT_MAX).c_str()); EXPECT_STREQ("-2147483648", to_string(INT_MIN).c_str()); EXPECT_STREQ("0", to_string(0u).c_str()); EXPECT_STREQ("4294967295", to_string(UINT_MAX).c_str()); EXPECT_STREQ("0", to_string((short)0).c_str()); EXPECT_STREQ("32767", to_string(SHRT_MAX).c_str()); EXPECT_STREQ("-32768", to_string(SHRT_MIN).c_str()); EXPECT_STREQ("0", to_string((unsigned short)0).c_str()); EXPECT_STREQ("65535", to_string(USHRT_MAX).c_str()); #if LONG_MAX == 2147483647 EXPECT_STREQ("2147483647", to_string(LONG_MAX).c_str()); EXPECT_STREQ("-2147483648", to_string(LONG_MIN).c_str()); EXPECT_STREQ("4294967295", to_string(ULONG_MAX).c_str()); #else EXPECT_STREQ("9223372036854775807", to_string(LONG_MAX).c_str()); EXPECT_STREQ("-9223372036854775808", to_string(LONG_MIN).c_str()); EXPECT_STREQ("18446744073709551615", to_string(ULONG_MAX).c_str()); #endif EXPECT_STREQ("9223372036854775807", to_string(LLONG_MAX).c_str()); EXPECT_STREQ("-9223372036854775808", to_string(LLONG_MIN).c_str()); EXPECT_STREQ("18446744073709551615", to_string(ULLONG_MAX).c_str()); EXPECT_STREQ("0.000000", to_string(0.0f).c_str()); EXPECT_STREQ("1.500000", to_string(1.5f).c_str()); EXPECT_STREQ("-3.140000", to_string(-3.14f).c_str()); } TEST(FixedSizeString, EmptyString) { { FixedSizeString<32> str; EXPECT_STREQ("", str.c_str()); } { FixedSizeString<32> str(""); EXPECT_STREQ("", str.c_str()); } } TEST(FixedSizeString, Constructors) { { FixedSizeString<32> str("short string"); EXPECT_STREQ("short string", str.c_str()); } { FixedSizeString<16> str("a long string abcdefghijklmnopqrst"); EXPECT_STREQ("a long string a", str.c_str()); } }