mshtml: Added put_backgroundImage implementation.
[wine] / dlls / riched32 / tests / editor.c
1 /*
2 * Unit test suite for rich edit control 1.0
3 *
4 * Copyright 2006 Google (Thomas Kho)
5 * Copyright 2007 Matt Finnicum
6 * Copyright 2007 Dmitry Timoshkov
7 * Copyright 2007 Alex VillacĂ­s Lasso
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24 #include <stdarg.h>
25 #include <assert.h>
26 #include <windef.h>
27 #include <winbase.h>
28 #include <wingdi.h>
29 #include <winuser.h>
30 #include <winnls.h>
31 #include <ole2.h>
32 #include <richedit.h>
33 #include <time.h>
34 #include <wine/test.h>
35
36 static HMODULE hmoduleRichEdit;
37
38 static HWND new_window(LPCTSTR lpClassName, DWORD dwStyle, HWND parent) {
39   HWND hwnd;
40   hwnd = CreateWindow(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL
41                       |WS_VISIBLE, 0, 0, 200, 60, parent, NULL,
42                       hmoduleRichEdit, NULL);
43   ok(hwnd != NULL, "class: %s, error: %d\n", lpClassName, (int) GetLastError());
44   return hwnd;
45 }
46
47 static HWND new_richedit(HWND parent) {
48   return new_window(RICHEDIT_CLASS10A, ES_MULTILINE, parent);
49 }
50
51 static void test_WM_SETTEXT()
52 {
53   HWND hwndRichEdit = new_richedit(NULL);
54   const char * TestItem1 = "TestSomeText";
55   const char * TestItem2 = "TestSomeText\r";
56   const char * TestItem3 = "TestSomeText\rSomeMoreText\r";
57   const char * TestItem4 = "TestSomeText\n\nTestSomeText";
58   const char * TestItem5 = "TestSomeText\r\r\nTestSomeText";
59   const char * TestItem6 = "TestSomeText\r\r\n\rTestSomeText";
60   const char * TestItem7 = "TestSomeText\r\n\r\r\n\rTestSomeText";
61   const char * TestItem8 = "TestSomeText\r\n";
62   const char * TestItem9 = "TestSomeText\r\nSomeMoreText\r\n";
63   const char * TestItem10 = "TestSomeText\r\n\r\nTestSomeText";
64   const char * TestItem11 = "TestSomeText TestSomeText";
65   const char * TestItem12 = "TestSomeText \r\nTestSomeText";
66   const char * TestItem13 = "TestSomeText\r\n \r\nTestSomeText";
67   const char * TestItem14 = "TestSomeText\n";
68   const char * TestItem15 = "TestSomeText\r\r\r";
69   const char * TestItem16 = "TestSomeText\r\r\rSomeMoreText";
70   char buf[1024] = {0};
71   LRESULT result;
72
73   /* This test attempts to show that WM_SETTEXT on a riched32 control does not
74      attempt to modify the text that is pasted into the control, and should
75      return it as is. In particular, \r\r\n is NOT converted, unlike riched20.
76      Currently, builtin riched32 mangles solitary \r or \n when not part of
77      a \r\n pair.
78
79      For riched32, the rules for breaking lines seem to be the following:
80      - \r\n is one line break. This is the normal case.
81      - \r{0,N}\n is one line break. In particular, \n by itself is a line break.
82      - \n{1,N} are that many line breaks.
83      - \r with text or other characters (except \n) past it, is a line break. That
84        is, a run of \r{N} without a terminating \n is considered N line breaks
85      - \r at the end of the text is NOT a line break. This differs from riched20,
86        where \r at the end of the text is a proper line break. This causes
87        TestItem2 to fail its test.
88    */
89
90 #define TEST_SETTEXT(a, b, nlines, is_todo, is_todo2) \
91   result = SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) a); \
92   ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
93   result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buf); \
94   ok (result == lstrlen(buf), \
95         "WM_GETTEXT returned %ld instead of expected %u\n", \
96         result, lstrlen(buf)); \
97   result = strcmp(b, buf); \
98   if (is_todo) todo_wine { \
99   ok(result == 0, \
100         "WM_SETTEXT round trip: strcmp = %ld\n", result); \
101   } else { \
102   ok(result == 0, \
103         "WM_SETTEXT round trip: strcmp = %ld\n", result); \
104   } \
105   result = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); \
106   if (is_todo2) todo_wine { \
107   ok(result == nlines, "EM_GETLINECOUNT returned %ld, expected %d\n", result, nlines); \
108   } else { \
109   ok(result == nlines, "EM_GETLINECOUNT returned %ld, expected %d\n", result, nlines); \
110   }
111
112   TEST_SETTEXT(TestItem1, TestItem1, 1, 0, 0)
113   TEST_SETTEXT(TestItem2, TestItem2, 1, 1, 1)
114   TEST_SETTEXT(TestItem3, TestItem3, 2, 1, 1)
115   TEST_SETTEXT(TestItem4, TestItem4, 3, 1, 0)
116   TEST_SETTEXT(TestItem5, TestItem5, 2, 1, 0)
117   TEST_SETTEXT(TestItem6, TestItem6, 3, 1, 0)
118   TEST_SETTEXT(TestItem7, TestItem7, 4, 1, 0)
119   TEST_SETTEXT(TestItem8, TestItem8, 2, 0, 0)
120   TEST_SETTEXT(TestItem9, TestItem9, 3, 0, 0)
121   TEST_SETTEXT(TestItem10, TestItem10, 3, 0, 0)
122   TEST_SETTEXT(TestItem11, TestItem11, 1, 0, 0)
123   TEST_SETTEXT(TestItem12, TestItem12, 2, 0, 0)
124   TEST_SETTEXT(TestItem13, TestItem13, 3, 0, 0)
125   TEST_SETTEXT(TestItem14, TestItem14, 2, 1, 0)
126   TEST_SETTEXT(TestItem15, TestItem15, 3, 1, 1)
127   TEST_SETTEXT(TestItem16, TestItem16, 4, 1, 0)
128
129 #undef TEST_SETTEXT
130   DestroyWindow(hwndRichEdit);
131 }
132
133 static void test_WM_GETTEXTLENGTH(void)
134 {
135     HWND hwndRichEdit = new_richedit(NULL);
136     static const char text3[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee";
137     static const char text4[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee\r\n";
138     int result;
139
140     /* Test for WM_GETTEXTLENGTH */
141     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text3);
142     result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
143     ok(result == lstrlen(text3),
144         "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
145         result, lstrlen(text3));
146
147     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text4);
148     result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
149     ok(result == lstrlen(text4),
150         "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
151         result, lstrlen(text4));
152
153     DestroyWindow(hwndRichEdit);
154 }
155
156 static DWORD CALLBACK test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie,
157                                          LPBYTE pbBuff,
158                                          LONG cb,
159                                          LONG *pcb)
160 {
161   const char** str = (const char**)dwCookie;
162   int size = strlen(*str);
163   *pcb = cb;
164   if (*pcb > size) {
165     *pcb = size;
166   }
167   if (*pcb > 0) {
168     memcpy(pbBuff, *str, *pcb);
169     *str += *pcb;
170   }
171   return 0;
172 }
173
174
175 static void test_EM_STREAMIN(void)
176 {
177   HWND hwndRichEdit = new_richedit(NULL);
178   LRESULT result;
179   EDITSTREAM es;
180   char buffer[1024] = {0};
181
182   const char * streamText0 = "{\\rtf1 TestSomeText}";
183   const char * streamText0a = "{\\rtf1 TestSomeText\\par}";
184   const char * streamText0b = "{\\rtf1 TestSomeText\\par\\par}";
185
186   const char * streamText1 =
187   "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n" \
188   "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n" \
189   "}\r\n";
190
191   /* This should be accepted in richedit 1.0 emulation. See bug #8326 */
192   const char * streamText2 =
193     "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;" \
194     "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255" \
195     "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 " \
196     "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 " \
197     "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 " \
198     "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 " \
199     "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }";
200
201   const char * streamText3 = "RichEdit1";
202
203   /* Minimal test without \par at the end */
204   es.dwCookie = (DWORD_PTR)&streamText0;
205   es.dwError = 0;
206   es.pfnCallback = test_EM_STREAMIN_esCallback;
207   SendMessage(hwndRichEdit, EM_STREAMIN,
208               (WPARAM)(SF_RTF), (LPARAM)&es);
209
210   result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
211   ok (result  == 12,
212       "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result);
213   result = strcmp (buffer,"TestSomeText");
214   ok (result  == 0,
215       "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer);
216
217   /* Native richedit 2.0 ignores last \par */
218   es.dwCookie = (DWORD_PTR)&streamText0a;
219   es.dwError = 0;
220   es.pfnCallback = test_EM_STREAMIN_esCallback;
221   SendMessage(hwndRichEdit, EM_STREAMIN,
222               (WPARAM)(SF_RTF), (LPARAM)&es);
223
224   result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
225   ok (result  == 12,
226       "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result);
227   result = strcmp (buffer,"TestSomeText");
228   ok (result  == 0,
229       "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer);
230
231   /* Native richedit 2.0 ignores last \par, next-to-last \par appears */
232   es.dwCookie = (DWORD_PTR)&streamText0b;
233   es.dwError = 0;
234   es.pfnCallback = test_EM_STREAMIN_esCallback;
235   SendMessage(hwndRichEdit, EM_STREAMIN,
236               (WPARAM)(SF_RTF), (LPARAM)&es);
237
238   result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
239   ok (result  == 14,
240       "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result);
241   result = strcmp (buffer,"TestSomeText\r\n");
242   ok (result  == 0,
243       "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer);
244
245   es.dwCookie = (DWORD_PTR)&streamText1;
246   es.dwError = 0;
247   es.pfnCallback = test_EM_STREAMIN_esCallback;
248   SendMessage(hwndRichEdit, EM_STREAMIN,
249               (WPARAM)(SF_RTF), (LPARAM)&es);
250
251   result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
252   ok (result  == 12,
253       "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result);
254   result = strcmp (buffer,"TestSomeText");
255   ok (result  == 0,
256       "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
257
258
259   es.dwCookie = (DWORD_PTR)&streamText2;
260   SendMessage(hwndRichEdit, EM_STREAMIN,
261               (WPARAM)(SF_RTF), (LPARAM)&es);
262
263   result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
264   todo_wine {
265   ok (result  == 9,
266       "EM_STREAMIN: Test 2 returned %ld, expected 9\n", result);
267   }
268   result = strcmp (buffer,"RichEdit1");
269   todo_wine {
270   ok (result  == 0,
271       "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
272   }
273
274   es.dwCookie = (DWORD_PTR)&streamText3;
275   SendMessage(hwndRichEdit, EM_STREAMIN,
276               (WPARAM)(SF_RTF), (LPARAM)&es);
277
278   result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
279   ok (result  == 0,
280       "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result);
281   ok (strlen(buffer)  == 0,
282       "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer);
283
284   DestroyWindow(hwndRichEdit);
285 }
286
287
288 START_TEST( editor )
289 {
290   MSG msg;
291   time_t end;
292
293   /* Must explicitly LoadLibrary(). The test has no references to functions in
294    * RICHED32.DLL, so the linker doesn't actually link to it. */
295   hmoduleRichEdit = LoadLibrary("RICHED32.DLL");
296   ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
297
298   test_WM_SETTEXT();
299   test_WM_GETTEXTLENGTH();
300   test_EM_STREAMIN();
301
302   /* Set the environment variable WINETEST_RICHED32 to keep windows
303    * responsive and open for 30 seconds. This is useful for debugging.
304    *
305    * The message pump uses PeekMessage() to empty the queue and then sleeps for
306    * 50ms before retrying the queue. */
307   end = time(NULL) + 30;
308   if (getenv( "WINETEST_RICHED32" )) {
309     while (time(NULL) < end) {
310       if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
311         TranslateMessage(&msg);
312         DispatchMessage(&msg);
313       } else {
314         Sleep(50);
315       }
316     }
317   }
318
319   OleFlushClipboard();
320   ok(FreeLibrary(hmoduleRichEdit) != 0, "error: %d\n", (int) GetLastError());
321 }