Author: mjansen
Date: Sat Jul 30 19:07:43 2016
New Revision: 72061

URL: http://svn.reactos.org/svn/reactos?rev=72061&view=rev
Log:
[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.

Added:
    trunk/rostests/apitests/atl/CString.cpp   (with props)
    trunk/rostests/apitests/atl/CString.inl   (with props)
Modified:
    trunk/reactos/sdk/lib/atl/atlsimpstr.h
    trunk/reactos/sdk/lib/atl/atlstr.h
    trunk/reactos/sdk/lib/atl/cstringt.h
    trunk/rostests/apitests/atl/CMakeLists.txt
    trunk/rostests/apitests/atl/testlist.c

Modified: trunk/reactos/sdk/lib/atl/atlsimpstr.h
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/sdk/lib/atl/atlsimpstr.h?rev=72061&r1=72060&r2=72061&view=diff
==============================================================================
--- trunk/reactos/sdk/lib/atl/atlsimpstr.h      [iso-8859-1] (original)
+++ trunk/reactos/sdk/lib/atl/atlsimpstr.h      [iso-8859-1] Sat Jul 30 
19:07:43 2016
@@ -200,6 +200,28 @@
         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 @@
         if (pOldData->IsShared())
         {
             Fork(nLength);
-            ATLASSERT(FALSE);
+            //ATLASSERT(FALSE);
         }
         else if (pOldData->nAllocLength < nLength)
         {

Modified: trunk/reactos/sdk/lib/atl/atlstr.h
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/sdk/lib/atl/atlstr.h?rev=72061&r1=72060&r2=72061&view=diff
==============================================================================
--- trunk/reactos/sdk/lib/atl/atlstr.h  [iso-8859-1] (original)
+++ trunk/reactos/sdk/lib/atl/atlstr.h  [iso-8859-1] Sat Jul 30 19:07:43 2016
@@ -124,6 +124,12 @@
 
 
 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;
+
 
 }
 

Modified: trunk/reactos/sdk/lib/atl/cstringt.h
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/sdk/lib/atl/cstringt.h?rev=72061&r1=72060&r2=72061&view=diff
==============================================================================
--- trunk/reactos/sdk/lib/atl/cstringt.h        [iso-8859-1] (original)
+++ trunk/reactos/sdk/lib/atl/cstringt.h        [iso-8859-1] Sat Jul 30 
19:07:43 2016
@@ -28,14 +28,28 @@
 
     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,8 +63,197 @@
 
         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_
@@ -62,6 +265,8 @@
     };
 }
 
+
+// TODO: disable conversion functions when 
_CSTRING_DISABLE_NARROW_WIDE_CONVERSION is defined.
 
 template <typename BaseType, class StringTraits>
 class CStringT :
@@ -90,12 +295,19 @@
 
     static void __cdecl Construct(_In_ CStringT* pString)
     {
-        pString = new CStringT;
+        new(pString) CStringT;
     }
 
     CStringT(_In_ const CStringT& strSrc) :
         CThisSimpleString(strSrc)
     {
+    }
+
+    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) :
@@ -114,6 +326,36 @@
         *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);
@@ -124,6 +366,59 @@
     {
         CThisSimpleString::operator=(pszSrc);
         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)
@@ -151,6 +446,299 @@
 
         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

Modified: trunk/rostests/apitests/atl/CMakeLists.txt
URL: 
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/atl/CMakeLists.txt?rev=72061&r1=72060&r2=72061&view=diff
==============================================================================
--- trunk/rostests/apitests/atl/CMakeLists.txt  [iso-8859-1] (original)
+++ trunk/rostests/apitests/atl/CMakeLists.txt  [iso-8859-1] Sat Jul 30 
19:07:43 2016
@@ -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)
 

Added: trunk/rostests/apitests/atl/CString.cpp
URL: 
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/atl/CString.cpp?rev=72061
==============================================================================
--- trunk/rostests/apitests/atl/CString.cpp     (added)
+++ trunk/rostests/apitests/atl/CString.cpp     [iso-8859-1] Sat Jul 30 
19:07:43 2016
@@ -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();
+}

Propchange: trunk/rostests/apitests/atl/CString.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Added: trunk/rostests/apitests/atl/CString.inl
URL: 
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/atl/CString.inl?rev=72061
==============================================================================
--- trunk/rostests/apitests/atl/CString.inl     (added)
+++ trunk/rostests/apitests/atl/CString.inl     [iso-8859-1] Sat Jul 30 
19:07:43 2016
@@ -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());
+}

Propchange: trunk/rostests/apitests/atl/CString.inl
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: trunk/rostests/apitests/atl/testlist.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/atl/testlist.c?rev=72061&r1=72060&r2=72061&view=diff
==============================================================================
--- trunk/rostests/apitests/atl/testlist.c      [iso-8859-1] (original)
+++ trunk/rostests/apitests/atl/testlist.c      [iso-8859-1] Sat Jul 30 
19:07:43 2016
@@ -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 }
 };


Reply via email to