[ATL][ATL_APITEST] Implement / Improve CString, based upon the code that was already there. CORE-11579 #resolve

Add code + tests for:
Conversion of A->W and W->A, equality operators, MakeLower, MakeUpper, Find, FindOneOf, ReverseFind, Compare, Mid, Left, Right, Format, Replace, Trim, TrimLeft, TrimRight.

svn path=/trunk/; revision=72061
This commit is contained in:
Mark Jansen 2016-07-30 19:07:43 +00:00
parent 47be569e64
commit 684feb7418
7 changed files with 1158 additions and 5 deletions

View file

@ -200,6 +200,28 @@ public:
return *this;
}
CSimpleStringT& operator=(_In_ const CSimpleStringT& strSrc)
{
CStringData* pData = GetData();
CStringData* pNewData = strSrc.GetData();
if (pNewData != pData)
{
if (!pData->IsLocked() && (pNewData->pStringMgr == pData->pStringMgr))
{
pNewData = CloneData(pNewData);
pData->Release();
Attach(pNewData);
}
else
{
SetString(strSrc.GetString(), strSrc.GetLength());
}
}
return *this;
}
CSimpleStringT& operator+=(_In_ const CSimpleStringT& strSrc)
{
Append(strSrc);
@ -495,7 +517,7 @@ private:
if (pOldData->IsShared())
{
Fork(nLength);
ATLASSERT(FALSE);
//ATLASSERT(FALSE);
}
else if (pOldData->nAllocLength < nLength)
{

View file

@ -124,6 +124,12 @@ public:
typedef CStringT< wchar_t, StrTraitATL< wchar_t, ChTraitsCRT<wchar_t> > > CAtlStringW;
typedef CStringT< char, StrTraitATL< char, ChTraitsCRT<char> > > CAtlStringA;
typedef CAtlStringW CStringW;
typedef CAtlStringA CStringA;
}

View file

@ -28,14 +28,28 @@ public:
static int __cdecl GetBaseTypeLength(_In_z_ LPCWSTR pszSource) throw()
{
return ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSource, -1, NULL, 0, NULL, NULL) - 1;
if (pszSource == NULL) return -1;
return static_cast<int>(wcslen(pszSource));
}
static int __cdecl GetBaseTypeLength(_In_z_ LPCSTR pszSource) throw()
{
if (pszSource == NULL) return 0;
return ::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszSource, -1, NULL, 0) - 1;
}
static int __cdecl GetBaseTypeLength(
_In_reads_(nLength) LPCWSTR pszSource,
_In_ int nLength) throw()
{
return ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSource, nLength, NULL, 0, NULL, NULL);
return nLength;
}
static int __cdecl GetBaseTypeLength(
_In_reads_(nLength) LPCSTR pszSource,
_In_ int nLength) throw()
{
return ::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszSource, nLength, NULL, 0);
}
static void __cdecl ConvertToBaseType(
@ -49,9 +63,198 @@ public:
wmemcpy(pszDest, pszSrc, nSrcLength);
}
static void __cdecl ConvertToBaseType(
_Out_writes_(nDestLength) LPWSTR pszDest,
_In_ int nDestLength,
_In_ LPCSTR pszSrc,
_In_ int nSrcLength = -1)
{
if (nSrcLength == -1)
nSrcLength = 1 + GetBaseTypeLength(pszSrc);
::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength);
}
static void __cdecl MakeLower(
_Out_writes_(nSrcLength) LPWSTR pszSource,
_In_ int nSrcLength)
{
::CharLowerBuffW(pszSource, nSrcLength);
}
static void __cdecl MakeUpper(
_Out_writes_(nSrcLength) LPWSTR pszSource,
_In_ int nSrcLength)
{
::CharUpperBuffW(pszSource, nSrcLength);
}
static LPWSTR __cdecl FindString(
_In_z_ LPCWSTR pszSource,
_In_z_ LPCWSTR pszSub)
{
return ::wcsstr(pszSource, pszSub);
}
static LPWSTR __cdecl FindChar(
_In_z_ LPCWSTR pszSource,
_In_ WCHAR ch)
{
return ::wcschr(pszSource, ch);
}
static LPWSTR __cdecl FindCharReverse(
_In_z_ LPCWSTR pszSource,
_In_ WCHAR ch)
{
return ::wcsrchr(pszSource, ch);
}
static LPWSTR __cdecl FindOneOf(
_In_z_ LPCWSTR pszSource,
_In_z_ LPCWSTR pszCharSet)
{
return ::wcspbrk(pszSource, pszCharSet);
}
static int __cdecl Compare(
_In_z_ LPCWSTR psz1,
_In_z_ LPCWSTR psz2)
{
return ::wcscmp(psz1, psz2);
}
static int __cdecl FormatV(
_In_opt_z_ LPWSTR pszDest,
_In_z_ LPCWSTR pszFormat,
_In_ va_list args)
{
if (pszDest == NULL)
return ::_vscwprintf(pszFormat, args);
return ::vswprintf(pszDest, pszFormat, args);
}
};
// Template specialization
template<>
class ChTraitsCRT<char> : public ChTraitsBase<char>
{
public:
static int __cdecl GetBaseTypeLength(_In_z_ LPCWSTR pszSource) throw()
{
return ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSource, -1, NULL, 0, NULL, NULL) - 1;
}
static int __cdecl GetBaseTypeLength(_In_z_ LPCSTR pszSource) throw()
{
if (pszSource == NULL) return 0;
return static_cast<int>(strlen(pszSource));
}
static int __cdecl GetBaseTypeLength(
_In_reads_(nLength) LPCWSTR pszSource,
_In_ int nLength) throw()
{
return ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSource, nLength, NULL, 0, NULL, NULL);
}
static int __cdecl GetBaseTypeLength(
_In_reads_(nLength) LPCSTR pszSource,
_In_ int nLength) throw()
{
return nLength;
}
static void __cdecl ConvertToBaseType(
_Out_writes_(nDestLength) LPSTR pszDest,
_In_ int nDestLength,
_In_ LPCWSTR pszSrc,
_In_ int nSrcLength = -1)
{
if (nSrcLength == -1)
nSrcLength = 1 + GetBaseTypeLength(pszSrc);
::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL);
}
static void __cdecl ConvertToBaseType(
_Out_writes_(nDestLength) LPSTR pszDest,
_In_ int nDestLength,
_In_ LPCSTR pszSrc,
_In_ int nSrcLength = -1)
{
if (nSrcLength == -1)
nSrcLength = 1 + GetBaseTypeLength(pszSrc);
memcpy(pszDest, pszSrc, nSrcLength);
}
static void __cdecl MakeLower(
_Out_writes_(nSrcLength) LPSTR pszSource,
_In_ int nSrcLength)
{
::CharLowerBuffA(pszSource, nSrcLength);
}
static void __cdecl MakeUpper(
_Out_writes_(nSrcLength) LPSTR pszSource,
_In_ int nSrcLength)
{
::CharUpperBuffA(pszSource, nSrcLength);
}
static LPSTR __cdecl FindString(
_In_z_ LPCSTR pszSource,
_In_z_ LPCSTR pszSub)
{
return ::strstr(pszSource, pszSub);
}
static LPSTR __cdecl FindChar(
_In_z_ LPCSTR pszSource,
_In_ CHAR ch)
{
return ::strchr(pszSource, ch);
}
static LPSTR __cdecl FindCharReverse(
_In_z_ LPCSTR pszSource,
_In_ CHAR ch)
{
return ::strrchr(pszSource, ch);
}
static LPSTR __cdecl FindOneOf(
_In_z_ LPCSTR pszSource,
_In_z_ LPCSTR pszCharSet)
{
return ::strpbrk(pszSource, pszCharSet);
}
static int __cdecl Compare(
_In_z_ LPCSTR psz1,
_In_z_ LPCSTR psz2)
{
return ::strcmp(psz1, psz2);
}
static int __cdecl FormatV(
_In_opt_z_ LPSTR pszDest,
_In_z_ LPCSTR pszFormat,
_In_ va_list args)
{
if (pszDest == NULL)
return ::_vscprintf(pszFormat, args);
return ::vsprintf(pszDest, pszFormat, args);
}
};
namespace _CSTRING_IMPL_
{
@ -63,6 +266,8 @@ namespace _CSTRING_IMPL_
}
// TODO: disable conversion functions when _CSTRING_DISABLE_NARROW_WIDE_CONVERSION is defined.
template <typename BaseType, class StringTraits>
class CStringT :
public CSimpleStringT <BaseType, _CSTRING_IMPL_::_MFCDLLTraitsCheck<BaseType, StringTraits>::c_bIsMFCDLLTraits>
@ -90,7 +295,7 @@ public:
static void __cdecl Construct(_In_ CStringT* pString)
{
pString = new CStringT;
new(pString) CStringT;
}
CStringT(_In_ const CStringT& strSrc) :
@ -98,6 +303,13 @@ public:
{
}
template<class StringTraits_>
CStringT(_In_ const CStringT<YCHAR, StringTraits_> & strSrc) :
CThisSimpleString(StringTraits::GetDefaultManager())
{
*this = static_cast<const YCHAR*>(strSrc);
}
CStringT(_In_opt_z_ const XCHAR* pszSrc) :
CThisSimpleString( StringTraits::GetDefaultManager() )
{
@ -114,6 +326,36 @@ public:
*this = pszSrc;
}
CStringT(_In_opt_z_ const YCHAR* pszSrc) :
CThisSimpleString( StringTraits::GetDefaultManager() )
{
// FIXME: Check whether pszSrc is not a resource string ID!
*this = pszSrc;
}
CStringT(
_In_opt_z_ const YCHAR* pszSrc,
_In_ IAtlStringMgr* pStringMgr) :
CThisSimpleString( pStringMgr )
{
// FIXME: Check whether pszSrc is not a resource string ID!
*this = pszSrc;
}
CStringT(
_In_reads_z_(nLength) const XCHAR* pch,
_In_ int nLength) :
CThisSimpleString(pch, nLength, StringTraits::GetDefaultManager())
{
}
CStringT(
_In_reads_z_(nLength) const YCHAR* pch,
_In_ int nLength) :
CThisSimpleString(pch, nLength, StringTraits::GetDefaultManager())
{
}
CStringT& operator=(_In_ const CStringT& strSrc)
{
CThisSimpleString::operator=(strSrc);
@ -126,6 +368,59 @@ public:
return *this;
}
CStringT& operator=(_In_opt_z_ PCYSTR pszSrc)
{
int length = pszSrc ? StringTraits::GetBaseTypeLength(pszSrc) : 0;
if (length > 0)
{
PXSTR result = CThisSimpleString::GetBuffer(length);
StringTraits::ConvertToBaseType(result, length, pszSrc);
CThisSimpleString::ReleaseBufferSetLength(length);
}
else
{
CThisSimpleString::Empty();
}
return *this;
}
friend bool operator==(const CStringT& str1, const CStringT& str2) throw()
{
return str1.Compare(str2) == 0;
}
friend bool operator==(const CStringT& str1, PCXSTR psz2) throw()
{
return str1.Compare(psz2) == 0;
}
friend bool operator==(const CStringT& str1, PCYSTR psz2) throw()
{
CStringT tmp(psz2, str1.GetManager());
return tmp == str1;
}
friend bool operator==(const CStringT& str1, XCHAR ch2) throw()
{
return str1.GetLength() == 1 && str1[0] == ch2;
}
friend bool operator==(PCXSTR psz1, const CStringT& str2) throw()
{
return str2.Compare(psz1) == 0;
}
friend bool operator==(PCYSTR psz1, const CStringT& str2) throw()
{
CStringT tmp(psz1, str2.GetManager());
return tmp.Compare(str2) == 0;
}
friend bool operator==(XCHAR ch1, const CStringT& str2) throw()
{
return str2.GetLength() == 1 && str2[0] == ch1;
}
CStringT& operator+=(_In_ const CThisSimpleString& str)
{
CThisSimpleString::operator+=(str);
@ -151,6 +446,299 @@ public:
return TRUE;
}
CStringT& MakeLower()
{
int nLength = CThisSimpleString::GetLength();
PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
StringTraits::MakeLower(pszBuffer, nLength);
CThisSimpleString::ReleaseBufferSetLength(nLength);
return *this;
}
CStringT& MakeUpper()
{
int nLength = CThisSimpleString::GetLength();
PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
StringTraits::MakeUpper(pszBuffer, nLength);
CThisSimpleString::ReleaseBufferSetLength(nLength);
return *this;
}
int Find(_In_ PCXSTR pszSub, _In_opt_ int iStart = 0) const throw()
{
int nLength = CThisSimpleString::GetLength();
if (iStart >= nLength || iStart < 0)
return -1;
PCXSTR pszString = CThisSimpleString::GetString();
PCXSTR pszResult = StringTraits::FindString(pszString + iStart, pszSub);
return pszResult ? ((int)(pszResult - pszString)) : -1;
}
int Find(_In_ XCHAR ch, _In_opt_ int iStart = 0) const throw()
{
int nLength = CThisSimpleString::GetLength();
if (iStart >= nLength || iStart < 0)
return -1;
PCXSTR pszString = CThisSimpleString::GetString();
PCXSTR pszResult = StringTraits::FindChar(pszString + iStart, ch);
return pszResult ? ((int)(pszResult - pszString)) : -1;
}
int FindOneOf(_In_ PCXSTR pszCharSet) const throw()
{
PCXSTR pszString = CThisSimpleString::GetString();
PCXSTR pszResult = StringTraits::FindOneOf(pszString, pszCharSet);
return pszResult ? ((int)(pszResult - pszString)) : -1;
}
int ReverseFind(_In_ XCHAR ch) const throw()
{
PCXSTR pszString = CThisSimpleString::GetString();
PCXSTR pszResult = StringTraits::FindCharReverse(pszString, ch);
return pszResult ? ((int)(pszResult - pszString)) : -1;
}
int Compare(_In_z_ PCXSTR psz) const
{
return StringTraits::Compare(CThisSimpleString::GetString(), psz);
}
CStringT Mid(int iFirst, int nCount) const
{
int nLength = CThisSimpleString::GetLength();
if (iFirst < 0)
iFirst = 0;
if (nCount < 0)
nCount = 0;
if (iFirst > nLength)
iFirst = nLength;
if (iFirst + nCount > nLength)
nCount = nLength - iFirst;
return CStringT(CThisSimpleString::GetString() + iFirst, nCount);
}
CStringT Mid(int iFirst) const
{
int nLength = CThisSimpleString::GetLength();
if (iFirst < 0)
iFirst = 0;
if (iFirst > nLength)
iFirst = nLength;
return CStringT(CThisSimpleString::GetString() + iFirst, nLength - iFirst);
}
CStringT Left(int nCount) const
{
int nLength = CThisSimpleString::GetLength();
if (nCount < 0)
nCount = 0;
if (nCount > nLength)
nCount = nLength;
return CStringT(CThisSimpleString::GetString(), nCount);
}
CStringT Right(int nCount) const
{
int nLength = CThisSimpleString::GetLength();
if (nCount < 0)
nCount = 0;
if (nCount > nLength)
nCount = nLength;
return CStringT(CThisSimpleString::GetString() + nLength - nCount, nCount);
}
//void __cdecl Format(UINT nFormatID, ...)
//{
// va_list args;
// va_start(args, dwMessageId);
// CStringT formatString;
// formatString.LoadString(?????);
// FormatV(formatString, args);
// va_end(args);
//}
void __cdecl Format(PCXSTR pszFormat, ...)
{
va_list args;
va_start(args, pszFormat);
FormatV(pszFormat, args);
va_end(args);
}
void FormatV(PCXSTR pszFormat, va_list args)
{
int nLength = StringTraits::FormatV(NULL, pszFormat, args);
PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
StringTraits::FormatV(pszBuffer, pszFormat, args);
CThisSimpleString::ReleaseBufferSetLength(nLength);
}
int Replace(PCXSTR pszOld, PCXSTR pszNew)
{
PCXSTR pszString = CThisSimpleString::GetString();
const int nLength = CThisSimpleString::GetLength();
const int nOldLen = StringTraits::GetBaseTypeLength(pszOld);
const int nNewLen = StringTraits::GetBaseTypeLength(pszNew);
const int nDiff = nNewLen - nOldLen;
int nResultLength = nLength;
PCXSTR pszFound;
while ((pszFound = StringTraits::FindString(pszString, pszOld)))
{
nResultLength += nDiff;
pszString = pszFound + nOldLen;
}
if (pszString == CThisSimpleString::GetString())
return 0;
PXSTR pszResult = CThisSimpleString::GetBuffer(nResultLength);
PXSTR pszNext;
int nCount = 0, nRemaining = nLength;
while (nRemaining && (pszNext = StringTraits::FindString(pszResult, pszOld)))
{
nRemaining -= (pszNext - pszResult);
nRemaining -= nOldLen;
if (nRemaining > 0)
CThisSimpleString::CopyCharsOverlapped(pszNext + nNewLen, nRemaining + 1, pszNext + nOldLen, nRemaining + 1);
CThisSimpleString::CopyCharsOverlapped(pszNext, nNewLen, pszNew, nNewLen);
pszResult = pszNext + nNewLen;
nCount++;
}
CThisSimpleString::ReleaseBufferSetLength(nResultLength);
return nCount;
}
int Replace(XCHAR chOld, XCHAR chNew)
{
PCXSTR pszString = CThisSimpleString::GetString();
PXSTR pszFirst = StringTraits::FindChar(pszString, chOld);
if (!pszFirst)
return 0;
int nLength = CThisSimpleString::GetLength();
int nCount = 0;
PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
pszFirst = pszBuffer + (pszFirst - pszString);
do {
*pszFirst = chNew;
++nCount;
} while ((pszFirst = StringTraits::FindChar(pszFirst + 1, chOld)));
CThisSimpleString::ReleaseBufferSetLength(nLength);
return nCount;
}
static PCXSTR DefaultTrimChars()
{
static XCHAR str[] = { ' ', '\t', '\r', '\n', 0 };
return str;
}
CStringT& TrimLeft()
{
return TrimLeft(DefaultTrimChars());
}
CStringT& TrimLeft(XCHAR chTarget)
{
XCHAR str[2] = { chTarget, 0 };
return TrimLeft(str);
}
CStringT& TrimLeft(PCXSTR pszTargets)
{
int nLength = CThisSimpleString::GetLength();
PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
int nCount = 0;
while (nCount < nLength && StringTraits::FindChar(pszTargets, pszBuffer[nCount]))
nCount++;
if (nCount > 0)
{
CThisSimpleString::CopyCharsOverlapped(pszBuffer, nLength - nCount, pszBuffer + nCount, nLength - nCount);
nLength -= nCount;
}
CThisSimpleString::ReleaseBufferSetLength(nLength);
return *this;
}
CStringT& TrimRight()
{
return TrimRight(DefaultTrimChars());
}
CStringT& TrimRight(XCHAR chTarget)
{
XCHAR str[2] = { chTarget, 0 };
return TrimRight(str);
}
CStringT& TrimRight(PCXSTR pszTargets)
{
int nLength = CThisSimpleString::GetLength();
PXSTR pszBuffer = CThisSimpleString::GetBuffer(nLength);
while (nLength > 0 && StringTraits::FindChar(pszTargets, pszBuffer[nLength-1]))
nLength--;
CThisSimpleString::ReleaseBufferSetLength(nLength);
return *this;
}
CStringT& Trim()
{
return Trim(DefaultTrimChars());
}
CStringT& Trim(XCHAR chTarget)
{
XCHAR str[2] = { chTarget, 0 };
return Trim(str);
}
CStringT& Trim(PCXSTR pszTargets)
{
return TrimRight(pszTargets).TrimLeft(pszTargets);
}
};
} //namespace ATL

