push 390edd058cbebc9f7cb21f639a52f5acd36a8bf3
[wine/hacks.git] / dlls / riched32 / tests / editor.c
blob5cc269d855def9551796176933b5227c3f03f35c
1 /*
2 * Unit test suite for rich edit control 1.0
4 * Copyright 2006 Google (Thomas Kho)
5 * Copyright 2007 Matt Finnicum
6 * Copyright 2007 Dmitry Timoshkov
7 * Copyright 2007 Alex VillacĂ­s Lasso
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.
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.
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
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>
36 static HMODULE hmoduleRichEdit;
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;
47 static HWND new_richedit(HWND parent) {
48 return new_window(RICHEDIT_CLASS10A, ES_MULTILINE, parent);
51 static void test_WM_SETTEXT(void)
53 static const struct {
54 const char *itemtext;
55 DWORD lines;
56 DWORD lines_broken;
57 } testitems[] = {
58 { "TestSomeText", 1},
59 { "TestSomeText\r", 1},
60 { "TestSomeText\rSomeMoreText\r", 2, 1}, /* NT4 and below */
61 { "TestSomeText\n\nTestSomeText", 3},
62 { "TestSomeText\r\r\nTestSomeText", 2},
63 { "TestSomeText\r\r\n\rTestSomeText", 3, 2}, /* NT4 and below */
64 { "TestSomeText\r\n\r\r\n\rTestSomeText", 4, 3}, /* NT4 and below */
65 { "TestSomeText\r\n" ,2},
66 { "TestSomeText\r\nSomeMoreText\r\n", 3},
67 { "TestSomeText\r\n\r\nTestSomeText", 3},
68 { "TestSomeText TestSomeText" ,1},
69 { "TestSomeText \r\nTestSomeText", 2},
70 { "TestSomeText\r\n \r\nTestSomeText", 3},
71 { "TestSomeText\n", 2},
72 { "TestSomeText\r\r\r", 3, 1}, /* NT4 and below */
73 { "TestSomeText\r\r\rSomeMoreText", 4, 2} /* NT4 and below */
75 HWND hwndRichEdit = new_richedit(NULL);
76 int i;
78 /* This test attempts to show that WM_SETTEXT on a riched32 control does not
79 * attempt to modify the text that is pasted into the control, and should
80 * return it as is. In particular, \r\r\n is NOT converted, unlike riched20.
82 * For riched32, the rules for breaking lines seem to be the following:
83 * - \r\n is one line break. This is the normal case.
84 * - \r{0,2}\n is one line break. In particular, \n by itself is a line break.
85 * - \r{0,N-1}\r\r\n is N line breaks.
86 * - \n{1,N} are that many line breaks.
87 * - \r with text or other characters (except \n) past it, is a line break. That
88 * is, a run of \r{N} without a terminating \n is considered N line breaks
89 * - \r at the end of the text is NOT a line break. This differs from riched20,
90 * where \r at the end of the text is a proper line break.
93 for (i = 0; i < sizeof(testitems)/sizeof(testitems[0]); i++) {
95 char buf[1024] = {0};
96 LRESULT result;
98 result = SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) testitems[i].itemtext);
99 ok (result == 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i, result);
100 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buf);
101 ok (result == lstrlen(buf),
102 "[%d] WM_GETTEXT returned %ld instead of expected %u\n",
103 i, result, lstrlen(buf));
104 result = strcmp(testitems[i].itemtext, buf);
105 ok (result == 0,
106 "[%d] WM_SETTEXT round trip: strcmp = %ld\n", i, result);
107 result = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
108 ok (result == testitems[i].lines ||
109 broken(testitems[i].lines_broken && result == testitems[i].lines_broken),
110 "[%d] EM_GETLINECOUNT returned %ld, expected %d\n", i, result, testitems[i].lines);
113 DestroyWindow(hwndRichEdit);
116 static void test_WM_GETTEXTLENGTH(void)
118 HWND hwndRichEdit = new_richedit(NULL);
119 static const char text3[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee";
120 static const char text4[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee\r\n";
121 int result;
123 /* Test for WM_GETTEXTLENGTH */
124 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text3);
125 result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
126 ok(result == lstrlen(text3),
127 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
128 result, lstrlen(text3));
130 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text4);
131 result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
132 ok(result == lstrlen(text4),
133 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
134 result, lstrlen(text4));
136 DestroyWindow(hwndRichEdit);
139 static DWORD CALLBACK test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie,
140 LPBYTE pbBuff,
141 LONG cb,
142 LONG *pcb)
144 const char** str = (const char**)dwCookie;
145 int size = strlen(*str);
146 *pcb = cb;
147 if (*pcb > size) {
148 *pcb = size;
150 if (*pcb > 0) {
151 memcpy(pbBuff, *str, *pcb);
152 *str += *pcb;
154 return 0;
158 static void test_EM_STREAMIN(void)
160 HWND hwndRichEdit = new_richedit(NULL);
161 LRESULT result;
162 EDITSTREAM es;
163 char buffer[1024] = {0};
165 const char * streamText0 = "{\\rtf1 TestSomeText}";
166 const char * streamText0a = "{\\rtf1 TestSomeText\\par}";
167 const char * streamText0b = "{\\rtf1 TestSomeText\\par\\par}";
169 const char * streamText1 =
170 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
171 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
172 "}\r\n";
174 /* This should be accepted in richedit 1.0 emulation. See bug #8326 */
175 const char * streamText2 =
176 "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;"
177 "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255"
178 "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 "
179 "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 "
180 "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 "
181 "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 "
182 "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }";
184 const char * streamText3 = "RichEdit1";
186 /* Minimal test without \par at the end */
187 es.dwCookie = (DWORD_PTR)&streamText0;
188 es.dwError = 0;
189 es.pfnCallback = test_EM_STREAMIN_esCallback;
190 SendMessage(hwndRichEdit, EM_STREAMIN,
191 (WPARAM)(SF_RTF), (LPARAM)&es);
193 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
194 ok (result == 12,
195 "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result);
196 result = strcmp (buffer,"TestSomeText");
197 ok (result == 0,
198 "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer);
199 ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
201 /* Native richedit 2.0 ignores last \par */
202 es.dwCookie = (DWORD_PTR)&streamText0a;
203 es.dwError = 0;
204 es.pfnCallback = test_EM_STREAMIN_esCallback;
205 SendMessage(hwndRichEdit, EM_STREAMIN,
206 (WPARAM)(SF_RTF), (LPARAM)&es);
208 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
209 ok (result == 12,
210 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result);
211 result = strcmp (buffer,"TestSomeText");
212 ok (result == 0,
213 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer);
214 ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
216 /* Native richedit 2.0 ignores last \par, next-to-last \par appears */
217 es.dwCookie = (DWORD_PTR)&streamText0b;
218 es.dwError = 0;
219 es.pfnCallback = test_EM_STREAMIN_esCallback;
220 SendMessage(hwndRichEdit, EM_STREAMIN,
221 (WPARAM)(SF_RTF), (LPARAM)&es);
223 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
224 ok (result == 14,
225 "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result);
226 result = strcmp (buffer,"TestSomeText\r\n");
227 ok (result == 0,
228 "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer);
229 ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
231 es.dwCookie = (DWORD_PTR)&streamText1;
232 es.dwError = 0;
233 es.pfnCallback = test_EM_STREAMIN_esCallback;
234 SendMessage(hwndRichEdit, EM_STREAMIN,
235 (WPARAM)(SF_RTF), (LPARAM)&es);
237 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
238 ok (result == 12,
239 "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result);
240 result = strcmp (buffer,"TestSomeText");
241 ok (result == 0,
242 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
243 ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
246 es.dwCookie = (DWORD_PTR)&streamText2;
247 es.dwError = 0;
248 SendMessage(hwndRichEdit, EM_STREAMIN,
249 (WPARAM)(SF_RTF), (LPARAM)&es);
251 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
252 todo_wine {
253 ok (result == 9,
254 "EM_STREAMIN: Test 2 returned %ld, expected 9\n", result);
256 result = strcmp (buffer,"RichEdit1");
257 todo_wine {
258 ok (result == 0,
259 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
261 ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
263 es.dwCookie = (DWORD_PTR)&streamText3;
264 es.dwError = 0;
265 SendMessage(hwndRichEdit, EM_STREAMIN,
266 (WPARAM)(SF_RTF), (LPARAM)&es);
268 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
269 ok (result == 0,
270 "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result);
271 ok (strlen(buffer) == 0,
272 "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer);
273 ok(es.dwError == -16, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, -16);
275 DestroyWindow(hwndRichEdit);
278 static DWORD CALLBACK test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie,
279 LPBYTE pbBuff,
280 LONG cb,
281 LONG *pcb)
283 char** str = (char**)dwCookie;
284 *pcb = cb;
285 if (*pcb > 0) {
286 memcpy(*str, pbBuff, *pcb);
287 *str += *pcb;
289 return 0;
292 static void test_EM_STREAMOUT(void)
294 HWND hwndRichEdit = new_richedit(NULL);
295 int r;
296 EDITSTREAM es;
297 char buf[1024] = {0};
298 char * p;
300 const char * TestItem1 = "TestSomeText";
301 const char * TestItem2 = "TestSomeText\r";
302 const char * TestItem3 = "TestSomeText\r\n";
304 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem1);
305 p = buf;
306 es.dwCookie = (DWORD_PTR)&p;
307 es.dwError = 0;
308 es.pfnCallback = test_WM_SETTEXT_esCallback;
309 memset(buf, 0, sizeof(buf));
310 SendMessage(hwndRichEdit, EM_STREAMOUT,
311 (WPARAM)(SF_TEXT), (LPARAM)&es);
312 r = strlen(buf);
313 ok(r == 12, "streamed text length is %d, expecting 12\n", r);
314 ok(strcmp(buf, TestItem1) == 0,
315 "streamed text different, got %s\n", buf);
317 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem2);
318 p = buf;
319 es.dwCookie = (DWORD_PTR)&p;
320 es.dwError = 0;
321 es.pfnCallback = test_WM_SETTEXT_esCallback;
322 memset(buf, 0, sizeof(buf));
323 SendMessage(hwndRichEdit, EM_STREAMOUT,
324 (WPARAM)(SF_TEXT), (LPARAM)&es);
325 r = strlen(buf);
327 ok(r == 13, "streamed text length is %d, expecting 13\n", r);
328 ok(strcmp(buf, TestItem2) == 0,
329 "streamed text different, got %s\n", buf);
331 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem3);
332 p = buf;
333 es.dwCookie = (DWORD_PTR)&p;
334 es.dwError = 0;
335 es.pfnCallback = test_WM_SETTEXT_esCallback;
336 memset(buf, 0, sizeof(buf));
337 SendMessage(hwndRichEdit, EM_STREAMOUT,
338 (WPARAM)(SF_TEXT), (LPARAM)&es);
339 r = strlen(buf);
340 ok(r == 14, "streamed text length is %d, expecting 14\n", r);
341 ok(strcmp(buf, TestItem3) == 0,
342 "streamed text different, got %s\n", buf);
344 DestroyWindow(hwndRichEdit);
347 static const struct getline_s {
348 int line;
349 size_t buffer_len;
350 const char *text;
351 const char *broken_text;
352 } gl[] = {
353 {0, 10, "foo bar\r\n", "foo bar\r\n"},
354 {1, 10, "\r", "\r\r\r\n"},
355 {2, 10, "\r\r\n", "bar\n"},
356 {3, 10, "bar\n", "\r\n"},
357 {4, 10, "\r\n"},
359 /* Buffer smaller than line length */
360 {0, 2, "foo bar\r"},
361 {0, 1, "foo bar\r"},
362 {0, 0, "foo bar\r"}
365 static void test_EM_GETLINE(void)
367 int i;
368 HWND hwndRichEdit = new_richedit(NULL);
369 static const int nBuf = 1024;
370 char dest[1024], origdest[1024];
371 LRESULT linecount;
372 const char text[] = "foo bar\r\n"
373 "\r"
374 "\r\r\n"
375 "bar\n";
376 BOOL broken_os = FALSE;
378 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
379 linecount = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
380 if (linecount == 4)
382 broken_os = TRUE;
383 win_skip("Win9x, WinME and NT4 handle '\\r only' differently\n");
386 memset(origdest, 0xBB, nBuf);
387 for (i = 0; i < sizeof(gl)/sizeof(struct getline_s); i++)
389 int nCopied, expected_nCopied, expected_bytes_written;
390 char gl_text[1024];
392 if (gl[i].line >= linecount)
393 continue; /* Win9x, WinME and NT4 */
395 if (broken_os && gl[i].broken_text)
396 /* Win9x, WinME and NT4 */
397 strcpy(gl_text, gl[i].broken_text);
398 else
399 strcpy(gl_text, gl[i].text);
401 expected_nCopied = min(gl[i].buffer_len, strlen(gl_text));
402 /* Cater for the fact that Win9x, WinME and NT4 don't append the '\0' */
403 expected_bytes_written = min(gl[i].buffer_len, strlen(gl_text) + (broken_os ? 0 : 1));
405 memset(dest, 0xBB, nBuf);
406 *(WORD *) dest = gl[i].buffer_len;
408 /* EM_GETLINE appends a "\r\0" to the end of the line
409 * nCopied counts up to and including the '\r' */
410 nCopied = SendMessage(hwndRichEdit, EM_GETLINE, gl[i].line, (LPARAM) dest);
411 ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied,
412 expected_nCopied);
413 /* two special cases since a parameter is passed via dest */
414 if (gl[i].buffer_len == 0)
415 ok(!dest[0] && !dest[1] && !strncmp(dest+2, origdest+2, nBuf-2),
416 "buffer_len=0\n");
417 else if (gl[i].buffer_len == 1)
418 ok(dest[0] == gl_text[0] && !dest[1] &&
419 !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n");
420 else
422 ok(!strncmp(dest, gl_text, expected_bytes_written),
423 "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
424 ok(!strncmp(dest + expected_bytes_written, origdest
425 + expected_bytes_written, nBuf - expected_bytes_written),
426 "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
430 DestroyWindow(hwndRichEdit);
433 static void test_EM_LINELENGTH(void)
435 HWND hwndRichEdit = new_richedit(NULL);
436 const char * text =
437 "richedit1\r"
438 "richedit1\n"
439 "richedit1\r\n"
440 "short\r"
441 "richedit1\r"
442 "\r"
443 "\r"
444 "\r\r\n";
445 int offset_test[16][2] = {
446 {0, 9}, /* Line 1: |richedit1\r */
447 {5, 9}, /* Line 1: riche|dit1\r */
448 {10, 9}, /* Line 2: |richedit1\n */
449 {15, 9}, /* Line 2: riche|dit1\n */
450 {20, 9}, /* Line 3: |richedit1\r\n */
451 {25, 9}, /* Line 3: riche|dit1\r\n */
452 {30, 9}, /* Line 3: richedit1\r|\n */
453 {31, 5}, /* Line 4: |short\r */
454 {42, 9}, /* Line 5: riche|dit1\r */
455 {46, 9}, /* Line 5: richedit1|\r */
456 {47, 0}, /* Line 6: |\r */
457 {48, 0}, /* Line 7: |\r */
458 {49, 0}, /* Line 8: |\r\r\n */
459 {50, 0}, /* Line 8: \r|\r\n */
460 {51, 0}, /* Line 8: \r\r|\n */
461 {52, 0}, /* Line 9: \r\r\n| */
463 int i;
464 LRESULT result;
466 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
468 result = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
469 if (result == 4) {
470 win_skip("Win9x, WinME and NT4 don't handle '\\r only' correctly\n");
471 return;
473 ok(result == 9, "Incorrect line count of %ld\n", result);
475 for (i = 0; i < sizeof(offset_test)/sizeof(offset_test[0]); i++) {
476 result = SendMessage(hwndRichEdit, EM_LINELENGTH, offset_test[i][0], 0);
477 ok(result == offset_test[i][1], "Length of line at offset %d is %ld, expected %d\n",
478 offset_test[i][0], result, offset_test[i][1]);
481 DestroyWindow(hwndRichEdit);
484 static void test_EM_GETTEXTRANGE(void)
486 HWND hwndRichEdit = new_richedit(NULL);
487 const char * text1 = "foo bar\r\nfoo bar";
488 const char * text3 = "foo bar\rfoo bar";
489 const char * expect1 = "bar\r\nfoo";
490 const char * expect2 = "\nfoo";
491 const char * expect3 = "bar\rfoo";
492 char buffer[1024] = {0};
493 LRESULT result;
494 TEXTRANGEA textRange;
496 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
498 textRange.lpstrText = buffer;
499 textRange.chrg.cpMin = 4;
500 textRange.chrg.cpMax = 12;
501 result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
502 ok(result == 8, "EM_GETTEXTRANGE returned %ld\n", result);
503 ok(!strcmp(expect1, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
505 textRange.lpstrText = buffer;
506 textRange.chrg.cpMin = 8;
507 textRange.chrg.cpMax = 12;
508 result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
509 ok(result == 4, "EM_GETTEXTRANGE returned %ld\n", result);
510 ok(!strcmp(expect2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
512 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3);
514 textRange.lpstrText = buffer;
515 textRange.chrg.cpMin = 4;
516 textRange.chrg.cpMax = 11;
517 result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
518 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
520 ok(!strcmp(expect3, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
523 DestroyWindow(hwndRichEdit);
526 static void test_EM_GETSELTEXT(void)
528 HWND hwndRichEdit = new_richedit(NULL);
529 const char * text1 = "foo bar\r\nfoo bar";
530 const char * text2 = "foo bar\rfoo bar";
531 const char * expect1 = "bar\r\nfoo";
532 const char * expect2 = "bar\rfoo";
533 char buffer[1024] = {0};
534 LRESULT result;
536 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
538 SendMessage(hwndRichEdit, EM_SETSEL, 4, 12);
539 result = SendMessage(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
540 ok(result == 8, "EM_GETTEXTRANGE returned %ld\n", result);
541 ok(!strcmp(expect1, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
543 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
545 SendMessage(hwndRichEdit, EM_SETSEL, 4, 11);
546 result = SendMessage(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
547 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
549 ok(!strcmp(expect2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
552 DestroyWindow(hwndRichEdit);
555 static const char haystack[] = "WINEWine wineWine wine WineWine";
556 /* ^0 ^10 ^20 ^30 */
558 static const char haystack2[] = "first\r\r\nsecond";
560 struct find_s {
561 int start;
562 int end;
563 const char *needle;
564 int flags;
565 int expected_loc;
569 struct find_s find_tests[] = {
570 /* Find in empty text */
571 {0, -1, "foo", FR_DOWN, -1},
572 {0, -1, "foo", 0, -1},
573 {0, -1, "", FR_DOWN, -1},
574 {20, 5, "foo", FR_DOWN, -1},
575 {5, 20, "foo", FR_DOWN, -1}
578 struct find_s find_tests2[] = {
579 /* No-result find */
580 {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1},
581 {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1},
583 /* Subsequent finds */
584 {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4},
585 {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13},
586 {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23},
587 {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27},
589 /* Find backwards */
590 {19, 20, "Wine", FR_MATCHCASE, -1},
591 {10, 20, "Wine", FR_MATCHCASE, 13},
592 {20, 10, "Wine", FR_MATCHCASE, -1},
594 /* Case-insensitive */
595 {1, 31, "wInE", FR_DOWN, 4},
596 {1, 31, "Wine", FR_DOWN, 4},
598 /* High-to-low ranges */
599 {20, 5, "Wine", FR_DOWN, -1},
600 {2, 1, "Wine", FR_DOWN, -1},
601 {30, 29, "Wine", FR_DOWN, -1},
602 {20, 5, "Wine", 0, /*13*/ -1},
604 /* Find nothing */
605 {5, 10, "", FR_DOWN, -1},
606 {10, 5, "", FR_DOWN, -1},
607 {0, -1, "", FR_DOWN, -1},
608 {10, 5, "", 0, -1},
610 /* Whole-word search */
611 {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18},
612 {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1},
613 {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18},
614 {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0},
615 {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23},
616 {11, -1, "winewine", FR_WHOLEWORD, 23},
617 {31, -1, "winewine", FR_WHOLEWORD, -1},
619 /* Bad ranges */
620 {5, 200, "XXX", FR_DOWN, -1},
621 {-20, 20, "Wine", FR_DOWN, -1},
622 {-20, 20, "Wine", FR_DOWN, -1},
623 {-15, -20, "Wine", FR_DOWN, -1},
624 {1<<12, 1<<13, "Wine", FR_DOWN, -1},
626 /* Check the case noted in bug 4479 where matches at end aren't recognized */
627 {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23},
628 {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27},
629 {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27},
630 {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23},
631 {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23},
633 /* The backwards case of bug 4479; bounds look right
634 * Fails because backward find is wrong */
635 {19, 20, "WINE", FR_MATCHCASE, -1},
636 {0, 20, "WINE", FR_MATCHCASE, 0},
638 {0, -1, "wineWine wine", FR_DOWN, 0},
639 {0, -1, "wineWine wine", 0, 0},
640 {0, -1, "INEW", 0, 1},
641 {0, 31, "INEW", 0, 1},
642 {4, -1, "INEW", 0, 10},
645 struct find_s find_tests3[] = {
646 /* Searching for end of line characters */
647 {0, -1, "t\r\r\ns", FR_DOWN | FR_MATCHCASE, 4},
648 {6, -1, "\r\n", FR_DOWN | FR_MATCHCASE, 6},
649 {7, -1, "\n", FR_DOWN | FR_MATCHCASE, 7},
652 static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id) {
653 int findloc;
654 FINDTEXT ft;
655 memset(&ft, 0, sizeof(ft));
656 ft.chrg.cpMin = f->start;
657 ft.chrg.cpMax = f->end;
658 ft.lpstrText = f->needle;
659 findloc = SendMessage(hwnd, EM_FINDTEXT, f->flags, (LPARAM) &ft);
660 ok(findloc == f->expected_loc,
661 "EM_FINDTEXT(%s,%d) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
662 name, id, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc);
665 static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f,
666 int id) {
667 int findloc;
668 FINDTEXTEX ft;
669 int expected_end_loc;
671 memset(&ft, 0, sizeof(ft));
672 ft.chrg.cpMin = f->start;
673 ft.chrg.cpMax = f->end;
674 ft.lpstrText = f->needle;
675 ft.chrgText.cpMax = 0xdeadbeef;
676 findloc = SendMessage(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM) &ft);
677 ok(findloc == f->expected_loc,
678 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
679 name, id, f->needle, f->start, f->end, f->flags, findloc);
680 ok(ft.chrgText.cpMin == f->expected_loc,
681 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d, expected %d\n",
682 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMin, f->expected_loc);
683 expected_end_loc = ((f->expected_loc == -1) ? -1
684 : f->expected_loc + strlen(f->needle));
685 ok(ft.chrgText.cpMax == expected_end_loc ||
686 broken(ft.chrgText.cpMin == -1 && ft.chrgText.cpMax == 0xdeadbeef), /* Win9x, WinME and NT4 */
687 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
688 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMax, expected_end_loc);
691 static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find,
692 int num_tests)
694 int i;
696 for (i = 0; i < num_tests; i++) {
697 check_EM_FINDTEXT(hwnd, name, &find[i], i);
698 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
702 static void test_EM_FINDTEXT(void)
704 HWND hwndRichEdit = new_richedit(NULL);
706 /* Empty rich edit control */
707 run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests,
708 sizeof(find_tests)/sizeof(struct find_s));
710 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack);
712 /* Haystack text */
713 run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2,
714 sizeof(find_tests2)/sizeof(struct find_s));
716 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack2);
718 /* Haystack text 2 (with EOL characters) */
719 run_tests_EM_FINDTEXT(hwndRichEdit, "3", find_tests3,
720 sizeof(find_tests3)/sizeof(struct find_s));
722 DestroyWindow(hwndRichEdit);
725 static void test_EM_POSFROMCHAR(void)
727 HWND hwndRichEdit = new_richedit(NULL);
728 int i;
729 POINTL pl;
730 LRESULT result;
731 unsigned int height = 0;
732 int xpos = 0;
733 static const char text[] = "aa\n"
734 "this is a long line of text that should be longer than the "
735 "control's width\n"
736 "cc\n"
737 "dd\n"
738 "ee\n"
739 "ff\n"
740 "gg\n"
741 "hh\n";
743 /* Fill the control to lines to ensure that most of them are offscreen */
744 for (i = 0; i < 50; i++)
746 /* Do not modify the string; it is exactly 16 characters long. */
747 SendMessage(hwndRichEdit, EM_SETSEL, 0, 0);
748 SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"0123456789ABCD\r\n");
752 Richedit 1.0 receives a POINTL* on wParam and character offset on lParam, returns void.
753 Richedit 2.0 receives character offset on wParam, ignores lParam, returns MAKELONG(x,y)
754 Richedit 3.0 accepts either of the above API conventions.
757 /* Testing Richedit 1.0 API format */
759 /* Testing start of lines. X-offset should be constant on all cases (native is 1).
760 Since all lines are identical and drawn with the same font,
761 they should have the same height... right?
763 for (i = 0; i < 50; i++)
765 /* All the lines are 16 characters long */
766 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, i * 16);
767 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
768 if (i == 0)
770 ok(pl.y == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl.y);
771 ok(pl.x == 1 ||
772 broken(pl.x == 0), /* Win9x, WinME and NT4 */
773 "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
774 xpos = pl.x;
776 else if (i == 1)
778 ok(pl.y > 0, "EM_POSFROMCHAR reports y=%d, expected > 0\n", pl.y);
779 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
780 height = pl.y;
782 else
784 ok(pl.y == i * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, i * height);
785 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
789 /* Testing position at end of text */
790 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 50 * 16);
791 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
792 ok(pl.y == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, 50 * height);
793 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
795 /* Testing position way past end of text */
796 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 55 * 16);
797 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
798 ok(pl.y == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, 50 * height);
799 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
802 /* Testing that vertical scrolling does, in fact, have an effect on EM_POSFROMCHAR */
803 SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
804 for (i = 0; i < 50; i++)
806 /* All the lines are 16 characters long */
807 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, i * 16);
808 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
809 ok(pl.y == (i - 1) * height,
810 "EM_POSFROMCHAR reports y=%d, expected %d\n",
811 pl.y, (i - 1) * height);
812 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
815 /* Testing position at end of text */
816 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 50 * 16);
817 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
818 ok(pl.y == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, (50 - 1) * height);
819 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
821 /* Testing position way past end of text */
822 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 55 * 16);
823 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
824 ok(pl.y == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, (50 - 1) * height);
825 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
827 /* Testing that horizontal scrolling does, in fact, have an effect on EM_POSFROMCHAR */
828 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
829 SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
831 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 0);
832 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
833 ok(pl.y == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl.y);
834 ok(pl.x == 1 ||
835 broken(pl.x == 0), /* Win9x, WinME and NT4 */
836 "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
837 xpos = pl.x;
839 SendMessage(hwndRichEdit, WM_HSCROLL, SB_LINERIGHT, 0);
840 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 0);
841 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
842 ok(pl.y == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl.y);
843 todo_wine {
844 /* Fails on builtin because horizontal scrollbar is not being shown */
845 ok(pl.x < xpos ||
846 broken(pl.x == xpos), /* Win9x, WinME and NT4 */
847 "EM_POSFROMCHAR reports x=%hd, expected value less than %d\n", pl.x, xpos);
849 DestroyWindow(hwndRichEdit);
852 static void test_word_wrap(void)
854 HWND hwnd;
855 POINTL point = {0, 60}; /* This point must be below the first line */
856 const char *text = "Must be long enough to test line wrapping";
857 DWORD dwCommonStyle = WS_VISIBLE|WS_POPUP|WS_VSCROLL|ES_MULTILINE;
858 int res, pos, lines, prevlines, reflines[3];
860 /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping
861 * when specified on window creation and set later. */
862 hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL, dwCommonStyle,
863 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
864 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
865 res = SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) text);
866 ok(res, "WM_SETTEXT failed.\n");
867 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
868 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
869 lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
870 ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines);
872 SetWindowLong(hwnd, GWL_STYLE, dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL);
873 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
874 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
875 DestroyWindow(hwnd);
877 hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL, dwCommonStyle|WS_HSCROLL,
878 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
879 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
881 res = SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) text);
882 ok(res, "WM_SETTEXT failed.\n");
883 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
884 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
885 lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
886 ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines);
888 SetWindowLong(hwnd, GWL_STYLE, dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL);
889 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
890 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
891 DestroyWindow(hwnd);
893 hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL, dwCommonStyle|ES_AUTOHSCROLL,
894 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
895 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
896 res = SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) text);
897 ok(res, "WM_SETTEXT failed.\n");
898 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
899 ok(!pos ||
900 broken(pos == lstrlen(text)), /* Win9x, WinME and NT4 */
901 "pos=%d indicating word wrap when none is expected.\n", pos);
902 lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
903 ok(lines == 1, "Line was not expected to wrap (lines=%d).\n", lines);
905 SetWindowLong(hwnd, GWL_STYLE, dwCommonStyle);
906 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
907 ok(!pos ||
908 broken(pos == lstrlen(text)), /* Win9x, WinME and NT4 */
909 "pos=%d indicating word wrap when none is expected.\n", pos);
910 lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
911 ok(lines == 1, "Line was not expected to wrap (lines=%d).\n", lines);
912 DestroyWindow(hwnd);
914 hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL,
915 dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL,
916 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
917 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
918 res = SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) text);
919 ok(res, "WM_SETTEXT failed.\n");
920 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
921 ok(!pos ||
922 broken(pos == lstrlen(text)), /* Win9x, WinME and NT4 */
923 "pos=%d indicating word wrap when none is expected.\n", pos);
924 lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
925 ok(lines == 1, "Line was not expected to wrap (lines=%d).\n", lines);
927 SetWindowLong(hwnd, GWL_STYLE, dwCommonStyle);
928 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
929 ok(!pos ||
930 broken(pos == lstrlen(text)), /* Win9x, WinME and NT4 */
931 "pos=%d indicating word wrap when none is expected.\n", pos);
932 lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
933 ok(lines == 1, "Line was not expected to wrap (lines=%d).\n", lines);
935 /* Test the effect of EM_SETTARGETDEVICE on word wrap. */
936 res = SendMessage(hwnd, EM_SETTARGETDEVICE, 0, 1);
937 ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res);
938 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
939 ok(!pos ||
940 broken(pos == lstrlen(text)), /* Win9x, WinME and NT4 */
941 "pos=%d indicating word wrap when none is expected.\n", pos);
942 lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
943 ok(lines == 1, "Line was not expected to wrap (lines=%d).\n", lines);
945 res = SendMessage(hwnd, EM_SETTARGETDEVICE, 0, 0);
946 ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res);
947 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
948 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
949 DestroyWindow(hwnd);
951 /* First lets see if the text would wrap normally (needed for reference) */
952 hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL, dwCommonStyle,
953 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
954 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
955 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
956 res = SendMessage(hwnd, EM_REPLACESEL, FALSE, (LPARAM) text);
957 ok(res, "EM_REPLACESEL failed.\n");
958 /* Should have wrapped */
959 reflines[0] = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
960 ok(reflines[0] > 1, "Line was expected to wrap (%d lines).\n", reflines[0]);
961 /* Resize the window to fit the line */
962 MoveWindow(hwnd, 0, 0, 600, 80, TRUE);
963 /* Text should not be wrapped */
964 reflines[1] = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
965 ok(reflines[1] == 1, "Line wasn't expected to wrap (%d lines).\n", reflines[1]);
966 /* Resize the window again to make sure the line wraps again */
967 MoveWindow(hwnd, 0, 0, 10, 80, TRUE);
968 reflines[2] = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
969 ok(reflines[2] > 1, "Line was expected to wrap (%d lines).\n", reflines[2]);
970 DestroyWindow(hwnd);
972 /* Same test with redraw disabled */
973 hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL, dwCommonStyle,
974 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
975 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
976 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
977 /* Redraw is disabled by making the window invisible. */
978 SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
979 ok(!IsWindowVisible(hwnd), "Window shouldn't be visible.\n");
980 res = SendMessage(hwnd, EM_REPLACESEL, FALSE, (LPARAM) text);
981 ok(res, "EM_REPLACESEL failed.\n");
982 /* Should have wrapped */
983 prevlines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
984 ok(prevlines == reflines[0],
985 "Line was expected to wrap (%d lines).\n", prevlines);
986 /* Resize the window to fit the line, no change to the number of lines */
987 MoveWindow(hwnd, 0, 0, 600, 80, TRUE);
988 lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
989 todo_wine
990 ok(lines == prevlines ||
991 broken(lines == reflines[1]), /* Win98, WinME and NT4 */
992 "Expected no change in the number of lines\n");
993 /* Resize the window again to make sure the line wraps again */
994 MoveWindow(hwnd, 0, 0, 10, 80, TRUE);
995 lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
996 todo_wine
997 ok(lines == prevlines ||
998 broken(lines == reflines[2]), /* Win98, WinME and NT4 */
999 "Expected no change in the number of lines\n");
1000 DestroyWindow(hwnd);
1003 static void test_EM_GETOPTIONS(void)
1005 HWND hwnd;
1006 DWORD options;
1008 hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL,
1009 WS_POPUP,
1010 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
1011 options = SendMessage(hwnd, EM_GETOPTIONS, 0, 0);
1012 ok(options == 0, "Incorrect options %x\n", options);
1013 DestroyWindow(hwnd);
1015 hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL,
1016 WS_POPUP|WS_VSCROLL|WS_HSCROLL,
1017 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
1018 options = SendMessage(hwnd, EM_GETOPTIONS, 0, 0);
1019 ok(options == ECO_AUTOVSCROLL ||
1020 broken(options == 0), /* Win9x, WinME and NT4 */
1021 "Incorrect initial options %x\n", options);
1022 DestroyWindow(hwnd);
1025 static void test_autoscroll(void)
1027 HWND hwnd;
1028 UINT ret;
1030 /* The WS_VSCROLL and WS_HSCROLL styles implicitly set
1031 * auto vertical/horizontal scrolling options. */
1032 hwnd = CreateWindowEx(0, RICHEDIT_CLASS10A, NULL,
1033 WS_POPUP|ES_MULTILINE|WS_VSCROLL|WS_HSCROLL,
1034 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
1035 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS10A, (int) GetLastError());
1036 ret = SendMessage(hwnd, EM_GETOPTIONS, 0, 0);
1037 ok(ret & ECO_AUTOVSCROLL ||
1038 broken(!(ret & ECO_AUTOVSCROLL)), /* Win9x, WinME and NT4 */
1039 "ECO_AUTOVSCROLL isn't set.\n");
1040 ok(!(ret & ECO_AUTOHSCROLL), "ECO_AUTOHSCROLL is set.\n");
1041 ret = GetWindowLong(hwnd, GWL_STYLE);
1042 todo_wine
1043 ok(ret & ES_AUTOVSCROLL ||
1044 broken(!(ret & ES_AUTOVSCROLL)), /* Win9x, WinMe and NT4 */
1045 "ES_AUTOVSCROLL isn't set.\n");
1046 ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n");
1047 DestroyWindow(hwnd);
1049 hwnd = CreateWindowEx(0, RICHEDIT_CLASS10A, NULL,
1050 WS_POPUP|ES_MULTILINE,
1051 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
1052 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS10A, (int) GetLastError());
1053 ret = SendMessage(hwnd, EM_GETOPTIONS, 0, 0);
1054 ok(!(ret & ECO_AUTOVSCROLL), "ECO_AUTOVSCROLL is set.\n");
1055 ok(!(ret & ECO_AUTOHSCROLL), "ECO_AUTOHSCROLL is set.\n");
1056 ret = GetWindowLong(hwnd, GWL_STYLE);
1057 ok(!(ret & ES_AUTOVSCROLL), "ES_AUTOVSCROLL is set.\n");
1058 ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n");
1059 DestroyWindow(hwnd);
1062 START_TEST( editor )
1064 MSG msg;
1065 time_t end;
1067 /* Must explicitly LoadLibrary(). The test has no references to functions in
1068 * RICHED32.DLL, so the linker doesn't actually link to it. */
1069 hmoduleRichEdit = LoadLibrary("RICHED32.DLL");
1070 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
1072 test_WM_SETTEXT();
1073 test_EM_GETTEXTRANGE();
1074 test_EM_GETSELTEXT();
1075 test_WM_GETTEXTLENGTH();
1076 test_EM_STREAMIN();
1077 test_EM_STREAMOUT();
1078 test_EM_GETLINE();
1079 test_EM_LINELENGTH();
1080 test_EM_FINDTEXT();
1081 test_EM_POSFROMCHAR();
1082 test_word_wrap();
1083 test_EM_GETOPTIONS();
1084 test_autoscroll();
1086 /* Set the environment variable WINETEST_RICHED32 to keep windows
1087 * responsive and open for 30 seconds. This is useful for debugging.
1089 * The message pump uses PeekMessage() to empty the queue and then sleeps for
1090 * 50ms before retrying the queue. */
1091 end = time(NULL) + 30;
1092 if (getenv( "WINETEST_RICHED32" )) {
1093 while (time(NULL) < end) {
1094 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1095 TranslateMessage(&msg);
1096 DispatchMessage(&msg);
1097 } else {
1098 Sleep(50);
1103 OleFlushClipboard();
1104 ok(FreeLibrary(hmoduleRichEdit) != 0, "error: %d\n", (int) GetLastError());