1 /*
2  * PROJECT:     ReactOS api tests
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Test for CString
5  * COPYRIGHT:   Copyright 2016-2017 Mark Jansen (mark.jansen@reactos.org)
6  *              Copyright 2017 Katayama Hirofumi MZ
7  */
8 
9 #include <atlstr.h>
10 #include "resource.h"
11 
12 #ifdef __REACTOS__
13     #include <apitest.h>
14 #else
15     #include <stdlib.h>
16     #include <stdio.h>
17     #include <stdarg.h>
18     #include <windows.h>
19     int g_tests_executed = 0;
20     int g_tests_failed = 0;
21     int g_tests_skipped = 0;
22     const char *g_file = NULL;
23     int g_line = 0;
24     void set_location(const char *file, int line)
25     {
26         g_file = file;
27         g_line = line;
28     }
29     void ok_func(int value, const char *fmt, ...)
30     {
31         va_list va;
32         va_start(va, fmt);
33         if (!value)
34         {
35             printf("%s (%d): ", g_file, g_line);
36             vprintf(fmt, va);
37             g_tests_failed++;
38         }
39         g_tests_executed++;
40         va_end(va);
41     }
42     void skip_func(const char *fmt, ...)
43     {
44         va_list va;
45         va_start(va, fmt);
46         printf("%s (%d): test skipped: ", g_file, g_line);
47         vprintf(fmt, va);
48         g_tests_skipped++;
49         va_end(va);
50     }
51     #undef ok
52     #define ok(value, ...) do { \
53         set_location(__FILE__, __LINE__); \
54         ok_func(value, __VA_ARGS__); \
55     } while (0)
56     #define ok_(x1,x2) set_location(x1,x2); ok_func
57     #define skip(...) do { \
58         set_location(__FILE__, __LINE__); \
59         skip_func(__VA_ARGS__); \
60     } while (0)
61     #define START_TEST(x)   int main(void)
62     char *wine_dbgstr_w(const wchar_t *wstr)
63     {
64         static char buf[512];
65         WideCharToMultiByte(CP_ACP, 0, wstr, -1, buf, _countof(buf), NULL, NULL);
66         return buf;
67     }
68 #endif
69 
70 struct traits_test
71 {
72     const char* strA;
73     const wchar_t* strW;
74     int str_len;
75     int exp_1, exp_2, exp_3, exp_4;
76 };
77 
78 traits_test g_Tests[] = {
79     // inputs                   outputs
80     { NULL, NULL, 0,            0,  0, -1,  0 },
81     { NULL, NULL, -1,           0, -1, -1,  0 },
82     { NULL, NULL, 1,            0,  1, -1,  0 },
83 
84     { "", L"", 0,               0,  0,  0,  0 },
85     { "", L"", -1,              0, -1,  0,  1 },
86     { "", L"", 1,               0,  1,  0,  1 },
87 
88     { "AAABBB", L"AAABBB", 0,   6,  0,  6,  0 },
89     { "AAABBB", L"AAABBB", 3,   6,  3,  6,  3 },
90     { "AAABBB", L"AAABBB", -1,  6, -1,  6,  7 },
91 };
92 
93 static void test_basetypes()
94 {
95     int len;
96     char bufA[10];
97     wchar_t bufW[10];
98 
99     for (size_t n = 0; n < _countof(g_Tests); ++n)
100     {
101         len = ChTraitsCRT<char>::GetBaseTypeLength(g_Tests[n].strA);
102         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);
103 
104         len = ChTraitsCRT<char>::GetBaseTypeLength(g_Tests[n].strA, g_Tests[n].str_len);
105         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);
106 
107         len = ChTraitsCRT<char>::GetBaseTypeLength(g_Tests[n].strW);
108         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);
109 
110         len = ChTraitsCRT<char>::GetBaseTypeLength(g_Tests[n].strW, g_Tests[n].str_len);
111         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);
112 
113         if (g_Tests[n].strA && g_Tests[n].strW)
114         {
115             memset(bufA, 'x', sizeof(bufA));
116             ChTraitsCRT<char>::ConvertToBaseType(bufA, g_Tests[n].exp_1+1, g_Tests[n].strA);
117             char ch = bufA[g_Tests[n].exp_1];
118             ok(ch == '\0', "Expected %i to be \\0, was: %c (%i) for %u\n", g_Tests[n].exp_1, ch, (int)ch, n);
119             ok(!strcmp(bufA, g_Tests[n].strA), "Expected bufA to be %s, was: %s for %u\n", g_Tests[n].strA, bufA, n);
120             ch = bufA[g_Tests[n].exp_1+1];
121             ok(ch == 'x', "Expected %i to be 'x', was: %c (%i) for %u\n", g_Tests[n].exp_1+1, ch, (int)ch, n);
122         }
123 
124         if (g_Tests[n].strA && g_Tests[n].strW)
125         {
126             memset(bufA, 'x', sizeof(bufA));
127             ChTraitsCRT<char>::ConvertToBaseType(bufA, g_Tests[n].exp_1+1, g_Tests[n].strW);
128             char ch = bufA[g_Tests[n].exp_1];
129             ok(ch == '\0', "Expected %i to be \\0, was: %c (%i) for %u\n", g_Tests[n].exp_1, ch, (int)ch, n);
130             ok(!strcmp(bufA, g_Tests[n].strA), "Expected bufA to be %s, was: %s for %u\n", g_Tests[n].strA, bufA, n);
131             ch = bufA[g_Tests[n].exp_1+1];
132             ok(ch == 'x', "Expected %i to be 'x', was: %c (%i) for %u\n", g_Tests[n].exp_1+1, ch, (int)ch, n);
133         }
134 
135         // wchar_t --> please note, swapped the expectations from 2 and 4 !
136         len = ChTraitsCRT<wchar_t>::GetBaseTypeLength(g_Tests[n].strA);
137         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);
138 
139         len = ChTraitsCRT<wchar_t>::GetBaseTypeLength(g_Tests[n].strA, g_Tests[n].str_len);
140         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);
141 
142         len = ChTraitsCRT<wchar_t>::GetBaseTypeLength(g_Tests[n].strW);
143         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);
144 
145         len = ChTraitsCRT<wchar_t>::GetBaseTypeLength(g_Tests[n].strW, g_Tests[n].str_len);
146         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);
147 
148         if (g_Tests[n].strA && g_Tests[n].strW)
149         {
150             memset(bufW, 'x', sizeof(bufW));
151             ChTraitsCRT<wchar_t>::ConvertToBaseType(bufW, g_Tests[n].exp_1+1, g_Tests[n].strA);
152             wchar_t ch = bufW[g_Tests[n].exp_1];
153             ok(ch == L'\0', "Expected %i to be \\0, was: %c (%i) for %u\n", g_Tests[n].exp_1, ch, (int)ch, n);
154             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);
155             ch = bufW[g_Tests[n].exp_1+1];
156             ok(ch == 30840, "Expected %i to be %i for %u\n", g_Tests[n].exp_1+1, (int)ch, n);
157         }
158 
159         if (g_Tests[n].strA && g_Tests[n].strW)
160         {
161             memset(bufW, 'x', sizeof(bufW));
162             ChTraitsCRT<wchar_t>::ConvertToBaseType(bufW, g_Tests[n].exp_1+1, g_Tests[n].strW);
163             wchar_t ch = bufW[g_Tests[n].exp_1];
164             ok(ch == '\0', "Expected %i to be \\0, was: %c (%i) for %u\n", g_Tests[n].exp_1, ch, (int)ch, n);
165             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);
166             ch = bufW[g_Tests[n].exp_1+1];
167             ok(ch == 30840, "Expected %i to be %i for %u\n", g_Tests[n].exp_1+1, (int)ch, n);
168         }
169     }
170 }
171 
172 // Allocation strategy seems to differ a bit between us and MS's atl.
173 // if someone cares enough to find out why, feel free to change the macro below.
174 #ifdef __REACTOS__
175 #define ALLOC_EXPECT(a, b)  b
176 #else
177 #define ALLOC_EXPECT(a, b)  a
178 #endif
179 
180 
181 #undef ok
182 #undef _T
183 
184 #define TEST_NAMEX(name)        void test_##name##W()
185 #define CStringX                CStringW
186 #define _X(x)                   L ## x
187 #define XCHAR                   WCHAR
188 #define YCHAR                   CHAR
189 #define dbgstrx(x)              wine_dbgstr_w(x)
190 #define ok                      ok_("CStringW:\n" __FILE__, __LINE__)
191 #define GetWindowsDirectoryX    GetWindowsDirectoryW
192 #define MAKEINTRESOURCEX(x)     MAKEINTRESOURCEW(x)
193 #define MAKEINTRESOURCEY(x)     MAKEINTRESOURCEA(x)
194 #include "CString.inl"
195 
196 
197 #undef CStringX
198 #undef TEST_NAMEX
199 #undef _X
200 #undef XCHAR
201 #undef YCHAR
202 #undef dbgstrx
203 #undef ok
204 #undef GetWindowsDirectoryX
205 #undef MAKEINTRESOURCEX
206 #undef MAKEINTRESOURCEY
207 
208 #define TEST_NAMEX(name)        void test_##name##A()
209 #define CStringX                CStringA
210 #define _X(x)                   x
211 #define XCHAR                   CHAR
212 #define YCHAR                   WCHAR
213 #define dbgstrx(x)              (const char*)x
214 #define ok                      ok_("CStringA:\n" __FILE__, __LINE__)
215 #define GetWindowsDirectoryX    GetWindowsDirectoryA
216 #define MAKEINTRESOURCEX(x)     MAKEINTRESOURCEA(x)
217 #define MAKEINTRESOURCEY(x)     MAKEINTRESOURCEW(x)
218 #include "CString.inl"
219 
220 
221 START_TEST(CString)
222 {
223     test_basetypes();
224 
225     if ((ALLOC_EXPECT(1, 2)) == 2)
226     {
227         skip("Ignoring real GetAllocLength() lenght\n");
228     }
229 
230     test_operators_initW();
231     test_operators_initA();
232 
233     test_compareW();
234     test_compareA();
235 
236     test_findW();
237     test_findA();
238 
239     test_formatW();
240     test_formatA();
241 
242     test_substrW();
243     test_substrA();
244 
245     test_replaceW();
246     test_replaceA();
247 
248     test_trimW();
249     test_trimA();
250 
251     test_envW();
252     test_envA();
253 
254     test_load_strW();
255     test_load_strA();
256 
257     test_bstrW();
258     test_bstrA();
259 
260 #ifndef __REACTOS__
261     printf("CString: %i tests executed (0 marked as todo, %i failures), %i skipped.\n", g_tests_executed, g_tests_failed, g_tests_skipped);
262     return g_tests_failed;
263 #endif
264 }
265