View file

@ -1,11 +1,12 @@
set_cpp(WITH_RUNTIME)
set_cpp(WITH_RUNTIME WITH_EXCEPTIONS)
include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/atl)
add_executable(atl_apitest
CComBSTR.cpp
CComHeapPtr.cpp
CString.cpp
testlist.c
atl_apitest.rc)

View file

@ -0,0 +1,176 @@
/*
* PROJECT: ReactOS api tests
* LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
* PURPOSE: Test for CString
* PROGRAMMER: Mark Jansen
*/
#include <apitest.h>
#include <atlstr.h>
struct traits_test
{
const char* strA;
const wchar_t* strW;
int str_len;
int exp_1, exp_2, exp_3, exp_4;
};
traits_test g_Tests[] = {
// inputs outputs
{ NULL, NULL, 0, 0, 0, -1, 0 },
{ NULL, NULL, -1, 0, -1, -1, 0 },
{ NULL, NULL, 1, 0, 1, -1, 0 },
{ "", L"", 0, 0, 0, 0, 0 },
{ "", L"", -1, 0, -1, 0, 1 },
{ "", L"", 1, 0, 1, 0, 1 },
{ "AAABBB", L"AAABBB", 0, 6, 0, 6, 0 },
{ "AAABBB", L"AAABBB", 3, 6, 3, 6, 3 },
{ "AAABBB", L"AAABBB", -1, 6, -1, 6, 7 },
};
static void test_basetypes()
{
int len;
char bufA[10];
wchar_t bufW[10];
for (size_t n = 0; n < _countof(g_Tests); ++n)
{
len = ChTraitsCRT<char>::GetBaseTypeLength(g_Tests[n].strA);
ok(len == g_Tests[n].exp_1, "Expected len to be %i, was %i for %u (A)\n", g_Tests[n].exp_1, len, n);
len = ChTraitsCRT<char>::GetBaseTypeLength(g_Tests[n].strA, g_Tests[n].str_len);
ok(len == g_Tests[n].exp_2, "Expected len to be %i, was %i for %u (A,len)\n", g_Tests[n].exp_2, len, n);
len = ChTraitsCRT<char>::GetBaseTypeLength(g_Tests[n].strW);
ok(len == g_Tests[n].exp_3, "Expected len to be %i, was %i for %u (W)\n", g_Tests[n].exp_3, len, n);
len = ChTraitsCRT<char>::GetBaseTypeLength(g_Tests[n].strW, g_Tests[n].str_len);
ok(len == g_Tests[n].exp_4, "Expected len to be %i, was %i for %u (W,len)\n", g_Tests[n].exp_4, len, n);
if (g_Tests[n].strA && g_Tests[n].strW)
{
memset(bufA, 'x', sizeof(bufA));
ChTraitsCRT<char>::ConvertToBaseType(bufA, g_Tests[n].exp_1+1, g_Tests[n].strA);
char ch = bufA[g_Tests[n].exp_1];
ok(ch == '\0', "Expected %i to be \\0, was: %c (%i) for %u\n", g_Tests[n].exp_1, ch, (int)ch, n);
ok(!strcmp(bufA, g_Tests[n].strA), "Expected bufA to be %s, was: %s for %u\n", g_Tests[n].strA, bufA, n);
ch = bufA[g_Tests[n].exp_1+1];
ok(ch == 'x', "Expected %i to be 'x', was: %c (%i) for %u\n", g_Tests[n].exp_1+1, ch, (int)ch, n);
}
if (g_Tests[n].strA && g_Tests[n].strW)
{
memset(bufA, 'x', sizeof(bufA));
ChTraitsCRT<char>::ConvertToBaseType(bufA, g_Tests[n].exp_1+1, g_Tests[n].strW);
char ch = bufA[g_Tests[n].exp_1];
ok(ch == '\0', "Expected %i to be \\0, was: %c (%i) for %u\n", g_Tests[n].exp_1, ch, (int)ch, n);
ok(!strcmp(bufA, g_Tests[n].strA), "Expected bufA to be %s, was: %s for %u\n", g_Tests[n].strA, bufA, n);
ch = bufA[g_Tests[n].exp_1+1];
ok(ch == 'x', "Expected %i to be 'x', was: %c (%i) for %u\n", g_Tests[n].exp_1+1, ch, (int)ch, n);
}
// wchar_t --> please note, swapped the expectations from 2 and 4 !
len = ChTraitsCRT<wchar_t>::GetBaseTypeLength(g_Tests[n].strA);
ok(len == g_Tests[n].exp_1, "Expected len to be %i, was %i for %u (A)\n", g_Tests[n].exp_1, len, n);
len = ChTraitsCRT<wchar_t>::GetBaseTypeLength(g_Tests[n].strA, g_Tests[n].str_len);
ok(len == g_Tests[n].exp_4, "Expected len to be %i, was %i for %u (A,len)\n", g_Tests[n].exp_4, len, n);
len = ChTraitsCRT<wchar_t>::GetBaseTypeLength(g_Tests[n].strW);
ok(len == g_Tests[n].exp_3, "Expected len to be %i, was %i for %u (W)\n", g_Tests[n].exp_3, len, n);
len = ChTraitsCRT<wchar_t>::GetBaseTypeLength(g_Tests[n].strW, g_Tests[n].str_len);
ok(len == g_Tests[n].exp_2, "Expected len to be %i, was %i for %u (W,len)\n", g_Tests[n].exp_2, len, n);
if (g_Tests[n].strA && g_Tests[n].strW)
{
memset(bufW, 'x', sizeof(bufW));
ChTraitsCRT<wchar_t>::ConvertToBaseType(bufW, g_Tests[n].exp_1+1, g_Tests[n].strA);
wchar_t ch = bufW[g_Tests[n].exp_1];
ok(ch == L'\0', "Expected %i to be \\0, was: %c (%i) for %u\n", g_Tests[n].exp_1, ch, (int)ch, n);
ok(!wcscmp(bufW, g_Tests[n].strW), "Expected bufW to be %s, was: %s for %u\n", wine_dbgstr_w(g_Tests[n].strW), wine_dbgstr_w(bufW), n);
ch = bufW[g_Tests[n].exp_1+1];
ok(ch == 30840, "Expected %i to be %i for %u\n", g_Tests[n].exp_1+1, (int)ch, n);
}
if (g_Tests[n].strA && g_Tests[n].strW)
{
memset(bufW, 'x', sizeof(bufW));
ChTraitsCRT<wchar_t>::ConvertToBaseType(bufW, g_Tests[n].exp_1+1, g_Tests[n].strW);
wchar_t ch = bufW[g_Tests[n].exp_1];
ok(ch == '\0', "Expected %i to be \\0, was: %c (%i) for %u\n", g_Tests[n].exp_1, ch, (int)ch, n);
ok(!wcscmp(bufW, g_Tests[n].strW), "Expected bufW to be %s, was: %s for %u\n", wine_dbgstr_w(g_Tests[n].strW), wine_dbgstr_w(bufW), n);
ch = bufW[g_Tests[n].exp_1+1];
ok(ch == 30840, "Expected %i to be %i for %u\n", g_Tests[n].exp_1+1, (int)ch, n);
}
}
}
// Allocation strategy seems to differ a bit between us and MS's atl.
// if someone cares enough to find out why, feel free to change the macro below.
#define ALLOC_EXPECT(a, b) b
#undef ok
#undef _T
#define TEST_NAMEX(name) void test_##name##W()
#define CStringX CStringW
#define _X(x) L ## x
#define XCHAR WCHAR
#define dbgstrx(x) wine_dbgstr_w(x)
#define ok ok_("CStringW:\n" __FILE__, __LINE__)
#include "CString.inl"
#undef CStringX
#undef TEST_NAMEX
#undef _X
#undef XCHAR
#undef dbgstrx
#undef ok
#define TEST_NAMEX(name) void test_##name##A()
#define CStringX CStringA
#define _X(x) x
#define XCHAR CHAR
#define dbgstrx(x) (const char*)x
#define ok ok_("CStringA:\n" __FILE__, __LINE__)
#include "CString.inl"
START_TEST(CString)
{
test_basetypes();
if ((ALLOC_EXPECT(1, 2)) == 2)
{
skip("Ignoring real GetAllocLength() lenght\n");
}
test_operators_initW();
test_operators_initA();
test_compareW();
test_compareA();
test_findW();
test_findA();
test_formatW();
test_formatA();
test_substrW();
test_substrA();
test_replaceW();
test_replaceA();
test_trimW();
test_trimA();
}

