sync rostests to r44455
[reactos.git] / rostests / winetests / riched32 / 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(void)
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 *
77 * For riched32, the rules for breaking lines seem to be the following:
78 * - \r\n is one line break. This is the normal case.
79 * - \r{0,2}\n is one line break. In particular, \n by itself is a line break.
80 * - \r{0,N-1}\r\r\n is N line breaks.
81 * - \n{1,N} are that many line breaks.
82 * - \r with text or other characters (except \n) past it, is a line break. That
83 * is, a run of \r{N} without a terminating \n is considered N line breaks
84 * - \r at the end of the text is NOT a line break. This differs from riched20,
85 * where \r at the end of the text is a proper line break.
86 */
87
88 #define TEST_SETTEXT(a, b, nlines) \
89 result = SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) a); \
90 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
91 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buf); \
92 ok (result == lstrlen(buf), \
93 "WM_GETTEXT returned %ld instead of expected %u\n", \
94 result, lstrlen(buf)); \
95 result = strcmp(b, buf); \
96 ok(result == 0, \
97 "WM_SETTEXT round trip: strcmp = %ld\n", result); \
98 result = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0); \
99 ok(result == nlines, "EM_GETLINECOUNT returned %ld, expected %d\n", result, nlines);
100
101 TEST_SETTEXT(TestItem1, TestItem1, 1)
102 TEST_SETTEXT(TestItem2, TestItem2, 1)
103 TEST_SETTEXT(TestItem3, TestItem3, 2)
104 TEST_SETTEXT(TestItem4, TestItem4, 3)
105 TEST_SETTEXT(TestItem5, TestItem5, 2)
106 TEST_SETTEXT(TestItem6, TestItem6, 3)
107 TEST_SETTEXT(TestItem7, TestItem7, 4)
108 TEST_SETTEXT(TestItem8, TestItem8, 2)
109 TEST_SETTEXT(TestItem9, TestItem9, 3)
110 TEST_SETTEXT(TestItem10, TestItem10, 3)
111 TEST_SETTEXT(TestItem11, TestItem11, 1)
112 TEST_SETTEXT(TestItem12, TestItem12, 2)
113 TEST_SETTEXT(TestItem13, TestItem13, 3)
114 TEST_SETTEXT(TestItem14, TestItem14, 2)
115 TEST_SETTEXT(TestItem15, TestItem15, 3)
116 TEST_SETTEXT(TestItem16, TestItem16, 4)
117
118 #undef TEST_SETTEXT
119 DestroyWindow(hwndRichEdit);
120 }
121
122 static void test_WM_GETTEXTLENGTH(void)
123 {
124 HWND hwndRichEdit = new_richedit(NULL);
125 static const char text3[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee";
126 static const char text4[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee\r\n";
127 int result;
128
129 /* Test for WM_GETTEXTLENGTH */
130 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text3);
131 result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
132 ok(result == lstrlen(text3),
133 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
134 result, lstrlen(text3));
135
136 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text4);
137 result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
138 ok(result == lstrlen(text4),
139 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
140 result, lstrlen(text4));
141
142 DestroyWindow(hwndRichEdit);
143 }
144
145 static DWORD CALLBACK test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie,
146 LPBYTE pbBuff,
147 LONG cb,
148 LONG *pcb)
149 {
150 const char** str = (const char**)dwCookie;
151 int size = strlen(*str);
152 *pcb = cb;
153 if (*pcb > size) {
154 *pcb = size;
155 }
156 if (*pcb > 0) {
157 memcpy(pbBuff, *str, *pcb);
158 *str += *pcb;
159 }
160 return 0;
161 }
162
163
164 static void test_EM_STREAMIN(void)
165 {
166 HWND hwndRichEdit = new_richedit(NULL);
167 LRESULT result;
168 EDITSTREAM es;
169 char buffer[1024] = {0};
170
171 const char * streamText0 = "{\\rtf1 TestSomeText}";
172 const char * streamText0a = "{\\rtf1 TestSomeText\\par}";
173 const char * streamText0b = "{\\rtf1 TestSomeText\\par\\par}";
174
175 const char * streamText1 =
176 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
177 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
178 "}\r\n";
179
180 /* This should be accepted in richedit 1.0 emulation. See bug #8326 */
181 const char * streamText2 =
182 "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;"
183 "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255"
184 "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 "
185 "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 "
186 "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 "
187 "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 "
188 "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }";
189
190 const char * streamText3 = "RichEdit1";
191
192 /* Minimal test without \par at the end */
193 es.dwCookie = (DWORD_PTR)&streamText0;
194 es.dwError = 0;
195 es.pfnCallback = test_EM_STREAMIN_esCallback;
196 SendMessage(hwndRichEdit, EM_STREAMIN,
197 (WPARAM)(SF_RTF), (LPARAM)&es);
198
199 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
200 ok (result == 12,
201 "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result);
202 result = strcmp (buffer,"TestSomeText");
203 ok (result == 0,
204 "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer);
205 ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
206
207 /* Native richedit 2.0 ignores last \par */
208 es.dwCookie = (DWORD_PTR)&streamText0a;
209 es.dwError = 0;
210 es.pfnCallback = test_EM_STREAMIN_esCallback;
211 SendMessage(hwndRichEdit, EM_STREAMIN,
212 (WPARAM)(SF_RTF), (LPARAM)&es);
213
214 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
215 ok (result == 12,
216 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result);
217 result = strcmp (buffer,"TestSomeText");
218 ok (result == 0,
219 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer);
220 ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
221
222 /* Native richedit 2.0 ignores last \par, next-to-last \par appears */
223 es.dwCookie = (DWORD_PTR)&streamText0b;
224 es.dwError = 0;
225 es.pfnCallback = test_EM_STREAMIN_esCallback;
226 SendMessage(hwndRichEdit, EM_STREAMIN,
227 (WPARAM)(SF_RTF), (LPARAM)&es);
228
229 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
230 ok (result == 14,
231 "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result);
232 result = strcmp (buffer,"TestSomeText\r\n");
233 ok (result == 0,
234 "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer);
235 ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
236
237 es.dwCookie = (DWORD_PTR)&streamText1;
238 es.dwError = 0;
239 es.pfnCallback = test_EM_STREAMIN_esCallback;
240 SendMessage(hwndRichEdit, EM_STREAMIN,
241 (WPARAM)(SF_RTF), (LPARAM)&es);
242
243 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
244 ok (result == 12,
245 "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result);
246 result = strcmp (buffer,"TestSomeText");
247 ok (result == 0,
248 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
249 ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
250
251
252 es.dwCookie = (DWORD_PTR)&streamText2;
253 es.dwError = 0;
254 SendMessage(hwndRichEdit, EM_STREAMIN,
255 (WPARAM)(SF_RTF), (LPARAM)&es);
256
257 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
258 todo_wine {
259 ok (result == 9,
260 "EM_STREAMIN: Test 2 returned %ld, expected 9\n", result);
261 }
262 result = strcmp (buffer,"RichEdit1");
263 todo_wine {
264 ok (result == 0,
265 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
266 }
267 ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
268
269 es.dwCookie = (DWORD_PTR)&streamText3;
270 es.dwError = 0;
271 SendMessage(hwndRichEdit, EM_STREAMIN,
272 (WPARAM)(SF_RTF), (LPARAM)&es);
273
274 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
275 ok (result == 0,
276 "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result);
277 ok (strlen(buffer) == 0,
278 "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer);
279 ok(es.dwError == -16, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, -16);
280
281 DestroyWindow(hwndRichEdit);
282 }
283
284 static DWORD CALLBACK test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie,
285 LPBYTE pbBuff,
286 LONG cb,
287 LONG *pcb)
288 {
289 char** str = (char**)dwCookie;
290 *pcb = cb;
291 if (*pcb > 0) {
292 memcpy(*str, pbBuff, *pcb);
293 *str += *pcb;
294 }
295 return 0;
296 }
297
298 static void test_EM_STREAMOUT(void)
299 {
300 HWND hwndRichEdit = new_richedit(NULL);
301 int r;
302 EDITSTREAM es;
303 char buf[1024] = {0};
304 char * p;
305
306 const char * TestItem1 = "TestSomeText";
307 const char * TestItem2 = "TestSomeText\r";
308 const char * TestItem3 = "TestSomeText\r\n";
309
310 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem1);
311 p = buf;
312 es.dwCookie = (DWORD_PTR)&p;
313 es.dwError = 0;
314 es.pfnCallback = test_WM_SETTEXT_esCallback;
315 memset(buf, 0, sizeof(buf));
316 SendMessage(hwndRichEdit, EM_STREAMOUT,
317 (WPARAM)(SF_TEXT), (LPARAM)&es);
318 r = strlen(buf);
319 ok(r == 12, "streamed text length is %d, expecting 12\n", r);
320 ok(strcmp(buf, TestItem1) == 0,
321 "streamed text different, got %s\n", buf);
322
323 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem2);
324 p = buf;
325 es.dwCookie = (DWORD_PTR)&p;
326 es.dwError = 0;
327 es.pfnCallback = test_WM_SETTEXT_esCallback;
328 memset(buf, 0, sizeof(buf));
329 SendMessage(hwndRichEdit, EM_STREAMOUT,
330 (WPARAM)(SF_TEXT), (LPARAM)&es);
331 r = strlen(buf);
332
333 ok(r == 13, "streamed text length is %d, expecting 13\n", r);
334 ok(strcmp(buf, TestItem2) == 0,
335 "streamed text different, got %s\n", buf);
336
337 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) TestItem3);
338 p = buf;
339 es.dwCookie = (DWORD_PTR)&p;
340 es.dwError = 0;
341 es.pfnCallback = test_WM_SETTEXT_esCallback;
342 memset(buf, 0, sizeof(buf));
343 SendMessage(hwndRichEdit, EM_STREAMOUT,
344 (WPARAM)(SF_TEXT), (LPARAM)&es);
345 r = strlen(buf);
346 ok(r == 14, "streamed text length is %d, expecting 14\n", r);
347 ok(strcmp(buf, TestItem3) == 0,
348 "streamed text different, got %s\n", buf);
349
350 DestroyWindow(hwndRichEdit);
351 }
352
353 static const struct getline_s {
354 int line;
355 size_t buffer_len;
356 const char *text;
357 } gl[] = {
358 {0, 10, "foo bar\r\n"},
359 {1, 10, "\r"},
360 {2, 10, "\r\r\n"},
361 {3, 10, "bar\n"},
362 {4, 10, "\r\n"},
363
364 /* Buffer smaller than line length */
365 {0, 2, "foo bar\r"},
366 {0, 1, "foo bar\r"},
367 {0, 0, "foo bar\r"}
368 };
369
370 static void test_EM_GETLINE(void)
371 {
372 int i;
373 HWND hwndRichEdit = new_richedit(NULL);
374 static const int nBuf = 1024;
375 char dest[1024], origdest[1024];
376 const char text[] = "foo bar\r\n"
377 "\r"
378 "\r\r\n"
379 "bar\n";
380
381 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
382
383 memset(origdest, 0xBB, nBuf);
384 for (i = 0; i < sizeof(gl)/sizeof(struct getline_s); i++)
385 {
386 int nCopied;
387 int expected_nCopied = min(gl[i].buffer_len, strlen(gl[i].text));
388 int expected_bytes_written = min(gl[i].buffer_len, strlen(gl[i].text) + 1);
389 memset(dest, 0xBB, nBuf);
390 *(WORD *) dest = gl[i].buffer_len;
391
392 /* EM_GETLINE appends a "\r\0" to the end of the line
393 * nCopied counts up to and including the '\r' */
394 nCopied = SendMessage(hwndRichEdit, EM_GETLINE, gl[i].line, (LPARAM) dest);
395 ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied,
396 expected_nCopied);
397 /* two special cases since a parameter is passed via dest */
398 if (gl[i].buffer_len == 0)
399 ok(!dest[0] && !dest[1] && !strncmp(dest+2, origdest+2, nBuf-2),
400 "buffer_len=0\n");
401 else if (gl[i].buffer_len == 1)
402 ok(dest[0] == gl[i].text[0] && !dest[1] &&
403 !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n");
404 else
405 {
406 ok(!strncmp(dest, gl[i].text, expected_bytes_written),
407 "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
408 ok(!strncmp(dest + expected_bytes_written, origdest
409 + expected_bytes_written, nBuf - expected_bytes_written),
410 "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
411 }
412 }
413
414 DestroyWindow(hwndRichEdit);
415 }
416
417 static void test_EM_LINELENGTH(void)
418 {
419 HWND hwndRichEdit = new_richedit(NULL);
420 const char * text =
421 "richedit1\r"
422 "richedit1\n"
423 "richedit1\r\n"
424 "short\r"
425 "richedit1\r"
426 "\r"
427 "\r"
428 "\r\r\n";
429 int offset_test[16][2] = {
430 {0, 9}, /* Line 1: |richedit1\r */
431 {5, 9}, /* Line 1: riche|dit1\r */
432 {10, 9}, /* Line 2: |richedit1\n */
433 {15, 9}, /* Line 2: riche|dit1\n */
434 {20, 9}, /* Line 3: |richedit1\r\n */
435 {25, 9}, /* Line 3: riche|dit1\r\n */
436 {30, 9}, /* Line 3: richedit1\r|\n */
437 {31, 5}, /* Line 4: |short\r */
438 {42, 9}, /* Line 5: riche|dit1\r */
439 {46, 9}, /* Line 5: richedit1|\r */
440 {47, 0}, /* Line 6: |\r */
441 {48, 0}, /* Line 7: |\r */
442 {49, 0}, /* Line 8: |\r\r\n */
443 {50, 0}, /* Line 8: \r|\r\n */
444 {51, 0}, /* Line 8: \r\r|\n */
445 {52, 0}, /* Line 9: \r\r\n| */
446 };
447 int i;
448 LRESULT result;
449
450 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
451
452 result = SendMessage(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
453 if (result == 4) {
454 win_skip("Win9x, WinME and NT4 don't handle '\\r only' correctly\n");
455 return;
456 }
457 ok(result == 9, "Incorrect line count of %ld\n", result);
458
459 for (i = 0; i < sizeof(offset_test)/sizeof(offset_test[0]); i++) {
460 result = SendMessage(hwndRichEdit, EM_LINELENGTH, offset_test[i][0], 0);
461 ok(result == offset_test[i][1], "Length of line at offset %d is %ld, expected %d\n",
462 offset_test[i][0], result, offset_test[i][1]);
463 }
464
465 DestroyWindow(hwndRichEdit);
466 }
467
468 static void test_EM_GETTEXTRANGE(void)
469 {
470 HWND hwndRichEdit = new_richedit(NULL);
471 const char * text1 = "foo bar\r\nfoo bar";
472 const char * text3 = "foo bar\rfoo bar";
473 const char * expect1 = "bar\r\nfoo";
474 const char * expect2 = "\nfoo";
475 const char * expect3 = "bar\rfoo";
476 char buffer[1024] = {0};
477 LRESULT result;
478 TEXTRANGEA textRange;
479
480 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
481
482 textRange.lpstrText = buffer;
483 textRange.chrg.cpMin = 4;
484 textRange.chrg.cpMax = 12;
485 result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
486 ok(result == 8, "EM_GETTEXTRANGE returned %ld\n", result);
487 ok(!strcmp(expect1, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
488
489 textRange.lpstrText = buffer;
490 textRange.chrg.cpMin = 8;
491 textRange.chrg.cpMax = 12;
492 result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
493 ok(result == 4, "EM_GETTEXTRANGE returned %ld\n", result);
494 ok(!strcmp(expect2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
495
496 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3);
497
498 textRange.lpstrText = buffer;
499 textRange.chrg.cpMin = 4;
500 textRange.chrg.cpMax = 11;
501 result = SendMessage(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
502 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
503
504 ok(!strcmp(expect3, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
505
506
507 DestroyWindow(hwndRichEdit);
508 }
509
510 static void test_EM_GETSELTEXT(void)
511 {
512 HWND hwndRichEdit = new_richedit(NULL);
513 const char * text1 = "foo bar\r\nfoo bar";
514 const char * text2 = "foo bar\rfoo bar";
515 const char * expect1 = "bar\r\nfoo";
516 const char * expect2 = "bar\rfoo";
517 char buffer[1024] = {0};
518 LRESULT result;
519
520 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
521
522 SendMessage(hwndRichEdit, EM_SETSEL, 4, 12);
523 result = SendMessage(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
524 ok(result == 8, "EM_GETTEXTRANGE returned %ld\n", result);
525 ok(!strcmp(expect1, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
526
527 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
528
529 SendMessage(hwndRichEdit, EM_SETSEL, 4, 11);
530 result = SendMessage(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
531 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
532
533 ok(!strcmp(expect2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
534
535
536 DestroyWindow(hwndRichEdit);
537 }
538
539 static const char haystack[] = "WINEWine wineWine wine WineWine";
540 /* ^0 ^10 ^20 ^30 */
541
542 static const char haystack2[] = "first\r\r\nsecond";
543
544 struct find_s {
545 int start;
546 int end;
547 const char *needle;
548 int flags;
549 int expected_loc;
550 };
551
552
553 struct find_s find_tests[] = {
554 /* Find in empty text */
555 {0, -1, "foo", FR_DOWN, -1},
556 {0, -1, "foo", 0, -1},
557 {0, -1, "", FR_DOWN, -1},
558 {20, 5, "foo", FR_DOWN, -1},
559 {5, 20, "foo", FR_DOWN, -1}
560 };
561
562 struct find_s find_tests2[] = {
563 /* No-result find */
564 {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1},
565 {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1},
566
567 /* Subsequent finds */
568 {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4},
569 {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13},
570 {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23},
571 {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27},
572
573 /* Find backwards */
574 {19, 20, "Wine", FR_MATCHCASE, -1},
575 {10, 20, "Wine", FR_MATCHCASE, 13},
576 {20, 10, "Wine", FR_MATCHCASE, -1},
577
578 /* Case-insensitive */
579 {1, 31, "wInE", FR_DOWN, 4},
580 {1, 31, "Wine", FR_DOWN, 4},
581
582 /* High-to-low ranges */
583 {20, 5, "Wine", FR_DOWN, -1},
584 {2, 1, "Wine", FR_DOWN, -1},
585 {30, 29, "Wine", FR_DOWN, -1},
586 {20, 5, "Wine", 0, /*13*/ -1},
587
588 /* Find nothing */
589 {5, 10, "", FR_DOWN, -1},
590 {10, 5, "", FR_DOWN, -1},
591 {0, -1, "", FR_DOWN, -1},
592 {10, 5, "", 0, -1},
593
594 /* Whole-word search */
595 {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18},
596 {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1},
597 {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18},
598 {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0},
599 {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23},
600 {11, -1, "winewine", FR_WHOLEWORD, 23},
601 {31, -1, "winewine", FR_WHOLEWORD, -1},
602
603 /* Bad ranges */
604 {5, 200, "XXX", FR_DOWN, -1},
605 {-20, 20, "Wine", FR_DOWN, -1},
606 {-20, 20, "Wine", FR_DOWN, -1},
607 {-15, -20, "Wine", FR_DOWN, -1},
608 {1<<12, 1<<13, "Wine", FR_DOWN, -1},
609
610 /* Check the case noted in bug 4479 where matches at end aren't recognized */
611 {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23},
612 {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27},
613 {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27},
614 {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23},
615 {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23},
616
617 /* The backwards case of bug 4479; bounds look right
618 * Fails because backward find is wrong */
619 {19, 20, "WINE", FR_MATCHCASE, -1},
620 {0, 20, "WINE", FR_MATCHCASE, 0},
621
622 {0, -1, "wineWine wine", FR_DOWN, 0},
623 {0, -1, "wineWine wine", 0, 0},
624 {0, -1, "INEW", 0, 1},
625 {0, 31, "INEW", 0, 1},
626 {4, -1, "INEW", 0, 10},
627 };
628
629 struct find_s find_tests3[] = {
630 /* Searching for end of line characters */
631 {0, -1, "t\r\r\ns", FR_DOWN | FR_MATCHCASE, 4},
632 {6, -1, "\r\n", FR_DOWN | FR_MATCHCASE, 6},
633 {7, -1, "\n", FR_DOWN | FR_MATCHCASE, 7},
634 };
635
636 static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id) {
637 int findloc;
638 FINDTEXT ft;
639 memset(&ft, 0, sizeof(ft));
640 ft.chrg.cpMin = f->start;
641 ft.chrg.cpMax = f->end;
642 ft.lpstrText = f->needle;
643 findloc = SendMessage(hwnd, EM_FINDTEXT, f->flags, (LPARAM) &ft);
644 ok(findloc == f->expected_loc,
645 "EM_FINDTEXT(%s,%d) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
646 name, id, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc);
647 }
648
649 static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f,
650 int id) {
651 int findloc;
652 FINDTEXTEX ft;
653 int expected_end_loc;
654
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_FINDTEXTEX, f->flags, (LPARAM) &ft);
660 ok(findloc == f->expected_loc,
661 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
662 name, id, f->needle, f->start, f->end, f->flags, findloc);
663 ok(ft.chrgText.cpMin == f->expected_loc,
664 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d, expected %d\n",
665 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMin, f->expected_loc);
666 expected_end_loc = ((f->expected_loc == -1) ? -1
667 : f->expected_loc + strlen(f->needle));
668 ok(ft.chrgText.cpMax == expected_end_loc,
669 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
670 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMax, expected_end_loc);
671 }
672
673 static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find,
674 int num_tests)
675 {
676 int i;
677
678 for (i = 0; i < num_tests; i++) {
679 check_EM_FINDTEXT(hwnd, name, &find[i], i);
680 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
681 }
682 }
683
684 static void test_EM_FINDTEXT(void)
685 {
686 HWND hwndRichEdit = new_richedit(NULL);
687
688 /* Empty rich edit control */
689 run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests,
690 sizeof(find_tests)/sizeof(struct find_s));
691
692 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack);
693
694 /* Haystack text */
695 run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2,
696 sizeof(find_tests2)/sizeof(struct find_s));
697
698 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack2);
699
700 /* Haystack text 2 (with EOL characters) */
701 run_tests_EM_FINDTEXT(hwndRichEdit, "3", find_tests3,
702 sizeof(find_tests3)/sizeof(struct find_s));
703
704 DestroyWindow(hwndRichEdit);
705 }
706
707 static void test_EM_POSFROMCHAR(void)
708 {
709 HWND hwndRichEdit = new_richedit(NULL);
710 int i;
711 POINTL pl;
712 LRESULT result;
713 unsigned int height = 0;
714 int xpos = 0;
715 static const char text[] = "aa\n"
716 "this is a long line of text that should be longer than the "
717 "control's width\n"
718 "cc\n"
719 "dd\n"
720 "ee\n"
721 "ff\n"
722 "gg\n"
723 "hh\n";
724
725 /* Fill the control to lines to ensure that most of them are offscreen */
726 for (i = 0; i < 50; i++)
727 {
728 /* Do not modify the string; it is exactly 16 characters long. */
729 SendMessage(hwndRichEdit, EM_SETSEL, 0, 0);
730 SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"0123456789ABCD\r\n");
731 }
732
733 /*
734 Richedit 1.0 receives a POINTL* on wParam and character offset on lParam, returns void.
735 Richedit 2.0 receives character offset on wParam, ignores lParam, returns MAKELONG(x,y)
736 Richedit 3.0 accepts either of the above API conventions.
737 */
738
739 /* Testing Richedit 1.0 API format */
740
741 /* Testing start of lines. X-offset should be constant on all cases (native is 1).
742 Since all lines are identical and drawn with the same font,
743 they should have the same height... right?
744 */
745 for (i = 0; i < 50; i++)
746 {
747 /* All the lines are 16 characters long */
748 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, i * 16);
749 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
750 if (i == 0)
751 {
752 ok(pl.y == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl.y);
753 ok(pl.x == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
754 xpos = pl.x;
755 }
756 else if (i == 1)
757 {
758 ok(pl.y > 0, "EM_POSFROMCHAR reports y=%d, expected > 0\n", pl.y);
759 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
760 height = pl.y;
761 }
762 else
763 {
764 ok(pl.y == i * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, i * height);
765 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
766 }
767 }
768
769 /* Testing position at end of text */
770 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 50 * 16);
771 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
772 ok(pl.y == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, 50 * height);
773 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
774
775 /* Testing position way past end of text */
776 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 55 * 16);
777 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
778 ok(pl.y == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, 50 * height);
779 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
780
781
782 /* Testing that vertical scrolling does, in fact, have an effect on EM_POSFROMCHAR */
783 SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
784 for (i = 0; i < 50; i++)
785 {
786 /* All the lines are 16 characters long */
787 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, i * 16);
788 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
789 ok(pl.y == (i - 1) * height,
790 "EM_POSFROMCHAR reports y=%d, expected %d\n",
791 pl.y, (i - 1) * height);
792 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
793 }
794
795 /* Testing position at end of text */
796 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 50 * 16);
797 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
798 ok(pl.y == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, (50 - 1) * height);
799 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
800
801 /* Testing position way past end of text */
802 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 55 * 16);
803 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
804 ok(pl.y == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, (50 - 1) * height);
805 ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
806
807 /* Testing that horizontal scrolling does, in fact, have an effect on EM_POSFROMCHAR */
808 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
809 SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
810
811 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 0);
812 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
813 ok(pl.y == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl.y);
814 ok(pl.x == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
815 xpos = pl.x;
816
817 SendMessage(hwndRichEdit, WM_HSCROLL, SB_LINERIGHT, 0);
818 result = SendMessage(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 0);
819 ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
820 ok(pl.y == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl.y);
821 todo_wine {
822 /* Fails on builtin because horizontal scrollbar is not being shown */
823 ok(pl.x < xpos, "EM_POSFROMCHAR reports x=%hd, expected value less than %d\n", pl.x, xpos);
824 }
825 DestroyWindow(hwndRichEdit);
826 }
827
828 static void test_word_wrap(void)
829 {
830 HWND hwnd;
831 POINTL point = {0, 60}; /* This point must be below the first line */
832 const char *text = "Must be long enough to test line wrapping";
833 DWORD dwCommonStyle = WS_VISIBLE|WS_POPUP|WS_VSCROLL|ES_MULTILINE;
834 int res, pos, lines;
835
836 /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping
837 * when specified on window creation and set later. */
838 hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL, dwCommonStyle,
839 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
840 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
841 res = SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) text);
842 ok(res, "WM_SETTEXT failed.\n");
843 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
844 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
845 lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
846 ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines);
847
848 SetWindowLong(hwnd, GWL_STYLE, dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL);
849 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
850 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
851 DestroyWindow(hwnd);
852
853 hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL, dwCommonStyle|WS_HSCROLL,
854 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
855 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
856
857 res = SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) text);
858 ok(res, "WM_SETTEXT failed.\n");
859 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
860 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
861 lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
862 ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines);
863
864 SetWindowLong(hwnd, GWL_STYLE, dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL);
865 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
866 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
867 DestroyWindow(hwnd);
868
869 hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL, dwCommonStyle|ES_AUTOHSCROLL,
870 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
871 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
872 res = SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) text);
873 ok(res, "WM_SETTEXT failed.\n");
874 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
875 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
876
877 SetWindowLong(hwnd, GWL_STYLE, dwCommonStyle);
878 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
879 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
880 DestroyWindow(hwnd);
881
882 hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL,
883 dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL,
884 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
885 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
886 res = SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) text);
887 ok(res, "WM_SETTEXT failed.\n");
888 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
889 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
890
891 SetWindowLong(hwnd, GWL_STYLE, dwCommonStyle);
892 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
893 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
894
895 /* Test the effect of EM_SETTARGETDEVICE on word wrap. */
896 res = SendMessage(hwnd, EM_SETTARGETDEVICE, 0, 1);
897 ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res);
898 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
899 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
900
901 res = SendMessage(hwnd, EM_SETTARGETDEVICE, 0, 0);
902 ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res);
903 pos = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM) &point);
904 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
905 DestroyWindow(hwnd);
906
907 /* Test to see if wrapping happens with redraw disabled. */
908 hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL, dwCommonStyle,
909 0, 0, 400, 80, NULL, NULL, hmoduleRichEdit, NULL);
910 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
911 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
912 SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
913 /* redraw is disabled by making the window invisible. */
914 ok(!IsWindowVisible(hwnd), "Window shouldn't be visible.\n");
915 res = SendMessage(hwnd, EM_REPLACESEL, FALSE, (LPARAM) text);
916 ok(res, "EM_REPLACESEL failed.\n");
917 MoveWindow(hwnd, 0, 0, 100, 80, TRUE);
918 SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
919 /* Wrapping didn't happen while redraw was disabled. */
920 lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
921 todo_wine ok(lines == 1, "Line wasn't expected to wrap (lines=%d).\n", lines);
922 /* There isn't even a rewrap from resizing the window. */
923 lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
924 todo_wine ok(lines == 1, "Line wasn't expected to wrap (lines=%d).\n", lines);
925 res = SendMessage(hwnd, EM_REPLACESEL, FALSE, (LPARAM) text);
926 ok(res, "EM_REPLACESEL failed.\n");
927 lines = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
928 ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines);
929
930 DestroyWindow(hwnd);
931 }
932
933 static void test_EM_GETOPTIONS(void)
934 {
935 HWND hwnd;
936 DWORD options;
937
938 hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL,
939 WS_POPUP,
940 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
941 options = SendMessage(hwnd, EM_GETOPTIONS, 0, 0);
942 ok(options == 0, "Incorrect options %x\n", options);
943 DestroyWindow(hwnd);
944
945 hwnd = CreateWindow(RICHEDIT_CLASS10A, NULL,
946 WS_POPUP|WS_VSCROLL|WS_HSCROLL,
947 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
948 options = SendMessage(hwnd, EM_GETOPTIONS, 0, 0);
949 ok(options == ECO_AUTOVSCROLL,
950 "Incorrect initial options %x\n", options);
951 DestroyWindow(hwnd);
952 }
953
954 static void test_autoscroll(void)
955 {
956 HWND hwnd;
957 UINT ret;
958
959 /* The WS_VSCROLL and WS_HSCROLL styles implicitly set
960 * auto vertical/horizontal scrolling options. */
961 hwnd = CreateWindowEx(0, RICHEDIT_CLASS10A, NULL,
962 WS_POPUP|ES_MULTILINE|WS_VSCROLL|WS_HSCROLL,
963 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
964 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError());
965 ret = SendMessage(hwnd, EM_GETOPTIONS, 0, 0);
966 ok(ret & ECO_AUTOVSCROLL, "ECO_AUTOVSCROLL isn't set.\n");
967 ok(!(ret & ECO_AUTOHSCROLL), "ECO_AUTOHSCROLL is set.\n");
968 ret = GetWindowLong(hwnd, GWL_STYLE);
969 todo_wine ok(ret & ES_AUTOVSCROLL, "ES_AUTOVSCROLL isn't set.\n");
970 ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n");
971 DestroyWindow(hwnd);
972
973 hwnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL,
974 WS_POPUP|ES_MULTILINE,
975 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
976 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS, (int) GetLastError());
977 ret = SendMessage(hwnd, EM_GETOPTIONS, 0, 0);
978 ok(!(ret & ECO_AUTOVSCROLL), "ECO_AUTOVSCROLL is set.\n");
979 ok(!(ret & ECO_AUTOHSCROLL), "ECO_AUTOHSCROLL is set.\n");
980 ret = GetWindowLong(hwnd, GWL_STYLE);
981 ok(!(ret & ES_AUTOVSCROLL), "ES_AUTOVSCROLL is set.\n");
982 ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n");
983 DestroyWindow(hwnd);
984 }
985
986 START_TEST( editor )
987 {
988 MSG msg;
989 time_t end;
990
991 /* Must explicitly LoadLibrary(). The test has no references to functions in
992 * RICHED32.DLL, so the linker doesn't actually link to it. */
993 hmoduleRichEdit = LoadLibrary("RICHED32.DLL");
994 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
995
996 test_WM_SETTEXT();
997 test_EM_GETTEXTRANGE();
998 test_EM_GETSELTEXT();
999 test_WM_GETTEXTLENGTH();
1000 test_EM_STREAMIN();
1001 test_EM_STREAMOUT();
1002 test_EM_GETLINE();
1003 test_EM_LINELENGTH();
1004 test_EM_FINDTEXT();
1005 test_EM_POSFROMCHAR();
1006 test_word_wrap();
1007 test_EM_GETOPTIONS();
1008 test_autoscroll();
1009
1010 /* Set the environment variable WINETEST_RICHED32 to keep windows
1011 * responsive and open for 30 seconds. This is useful for debugging.
1012 *
1013 * The message pump uses PeekMessage() to empty the queue and then sleeps for
1014 * 50ms before retrying the queue. */
1015 end = time(NULL) + 30;
1016 if (getenv( "WINETEST_RICHED32" )) {
1017 while (time(NULL) < end) {
1018 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1019 TranslateMessage(&msg);
1020 DispatchMessage(&msg);
1021 } else {
1022 Sleep(50);
1023 }
1024 }
1025 }
1026
1027 OleFlushClipboard();
1028 ok(FreeLibrary(hmoduleRichEdit) != 0, "error: %d\n", (int) GetLastError());
1029 }