363 lines
13 KiB
C++
363 lines
13 KiB
C++
/***************************************************************************
|
|
copyright : (C) 2007 by Lukas Lalinsky
|
|
email : lukas@oxygene.sk
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* This library is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU Lesser General Public License version *
|
|
* 2.1 as published by the Free Software Foundation. *
|
|
* *
|
|
* This library is distributed in the hope that it will be useful, but *
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
* Lesser General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Lesser General Public *
|
|
* License along with this library; if not, write to the Free Software *
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
|
* 02110-1301 USA *
|
|
* *
|
|
* Alternatively, this file is available under the Mozilla Public *
|
|
* License Version 1.1. You may obtain a copy of the License at *
|
|
* http://www.mozilla.org/MPL/ *
|
|
***************************************************************************/
|
|
|
|
#include <cstring>
|
|
#include <cppunit/extensions/HelperMacros.h>
|
|
|
|
#include "tstring.h"
|
|
|
|
using namespace std;
|
|
using namespace Strawberry_TagLib::TagLib;
|
|
|
|
class TestString : public CppUnit::TestFixture {
|
|
CPPUNIT_TEST_SUITE(TestString);
|
|
CPPUNIT_TEST(testString);
|
|
CPPUNIT_TEST(testRfind);
|
|
CPPUNIT_TEST(testUTF16Encode);
|
|
CPPUNIT_TEST(testUTF16Decode);
|
|
CPPUNIT_TEST(testUTF16DecodeInvalidBOM);
|
|
CPPUNIT_TEST(testUTF16DecodeEmptyWithBOM);
|
|
CPPUNIT_TEST(testSurrogatePair);
|
|
CPPUNIT_TEST(testAppendCharDetach);
|
|
CPPUNIT_TEST(testAppendStringDetach);
|
|
CPPUNIT_TEST(testToInt);
|
|
CPPUNIT_TEST(testFromInt);
|
|
CPPUNIT_TEST(testSubstr);
|
|
CPPUNIT_TEST(testNewline);
|
|
CPPUNIT_TEST(testUpper);
|
|
CPPUNIT_TEST(testEncodeNonLatin1);
|
|
CPPUNIT_TEST(testEncodeEmpty);
|
|
CPPUNIT_TEST(testEncodeNonBMP);
|
|
CPPUNIT_TEST(testIterator);
|
|
CPPUNIT_TEST(testInvalidUTF8);
|
|
CPPUNIT_TEST_SUITE_END();
|
|
|
|
public:
|
|
void testString() {
|
|
// Needs to know the system byte order for some Unicode tests.
|
|
bool littleEndian;
|
|
{
|
|
union {
|
|
int i;
|
|
char c;
|
|
} u;
|
|
|
|
u.i = 1;
|
|
littleEndian = (u.c == 1) ? true : false;
|
|
}
|
|
|
|
String s = "taglib string";
|
|
ByteVector v = "taglib string";
|
|
CPPUNIT_ASSERT(v == s.data(String::Latin1));
|
|
|
|
char str[] = "taglib string";
|
|
CPPUNIT_ASSERT(strcmp(s.toCString(), str) == 0);
|
|
|
|
s.clear();
|
|
CPPUNIT_ASSERT(s.isEmpty());
|
|
|
|
String unicode("José Carlos", String::UTF8);
|
|
CPPUNIT_ASSERT(strcmp(unicode.toCString(), "Jos\xe9 Carlos") == 0);
|
|
|
|
String latin = "Jos\xe9 Carlos";
|
|
CPPUNIT_ASSERT(strcmp(latin.toCString(true), "José Carlos") == 0);
|
|
|
|
String c;
|
|
c = "1";
|
|
CPPUNIT_ASSERT(c == L"1");
|
|
|
|
c = L'\u4E00';
|
|
CPPUNIT_ASSERT(c == L"\u4E00");
|
|
|
|
String unicode2(unicode.to8Bit(true), String::UTF8);
|
|
CPPUNIT_ASSERT(unicode == unicode2);
|
|
|
|
String unicode3(L"\u65E5\u672C\u8A9E");
|
|
CPPUNIT_ASSERT(*(unicode3.toCWString() + 1) == L'\u672C');
|
|
|
|
String unicode4(L"\u65e5\u672c\u8a9e");
|
|
CPPUNIT_ASSERT(unicode4[1] == L'\u672c');
|
|
|
|
String unicode5(L"\u65e5\u672c\u8a9e", String::UTF16BE);
|
|
CPPUNIT_ASSERT(unicode5[1] == (littleEndian ? L'\u2c67' : L'\u672c'));
|
|
|
|
String unicode6(L"\u65e5\u672c\u8a9e", String::UTF16LE);
|
|
CPPUNIT_ASSERT(unicode6[1] == (littleEndian ? L'\u672c' : L'\u2c67'));
|
|
|
|
CPPUNIT_ASSERT(String(" foo ").stripWhiteSpace() == String("foo"));
|
|
CPPUNIT_ASSERT(String("foo ").stripWhiteSpace() == String("foo"));
|
|
CPPUNIT_ASSERT(String(" foo").stripWhiteSpace() == String("foo"));
|
|
CPPUNIT_ASSERT(String("foo").stripWhiteSpace() == String("foo"));
|
|
CPPUNIT_ASSERT(String("f o o").stripWhiteSpace() == String("f o o"));
|
|
CPPUNIT_ASSERT(String(" f o o ").stripWhiteSpace() == String("f o o"));
|
|
|
|
CPPUNIT_ASSERT(memcmp(String("foo").data(String::Latin1).data(), "foo", 3) == 0);
|
|
CPPUNIT_ASSERT(memcmp(String("f").data(String::Latin1).data(), "f", 1) == 0);
|
|
}
|
|
|
|
void testUTF16Encode() {
|
|
String a("foo");
|
|
ByteVector b("\0f\0o\0o", 6);
|
|
ByteVector c("f\0o\0o\0", 6);
|
|
ByteVector d("\377\376f\0o\0o\0", 8);
|
|
CPPUNIT_ASSERT(a.data(String::UTF16BE) != a.data(String::UTF16LE));
|
|
CPPUNIT_ASSERT(b == a.data(String::UTF16BE));
|
|
CPPUNIT_ASSERT(c == a.data(String::UTF16LE));
|
|
CPPUNIT_ASSERT_EQUAL(d, a.data(String::UTF16));
|
|
}
|
|
|
|
void testUTF16Decode() {
|
|
String a("foo");
|
|
ByteVector b("\0f\0o\0o", 6);
|
|
ByteVector c("f\0o\0o\0", 6);
|
|
ByteVector d("\377\376f\0o\0o\0", 8);
|
|
CPPUNIT_ASSERT_EQUAL(a, String(b, String::UTF16BE));
|
|
CPPUNIT_ASSERT_EQUAL(a, String(c, String::UTF16LE));
|
|
CPPUNIT_ASSERT_EQUAL(a, String(d, String::UTF16));
|
|
}
|
|
|
|
// this test is expected to print "TagLib: String::copyFromUTF16() -
|
|
// Invalid UTF16 string." on the console 3 times
|
|
void testUTF16DecodeInvalidBOM() {
|
|
ByteVector b(" ", 1);
|
|
ByteVector c(" ", 2);
|
|
ByteVector d(" \0f\0o\0o", 8);
|
|
CPPUNIT_ASSERT_EQUAL(String(), String(b, String::UTF16));
|
|
CPPUNIT_ASSERT_EQUAL(String(), String(c, String::UTF16));
|
|
CPPUNIT_ASSERT_EQUAL(String(), String(d, String::UTF16));
|
|
}
|
|
|
|
void testUTF16DecodeEmptyWithBOM() {
|
|
ByteVector a("\377\376", 2);
|
|
ByteVector b("\376\377", 2);
|
|
CPPUNIT_ASSERT_EQUAL(String(), String(a, String::UTF16));
|
|
CPPUNIT_ASSERT_EQUAL(String(), String(b, String::UTF16));
|
|
}
|
|
|
|
void testSurrogatePair() {
|
|
// Make sure that a surrogate pair is converted into single UTF-8 char
|
|
// and vice versa.
|
|
|
|
const ByteVector v1("\xff\xfe\x42\xd8\xb7\xdf\xce\x91\x4b\x5c");
|
|
const ByteVector v2("\xf0\xa0\xae\xb7\xe9\x87\x8e\xe5\xb1\x8b");
|
|
|
|
const String s1(v1, String::UTF16);
|
|
CPPUNIT_ASSERT_EQUAL(s1.data(String::UTF8), v2);
|
|
|
|
const String s2(v2, String::UTF8);
|
|
CPPUNIT_ASSERT_EQUAL(s2.data(String::UTF16), v1);
|
|
|
|
const ByteVector v3("\xfe\xff\xd8\x01\x30\x42");
|
|
CPPUNIT_ASSERT(String(v3, String::UTF16).data(String::UTF8).isEmpty());
|
|
|
|
const ByteVector v4("\xfe\xff\x30\x42\xdc\x01");
|
|
CPPUNIT_ASSERT(String(v4, String::UTF16).data(String::UTF8).isEmpty());
|
|
|
|
const ByteVector v5("\xfe\xff\xdc\x01\xd8\x01");
|
|
CPPUNIT_ASSERT(String(v5, String::UTF16).data(String::UTF8).isEmpty());
|
|
}
|
|
|
|
void testAppendStringDetach() {
|
|
String a("abc");
|
|
String b = a;
|
|
String c = a;
|
|
|
|
b += "def";
|
|
c += L"def";
|
|
|
|
CPPUNIT_ASSERT_EQUAL(String("abc"), a);
|
|
CPPUNIT_ASSERT_EQUAL(String("abcdef"), b);
|
|
CPPUNIT_ASSERT_EQUAL(String("abcdef"), c);
|
|
}
|
|
|
|
void testAppendCharDetach() {
|
|
String a("abc");
|
|
String b = a;
|
|
String c = a;
|
|
|
|
b += 'd';
|
|
c += L'd';
|
|
|
|
CPPUNIT_ASSERT_EQUAL(String("abc"), a);
|
|
CPPUNIT_ASSERT_EQUAL(String("abcd"), b);
|
|
CPPUNIT_ASSERT_EQUAL(String("abcd"), c);
|
|
}
|
|
|
|
void testRfind() {
|
|
CPPUNIT_ASSERT_EQUAL(String::npos(), String("foo.bar").rfind(".", 0));
|
|
CPPUNIT_ASSERT_EQUAL(String::npos(), String("foo.bar").rfind(".", 1));
|
|
CPPUNIT_ASSERT_EQUAL(String::npos(), String("foo.bar").rfind(".", 2));
|
|
CPPUNIT_ASSERT_EQUAL((size_t)3, String("foo.bar").rfind(".", 3));
|
|
CPPUNIT_ASSERT_EQUAL((size_t)3, String("foo.bar").rfind(".", 4));
|
|
CPPUNIT_ASSERT_EQUAL((size_t)3, String("foo.bar").rfind(".", 5));
|
|
CPPUNIT_ASSERT_EQUAL((size_t)3, String("foo.bar").rfind(".", 6));
|
|
CPPUNIT_ASSERT_EQUAL((size_t)3, String("foo.bar").rfind(".", 7));
|
|
CPPUNIT_ASSERT_EQUAL((size_t)3, String("foo.bar").rfind("."));
|
|
}
|
|
|
|
void testToInt() {
|
|
bool ok;
|
|
CPPUNIT_ASSERT_EQUAL(String("123").toInt(&ok), 123);
|
|
CPPUNIT_ASSERT_EQUAL(ok, true);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(String("-123").toInt(&ok), -123);
|
|
CPPUNIT_ASSERT_EQUAL(ok, true);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(String("123aa").toInt(&ok), 123);
|
|
CPPUNIT_ASSERT_EQUAL(ok, false);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(String("-123aa").toInt(&ok), -123);
|
|
CPPUNIT_ASSERT_EQUAL(ok, false);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(String("abc").toInt(&ok), 0);
|
|
CPPUNIT_ASSERT_EQUAL(ok, false);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(String("1x").toInt(&ok), 1);
|
|
CPPUNIT_ASSERT_EQUAL(ok, false);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(String("").toInt(&ok), 0);
|
|
CPPUNIT_ASSERT_EQUAL(ok, false);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(String("-").toInt(&ok), 0);
|
|
CPPUNIT_ASSERT_EQUAL(ok, false);
|
|
|
|
String("9999999999").toInt(&ok);
|
|
CPPUNIT_ASSERT_EQUAL(ok, false);
|
|
|
|
CPPUNIT_ASSERT_EQUAL(String("0000").toInt(), 0);
|
|
CPPUNIT_ASSERT_EQUAL(String("0001").toInt(), 1);
|
|
|
|
String("2147483648").toInt(&ok);
|
|
CPPUNIT_ASSERT_EQUAL(ok, false);
|
|
|
|
String("-2147483649").toInt(&ok);
|
|
CPPUNIT_ASSERT_EQUAL(ok, false);
|
|
}
|
|
|
|
void testFromInt() {
|
|
CPPUNIT_ASSERT_EQUAL(String::number(0), String("0"));
|
|
CPPUNIT_ASSERT_EQUAL(String::number(12345678), String("12345678"));
|
|
CPPUNIT_ASSERT_EQUAL(String::number(-12345678), String("-12345678"));
|
|
}
|
|
|
|
void testSubstr() {
|
|
CPPUNIT_ASSERT_EQUAL(String("01"), String("0123456").substr(0, 2));
|
|
CPPUNIT_ASSERT_EQUAL(String("12"), String("0123456").substr(1, 2));
|
|
CPPUNIT_ASSERT_EQUAL(String("123456"), String("0123456").substr(1, 200));
|
|
CPPUNIT_ASSERT_EQUAL(String("0123456"), String("0123456").substr(0, 7));
|
|
CPPUNIT_ASSERT_EQUAL(String("0123456"), String("0123456").substr(0, 200));
|
|
}
|
|
|
|
void testNewline() {
|
|
ByteVector cr("abc\x0dxyz", 7);
|
|
ByteVector lf("abc\x0axyz", 7);
|
|
ByteVector crlf("abc\x0d\x0axyz", 8);
|
|
|
|
CPPUNIT_ASSERT_EQUAL((size_t)7, String(cr).size());
|
|
CPPUNIT_ASSERT_EQUAL((size_t)7, String(lf).size());
|
|
CPPUNIT_ASSERT_EQUAL((size_t)8, String(crlf).size());
|
|
|
|
CPPUNIT_ASSERT_EQUAL(L'\x0d', String(cr)[3]);
|
|
CPPUNIT_ASSERT_EQUAL(L'\x0a', String(lf)[3]);
|
|
CPPUNIT_ASSERT_EQUAL(L'\x0d', String(crlf)[3]);
|
|
CPPUNIT_ASSERT_EQUAL(L'\x0a', String(crlf)[4]);
|
|
}
|
|
|
|
void testUpper() {
|
|
String s1 = "tagLIB 012 strING";
|
|
String s2 = s1.upper();
|
|
CPPUNIT_ASSERT_EQUAL(String("tagLIB 012 strING"), s1);
|
|
CPPUNIT_ASSERT_EQUAL(String("TAGLIB 012 STRING"), s2);
|
|
}
|
|
|
|
void testEncodeNonLatin1() {
|
|
const String jpn(L"\u65E5\u672C\u8A9E");
|
|
CPPUNIT_ASSERT_EQUAL(ByteVector("\xE5\x2C\x9E"), jpn.data(String::Latin1));
|
|
CPPUNIT_ASSERT_EQUAL(ByteVector("\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E"), jpn.data(String::UTF8));
|
|
CPPUNIT_ASSERT_EQUAL(ByteVector("\xFF\xFE\xE5\x65\x2C\x67\x9E\x8A"), jpn.data(String::UTF16));
|
|
CPPUNIT_ASSERT_EQUAL(ByteVector("\xE5\x65\x2C\x67\x9E\x8A"), jpn.data(String::UTF16LE));
|
|
CPPUNIT_ASSERT_EQUAL(ByteVector("\x65\xE5\x67\x2C\x8A\x9E"), jpn.data(String::UTF16BE));
|
|
CPPUNIT_ASSERT_EQUAL(std::string("\xE5\x2C\x9E"), jpn.to8Bit(false));
|
|
CPPUNIT_ASSERT_EQUAL(std::string("\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E"), jpn.to8Bit(true));
|
|
}
|
|
|
|
void testEncodeEmpty() {
|
|
const String empty;
|
|
CPPUNIT_ASSERT(empty.data(String::Latin1).isEmpty());
|
|
CPPUNIT_ASSERT(empty.data(String::UTF8).isEmpty());
|
|
CPPUNIT_ASSERT_EQUAL(ByteVector("\xFF\xFE"), empty.data(String::UTF16));
|
|
CPPUNIT_ASSERT(empty.data(String::UTF16LE).isEmpty());
|
|
CPPUNIT_ASSERT(empty.data(String::UTF16BE).isEmpty());
|
|
CPPUNIT_ASSERT(empty.to8Bit(false).empty());
|
|
CPPUNIT_ASSERT(empty.to8Bit(true).empty());
|
|
}
|
|
|
|
void testEncodeNonBMP() {
|
|
const ByteVector a("\xFF\xFE\x3C\xD8\x50\xDD\x40\xD8\xF5\xDC\x3C\xD8\x00\xDE", 14);
|
|
const ByteVector b("\xF0\x9F\x85\x90\xF0\xA0\x83\xB5\xF0\x9F\x88\x80");
|
|
CPPUNIT_ASSERT_EQUAL(b, String(a, String::UTF16).data(String::UTF8));
|
|
}
|
|
|
|
void testIterator() {
|
|
String s1 = "taglib string";
|
|
String s2 = s1;
|
|
|
|
String::Iterator it1 = s1.begin();
|
|
String::Iterator it2 = s2.begin();
|
|
|
|
CPPUNIT_ASSERT_EQUAL(L't', *it1);
|
|
CPPUNIT_ASSERT_EQUAL(L't', *it2);
|
|
|
|
std::advance(it1, 4);
|
|
std::advance(it2, 4);
|
|
*it2 = L'I';
|
|
CPPUNIT_ASSERT_EQUAL(L'i', *it1);
|
|
CPPUNIT_ASSERT_EQUAL(L'I', *it2);
|
|
}
|
|
|
|
void testInvalidUTF8() {
|
|
CPPUNIT_ASSERT_EQUAL(String("/"), String(ByteVector("\x2F"), String::UTF8));
|
|
CPPUNIT_ASSERT(String(ByteVector("\xC0\xAF"), String::UTF8).isEmpty());
|
|
CPPUNIT_ASSERT(String(ByteVector("\xE0\x80\xAF"), String::UTF8).isEmpty());
|
|
CPPUNIT_ASSERT(String(ByteVector("\xF0\x80\x80\xAF"), String::UTF8).isEmpty());
|
|
|
|
CPPUNIT_ASSERT(String(ByteVector("\xF8\x80\x80\x80\x80"), String::UTF8).isEmpty());
|
|
CPPUNIT_ASSERT(String(ByteVector("\xFC\x80\x80\x80\x80\x80"), String::UTF8).isEmpty());
|
|
|
|
CPPUNIT_ASSERT(String(ByteVector("\xC2"), String::UTF8).isEmpty());
|
|
CPPUNIT_ASSERT(String(ByteVector("\xE0\x80"), String::UTF8).isEmpty());
|
|
CPPUNIT_ASSERT(String(ByteVector("\xF0\x80\x80"), String::UTF8).isEmpty());
|
|
CPPUNIT_ASSERT(String(ByteVector("\xF8\x80\x80\x80"), String::UTF8).isEmpty());
|
|
CPPUNIT_ASSERT(String(ByteVector("\xFC\x80\x80\x80\x80"), String::UTF8).isEmpty());
|
|
|
|
CPPUNIT_ASSERT(String('\x80', String::UTF8).isEmpty());
|
|
|
|
CPPUNIT_ASSERT(String(ByteVector("\xED\xA0\x80\xED\xB0\x80"), String::UTF8).isEmpty());
|
|
CPPUNIT_ASSERT(String(ByteVector("\xED\xB0\x80\xED\xA0\x80"), String::UTF8).isEmpty());
|
|
}
|
|
};
|
|
|
|
CPPUNIT_TEST_SUITE_REGISTRATION(TestString);
|