View file

@ -0,0 +1,358 @@
TEST_NAMEX(operators_init)
{
CStringX test;
ok(test.IsEmpty() == true, "Expected test to be empty\n");
ok(test.GetLength() == 0, "Expected GetLength() to be 0, was: %i\n", test.GetLength());
ok(test.GetAllocLength() == 0, "Expected GetAllocLength() to be 0, was: %i\n", test.GetAllocLength());
// Operator
const XCHAR* cstring = (const XCHAR*)test;
ok(cstring != NULL, "Expected a valid pointer\n");
if (cstring)
{
ok(cstring[0] == '\0', "Expected \\0, got: %c (%i)\n", cstring[0], (int)cstring[0]);
}
CStringX first(_X("First "));
ok(first.IsEmpty() != true, "Expected first to not be empty\n");
ok(first.GetLength() == 6, "Expected GetLength() to be 6, was: %i\n", first.GetLength());
ok(first.GetAllocLength() == ALLOC_EXPECT(7, 6), "Expected GetAllocLength() to be %i, was: %i\n", ALLOC_EXPECT(7, 6), first.GetAllocLength());
CStringX second(_X("Second"));
ok(second.IsEmpty() != true, "Expected second to not be empty\n");
ok(second.GetLength() == 6, "Expected GetLength() to be 6, was: %i\n", second.GetLength());
ok(second.GetAllocLength() == ALLOC_EXPECT(7, 6), "Expected GetAllocLength() to be %i, was: %i\n", ALLOC_EXPECT(7, 6), second.GetAllocLength());
test = first;
ok(test.IsEmpty() != true, "Expected test to not be empty\n");
ok(test.GetLength() == 6, "Expected GetLength() to be 6, was: %i\n", test.GetLength());
ok(test.GetAllocLength() == ALLOC_EXPECT(7, 6), "Expected GetAllocLength() to be %i, was: %i\n", ALLOC_EXPECT(7, 6), test.GetAllocLength());
test.Empty();
ok(test.IsEmpty() == true, "Expected test to be empty\n");
ok(test.GetLength() == 0, "Expected GetLength() to be 0, was: %i\n", test.GetLength());
ok(test.GetAllocLength() == 0, "Expected GetAllocLength() to be 0, was: %i\n", test.GetAllocLength());
test = _X("First ");
ok(test.IsEmpty() != true, "Expected test to not be empty\n");
ok(test.GetLength() == 6, "Expected GetLength() to be 6, was: %i\n", test.GetLength());
ok(test.GetAllocLength() == ALLOC_EXPECT(7, 6), "Expected GetAllocLength() to be %i, was: %i\n", ALLOC_EXPECT(7, 6), test.GetAllocLength());
test += second;
ok(test.IsEmpty() != true, "Expected test to not be empty\n");
ok(test.GetLength() == 12, "Expected GetLength() to be 12, was: %i\n", test.GetLength());
ok(test.GetAllocLength() == ALLOC_EXPECT(15, 12), "Expected GetAllocLength() to be %i, was: %i\n", ALLOC_EXPECT(15, 12), test.GetAllocLength());
test = first + second;
ok(test.IsEmpty() != true, "Expected test to not be empty\n");
ok(test.GetLength() == 12, "Expected GetLength() to be 12, was: %i\n", test.GetLength());
ok(test.GetAllocLength() == ALLOC_EXPECT(15, 12), "Expected GetAllocLength() to be %i, was: %i\n", ALLOC_EXPECT(15, 12), test.GetAllocLength());
test = first + second + _X(".");
ok(test.IsEmpty() != true, "Expected test to not be empty\n");
ok(test.GetLength() == 13, "Expected GetLength() to be 13, was: %i\n", test.GetLength());
ok(test.GetAllocLength() == ALLOC_EXPECT(15, 18), "Expected GetAllocLength() to be %i, was: %i\n", ALLOC_EXPECT(15, 18), test.GetAllocLength());
CStringX test2(test);
ok(test2.IsEmpty() != true, "Expected test2 to not be empty\n");
ok(test2.GetLength() == 13, "Expected GetLength() to be 13, was: %i\n", test2.GetLength());
ok(test2.GetAllocLength() == ALLOC_EXPECT(15, 18), "Expected GetAllocLength() to be %i, was: %i\n", ALLOC_EXPECT(15, 18), test2.GetAllocLength());
// Clear it again
test.Empty();
ok(test.IsEmpty() == true, "Expected test to be empty\n");
ok(test.GetLength() == 0, "Expected GetLength() to be 0, was: %i\n", test.GetLength());
ok(test.GetAllocLength() == 0, "Expected GetAllocLength() to be 0, was: %i\n", test.GetAllocLength());
// Assign string
test = "First ";
ok(test.IsEmpty() != true, "Expected test to not be empty\n");
ok(test.GetLength() == 6, "Expected GetLength() to be 6, was: %i\n", test.GetLength());
ok(test.GetAllocLength() == ALLOC_EXPECT(7, 6), "Expected GetAllocLength() to be 7, was: %i\n", test.GetAllocLength());
CStringA testA = test;
ok(testA.IsEmpty() != true, "Expected testA to not be empty\n");
ok(testA.GetLength() == 6, "Expected GetLength() to be 6, was: %i\n", testA.GetLength());
ok(testA.GetAllocLength() == ALLOC_EXPECT(7, 6), "Expected GetAllocLength() to be 7, was: %i\n", testA.GetAllocLength());
CStringW testW = test;
ok(testW.IsEmpty() != true, "Expected testW to not be empty\n");
ok(testW.GetLength() == 6, "Expected GetLength() to be 6, was: %i\n", testW.GetLength());
ok(testW.GetAllocLength() == ALLOC_EXPECT(7, 6), "Expected GetAllocLength() to be 7, was: %i\n", testW.GetAllocLength());
// Assign wstring
test = L"First ";
ok(test.IsEmpty() != true, "Expected test to not be empty\n");
ok(test.GetLength() == 6, "Expected GetLength() to be 6, was: %i\n", test.GetLength());
ok(test.GetAllocLength() == ALLOC_EXPECT(7, 6), "Expected GetAllocLength() to be 7, was: %i\n", test.GetAllocLength());
}
TEST_NAMEX(compare)
{
CStringX s1, s2;
s1 = s2 = _X("some text 1!");
int c = s1.Compare(s2);
ok(c == 0, "Expected c to be 1, was: %i\n", c);
c = s1.Compare(_X("r"));
ok(c == 1, "Expected c to be 1, was: %i\n", c);
c = s1.Compare(_X("s"));
ok(c == 1, "Expected c to be 1, was: %i\n", c);
c = s1.Compare(_X("t"));
ok(c == -1, "Expected c to be -1, was: %i\n", c);
c = s1.Compare(_X("R"));
ok(c == 1, "Expected c to be 1, was: %i\n", c);
c = s1.Compare(_X("S"));
ok(c == 1, "Expected c to be 1, was: %i\n", c);
c = s1.Compare(_X("T"));
ok(c == 1, "Expected c to be 1, was: %i\n", c);
ok(s1 == s2, "Expected s1 and s2 to be equal: '%s' == '%s'\n", dbgstrx(s1), dbgstrx(s2));
s1.MakeUpper(); // Does not modify s2
ok(s1[0] == _X('S'), "Expected s1[0] to be S, was: %c\n", (char)s1[0]);
ok(s2[0] == _X('s'), "Expected s2[0] to be s, was: %c\n", (char)s2[0]);
ok(s1 == _X("SOME TEXT 1!"), "Expected s1 to be 'SOME TEXT 1!', was: %s\n", dbgstrx(s1));
CStringX s3 = s1.MakeLower();
ok(s1 == _X("some text 1!"), "Expected s1 to be 'some text 1!', was: %s\n", dbgstrx(s1));
ok(s1 == s3, "Expected s1 and s3 to be equal: '%s' == '%s'\n", dbgstrx(s1), dbgstrx(s3));
}
TEST_NAMEX(find)
{
CStringX s(_X("adbcdef"));
int n = s.Find(_X('c'));
ok(n == 3, "Expected n to be 2, was %i\n", n);
n = s.Find(_X("de"));
ok(n == 4, "Expected n to be 4, was %i\n", n);
CStringX str(_X("The waves are still"));
n = str.Find(_X('e'), 5);
ok(n == 7, "Expected n to be 7, was %i\n", n);
n = str.Find(_X('e'), 7);
ok(n == 7, "Expected n to be 7, was %i\n", n);
s = _X("abcdefGHIJKLMNop");
n = s.FindOneOf(_X("Nd"));
ok(n == 3, "Expected n to be 3, was %i\n", n);
n = s.FindOneOf(_X("Np"));
ok(n == 13, "Expected n to be 13, was %i\n", n);
n = str.ReverseFind(_X('l'));
ok(n == 18, "Expected n to be 18, was %i\n", n);
n = str.ReverseFind(_X('e'));
ok(n == 12, "Expected n to be 12, was %i\n", n);
}
void WriteString(const XCHAR* pstrFormat, ...)
{
CStringX str;
va_list args;
va_start(args, pstrFormat);
str.FormatV(pstrFormat, args);
va_end(args);
ok(str == _X("10e 1351l"), "Expected str to be '10e 1351l', was: %s\n", dbgstrx(str));
}
TEST_NAMEX(format)
{
CStringX str;
str.Format(_X("FP: %.2f"), 12345.12345);
ok(str == _X("FP: 12345.12"), "Expected str to be 'FP: 12345.12', was: %s\n", dbgstrx(str));
str.Format(_X("int: %.6d"), 35);
ok(str == _X("int: 000035"), "Expected str to be 'int: 000035', was: %s\n", dbgstrx(str));
WriteString(_X("%de %dl"), 10, 1351);
}
TEST_NAMEX(substr)
{
CStringX s(_X("abcdef"));
CStringX m = s.Mid(2, 3);
ok(m == _X("cde"), "Expected str to be 'cde', was: %s\n", dbgstrx(m));
ok(m.GetLength() == 3, "Expected GetLength() to be 3, was: %i\n", m.GetLength());
m = s.Mid(-5, 3);
ok(m == _X("abc"), "Expected str to be 'abc', was: %s\n", dbgstrx(m));
ok(m.GetLength() == 3, "Expected GetLength() to be 3, was: %i\n", m.GetLength());
m = s.Mid(3, 20);
ok(m == _X("def"), "Expected str to be 'def', was: %s\n", dbgstrx(m));
ok(m.GetLength() == 3, "Expected GetLength() to be 3, was: %i\n", m.GetLength());
m = s.Mid(3, -1);
ok(m == _X(""), "Expected str to be '', was: %s\n", dbgstrx(m));
ok(m.GetLength() == 0, "Expected GetLength() to be 0, was: %i\n", m.GetLength());
m = s.Mid(2);
ok(m == _X("cdef"), "Expected str to be 'cdef', was: %s\n", dbgstrx(m));
ok(m.GetLength() == 4, "Expected GetLength() to be 4, was: %i\n", m.GetLength());
m = s.Mid(-3);
ok(m == _X("abcdef"), "Expected str to be 'abcdef', was: %s\n", dbgstrx(m));
ok(m.GetLength() == 6, "Expected GetLength() to be 6, was: %i\n", m.GetLength());
m = s.Mid(20);
ok(m == _X(""), "Expected str to be '', was: %s\n", dbgstrx(m));
ok(m.GetLength() == 0, "Expected GetLength() to be 0, was: %i\n", m.GetLength());
m = s.Left(2);
ok(m == _X("ab"), "Expected str to be 'ab', was: %s\n", dbgstrx(m));
ok(m.GetLength() == 2, "Expected GetLength() to be 2, was: %i\n", m.GetLength());
m = s.Left(40);
ok(m == _X("abcdef"), "Expected str to be 'abcdef', was: %s\n", dbgstrx(m));
ok(m.GetLength() == 6, "Expected GetLength() to be 6, was: %i\n", m.GetLength());
m = s.Left(-10);
ok(m == _X(""), "Expected str to be '', was: %s\n", dbgstrx(m));
ok(m.GetLength() == 0, "Expected GetLength() to be 0, was: %i\n", m.GetLength());
m = s.Right(2);
ok(m == _X("ef"), "Expected str to be 'ef', was: %s\n", dbgstrx(m));
ok(m.GetLength() == 2, "Expected GetLength() to be 2, was: %i\n", m.GetLength());
m = s.Right(-40);
ok(m == _X(""), "Expected str to be '', was: %s\n", dbgstrx(m));
ok(m.GetLength() == 0, "Expected GetLength() to be 0, was: %i\n", m.GetLength());
m = s.Right(99);
ok(m == _X("abcdef"), "Expected str to be 'abcdef', was: %s\n", dbgstrx(m));
ok(m.GetLength() == 6, "Expected GetLength() to be 6, was: %i\n", m.GetLength());
}
TEST_NAMEX(replace)
{
CStringX str(_X("abcde"));
int n = str.Replace(_X("b"), _X("bx"));
ok(n == 1, "Expected n to be 1, was %i\n", n);
ok(str == _X("abxcde"), "Expected str to be 'abxcde', was: %s\n", dbgstrx(str));
ok(str.GetLength() == 6, "Expected GetLength() to be 6, was: %i\n", str.GetLength());
CStringX strBang(_X("The quick brown fox is lazy today of all days"));
n = strBang.Replace(_X("is"), _X("was"));
ok(n == 1, "Expected n to be 1, was %i\n", n);
ok(strBang == _X("The quick brown fox was lazy today of all days"),
"Expected str to be 'The quick brown fox was lazy today of all days', was: %s\n", dbgstrx(strBang));
ok(strBang.GetLength() == 46, "Expected GetLength() to be 46, was: %i\n", strBang.GetLength());
n = strBang.Replace(_X("is"), _X("was"));
ok(n == 0, "Expected n to be 0, was %i\n", n);
ok(strBang == _X("The quick brown fox was lazy today of all days"),
"Expected str to be 'The quick brown fox was lazy today of all days', was: %s\n", dbgstrx(strBang));
ok(strBang.GetLength() == 46, "Expected GetLength() to be 46, was: %i\n", strBang.GetLength());
n = strBang.Replace(_X('o'), _X('0'));
ok(n == 4, "Expected n to be 4, was %i\n", n);
ok(strBang == _X("The quick br0wn f0x was lazy t0day 0f all days"),
"Expected str to be 'The quick br0wn f0x was lazy t0day 0f all days', was: %s\n", dbgstrx(strBang));
ok(strBang.GetLength() == 46, "Expected GetLength() to be 46, was: %i\n", strBang.GetLength());
n = strBang.Replace(_X('o'), _X('0'));
ok(n == 0, "Expected n to be 0, was %i\n", n);
ok(strBang == _X("The quick br0wn f0x was lazy t0day 0f all days"),
"Expected str to be 'The quick br0wn f0x was lazy t0day 0f all days', was: %s\n", dbgstrx(strBang));
ok(strBang.GetLength() == 46, "Expected GetLength() to be 46, was: %i\n", strBang.GetLength());
n = strBang.Replace(_X("y "), _X("y, "));
ok(n == 2, "Expected n to be 2, was %i\n", n);
ok(strBang == _X("The quick br0wn f0x was lazy, t0day, 0f all days"),
"Expected str to be 'The quick br0wn f0x was lazy, t0day, 0f all days', was: %s\n", dbgstrx(strBang));
ok(strBang.GetLength() == 48, "Expected GetLength() to be 48, was: %i\n", strBang.GetLength());
n = strBang.Replace(_X(", 0f all days"), _X(""));
ok(n == 1, "Expected n to be 1, was %i\n", n);
ok(strBang == _X("The quick br0wn f0x was lazy, t0day"),
"Expected str to be 'The quick br0wn f0x was lazy, t0day', was: %s\n", dbgstrx(strBang));
ok(strBang.GetLength() == 35, "Expected GetLength() to be 35, was: %i\n", strBang.GetLength());
n = strBang.Replace(_X(" lazy, "), _X(" fast "));
ok(n == 1, "Expected n to be 1, was %i\n", n);
ok(strBang == _X("The quick br0wn f0x was fast t0day"),
"Expected str to be 'The quick br0wn f0x was fast t0day', was: %s\n", dbgstrx(strBang));
ok(strBang.GetLength() == 34, "Expected GetLength() to be 34, was: %i\n", strBang.GetLength());
n = strBang.Replace(_X("The "), _X(""));
ok(n == 1, "Expected n to be 1, was %i\n", n);
ok(strBang == _X("quick br0wn f0x was fast t0day"),
"Expected str to be 'quick br0wn f0x was fast t0day', was: %s\n", dbgstrx(strBang));
ok(strBang.GetLength() == 30, "Expected GetLength() to be 30, was: %i\n", strBang.GetLength());
n = strBang.Replace(_X(" t0day"), _X(""));
ok(n == 1, "Expected n to be 1, was %i\n", n);
ok(strBang == _X("quick br0wn f0x was fast"),
"Expected str to be 'quick br0wn f0x was fast', was: %s\n", dbgstrx(strBang));
ok(strBang.GetLength() == 24, "Expected GetLength() to be 24, was: %i\n", strBang.GetLength());
n = strBang.Replace(_X("quick"), _X("The fast, quick"));
ok(n == 1, "Expected n to be 1, was %i\n", n);
ok(strBang == _X("The fast, quick br0wn f0x was fast"),
"Expected str to be 'The fast, quick br0wn f0x was fast', was: %s\n", dbgstrx(strBang));
ok(strBang.GetLength() == 34, "Expected GetLength() to be 34, was: %i\n", strBang.GetLength());
}
TEST_NAMEX(trim)
{
CStringX str;
str = _X(" \t\r\n******Trim some text!?!?!?!?!\n\r\t ");
str.TrimLeft();
ok(str == _X("******Trim some text!?!?!?!?!\n\r\t "), "Expected str to be '******Trim some text!?!?!?!?!\n\r\t ', was: %s\n", dbgstrx(str));
ok(str.GetLength() == 33, "Expected GetLength() to be 33, was: %i\n", str.GetLength());
str.TrimRight();
ok(str == _X("******Trim some text!?!?!?!?!"), "Expected str to be '******Trim some text!?!?!?!?!', was: %s\n", dbgstrx(str));
ok(str.GetLength() == 29, "Expected GetLength() to be 29, was: %i\n", str.GetLength());
CStringX str2 = str.Trim(_X("?!*"));
ok(str2 == _X("Trim some text"), "Expected str to be 'Trim some text', was: %s\n", dbgstrx(str2));
ok(str2.GetLength() == 14, "Expected GetLength() to be 14, was: %i\n", str2.GetLength());
str = _X("\t\t ****Trim some text!");
str2 = str.TrimLeft(_X("\t *"));
ok(str2 == _X("Trim some text!"), "Expected str to be 'Trim some text!', was: %s\n", dbgstrx(str2));
ok(str2.GetLength() == 15, "Expected GetLength() to be 15, was: %i\n", str2.GetLength());
str = _X("Trim some text!?!?!?!?!");
str2 = str.TrimRight(_X("?!"));
ok(str2 == _X("Trim some text"), "Expected str to be 'Trim some text', was: %s\n", dbgstrx(str2));
ok(str2.GetLength() == 14, "Expected GetLength() to be 14, was: %i\n", str2.GetLength());
str = _X("\t\t\t\t\t");
str2 = str.TrimLeft();
ok(str2 == _X(""), "Expected str2 to be '', was: %s\n", dbgstrx(str2));
ok(str2.GetLength() == 0, "Expected GetLength() to be 0, was: %i\n", str2.GetLength());
str = _X("\t\t\t\t\t");
str2 = str.TrimRight();
ok(str2 == _X(""), "Expected str2 to be '', was: %s\n", dbgstrx(str2));
ok(str2.GetLength() == 0, "Expected GetLength() to be 0, was: %i\n", str2.GetLength());
str = _X("\t\t\t\t\t");
str2 = str.Trim();
ok(str2 == _X(""), "Expected str2 to be '', was: %s\n", dbgstrx(str2));
ok(str2.GetLength() == 0, "Expected GetLength() to be 0, was: %i\n", str2.GetLength());
}

View file

@ -3,10 +3,12 @@
extern void func_CComBSTR(void);
extern void func_CComHeapPtr(void);
extern void func_CString(void);
const struct test winetest_testlist[] =
{
{ "CComBSTR", func_CComBSTR },
{ "CComHeapPtr", func_CComHeapPtr },
{ "CString", func_CString },
{ 0, 0 }
};