2 * Unit test suite for rich edit control
4 * Copyright 2006 Google (Thomas Kho)
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <wine/test.h>
26 static HMODULE hmoduleRichEdit;
28 static HWND new_window(LPCTSTR lpClassName, DWORD dwStyle, HWND parent) {
30 hwnd = CreateWindow(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL
31 |WS_VISIBLE, 0, 0, 200, 60, parent, NULL,
32 hmoduleRichEdit, NULL);
33 ok(hwnd != NULL, "class: %s, error: %d\n", lpClassName, (int) GetLastError());
37 static HWND new_richedit(HWND parent) {
38 return new_window(RICHEDIT_CLASS, ES_MULTILINE, parent);
41 static const char haystack[] = "WINEWine wineWine wine WineWine";
54 struct find_s find_tests[] = {
55 /* Find in empty text */
56 {0, -1, "foo", FR_DOWN, -1, 0},
57 {0, -1, "foo", 0, -1, 0},
58 {0, -1, "", FR_DOWN, -1, 0},
59 {20, 5, "foo", FR_DOWN, -1, 0},
60 {5, 20, "foo", FR_DOWN, -1, 0}
63 struct find_s find_tests2[] = {
65 {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1, 0},
66 {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1, 0},
68 /* Subsequent finds */
69 {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4, 0},
70 {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13, 0},
71 {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0},
72 {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
75 {19, 20, "Wine", FR_MATCHCASE, 13, 0},
76 {10, 20, "Wine", FR_MATCHCASE, 4, 0},
77 {20, 10, "Wine", FR_MATCHCASE, 13, 0},
79 /* Case-insensitive */
80 {1, 31, "wInE", FR_DOWN, 4, 0},
81 {1, 31, "Wine", FR_DOWN, 4, 0},
83 /* High-to-low ranges */
84 {20, 5, "Wine", FR_DOWN, -1, 0},
85 {2, 1, "Wine", FR_DOWN, -1, 0},
86 {30, 29, "Wine", FR_DOWN, -1, 0},
87 {20, 5, "Wine", 0, 13, 0},
90 {5, 10, "", FR_DOWN, -1, 0},
91 {10, 5, "", FR_DOWN, -1, 0},
92 {0, -1, "", FR_DOWN, -1, 0},
93 {10, 5, "", 0, -1, 0},
95 /* Whole-word search */
96 {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0},
97 {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1, 0},
98 {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0},
99 {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0, 0},
100 {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23, 0},
101 {11, -1, "winewine", FR_WHOLEWORD, 0, 0},
102 {31, -1, "winewine", FR_WHOLEWORD, 23, 0},
105 {5, 200, "XXX", FR_DOWN, -1, 0},
106 {-20, 20, "Wine", FR_DOWN, -1, 0},
107 {-20, 20, "Wine", FR_DOWN, -1, 0},
108 {-15, -20, "Wine", FR_DOWN, -1, 0},
109 {1<<12, 1<<13, "Wine", FR_DOWN, -1, 0},
111 /* Check the case noted in bug 4479 where matches at end aren't recognized */
112 {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0},
113 {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
114 {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
115 {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0},
116 {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0},
118 /* The backwards case of bug 4479; bounds look right
119 * Fails because backward find is wrong */
120 {19, 20, "WINE", FR_MATCHCASE, 0, 0},
121 {0, 20, "WINE", FR_MATCHCASE, -1, 0}
124 static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id) {
127 memset(&ft, 0, sizeof(ft));
128 ft.chrg.cpMin = f->start;
129 ft.chrg.cpMax = f->end;
130 ft.lpstrText = f->needle;
131 findloc = SendMessage(hwnd, EM_FINDTEXT, f->flags, (LPARAM) &ft);
132 ok(findloc == f->expected_loc,
133 "EM_FINDTEXT(%s,%d) '%s' in range(%d,%d), flags %08x, got start at %d\n",
134 name, id, f->needle, f->start, f->end, f->flags, findloc);
137 static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f,
141 memset(&ft, 0, sizeof(ft));
142 ft.chrg.cpMin = f->start;
143 ft.chrg.cpMax = f->end;
144 ft.lpstrText = f->needle;
145 findloc = SendMessage(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM) &ft);
146 ok(findloc == f->expected_loc,
147 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
148 name, id, f->needle, f->start, f->end, f->flags, findloc);
149 ok(ft.chrgText.cpMin == f->expected_loc,
150 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
151 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMin);
152 ok(ft.chrgText.cpMax == ((f->expected_loc == -1) ? -1
153 : f->expected_loc + strlen(f->needle)),
154 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d\n",
155 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMax);
158 static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find,
163 for (i = 0; i < num_tests; i++) {
164 if (find[i]._todo_wine) {
166 check_EM_FINDTEXT(hwnd, name, &find[i], i);
167 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
170 check_EM_FINDTEXT(hwnd, name, &find[i], i);
171 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
176 static void test_EM_FINDTEXT(void)
178 HWND hwndRichEdit = new_richedit(NULL);
180 /* Empty rich edit control */
181 run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests,
182 sizeof(find_tests)/sizeof(struct find_s));
184 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack);
187 run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2,
188 sizeof(find_tests2)/sizeof(struct find_s));
190 DestroyWindow(hwndRichEdit);
193 static const struct getline_s {
198 {0, 10, "foo bar\r"},
203 /* Buffer smaller than line length */
209 static void test_EM_GETLINE(void)
212 HWND hwndRichEdit = new_richedit(NULL);
213 static const int nBuf = 1024;
214 char dest[1024], origdest[1024];
215 const char text[] = "foo bar\n"
219 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
221 memset(origdest, 0xBB, nBuf);
222 for (i = 0; i < sizeof(gl)/sizeof(struct getline_s); i++)
225 int expected_nCopied = min(gl[i].buffer_len, strlen(gl[i].text));
226 int expected_bytes_written = min(gl[i].buffer_len, strlen(gl[i].text) + 1);
227 memset(dest, 0xBB, nBuf);
228 *(WORD *) dest = gl[i].buffer_len;
230 /* EM_GETLINE appends a "\r\0" to the end of the line
231 * nCopied counts up to and including the '\r' */
232 nCopied = SendMessage(hwndRichEdit, EM_GETLINE, gl[i].line, (LPARAM) dest);
233 ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied,
235 /* two special cases since a parameter is passed via dest */
236 if (gl[i].buffer_len == 0)
237 ok(!dest[0] && !dest[1] && !strncmp(dest+2, origdest+2, nBuf-2),
239 else if (gl[i].buffer_len == 1)
240 ok(dest[0] == gl[i].text[0] && !dest[1] &&
241 !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n");
244 ok(!strncmp(dest, gl[i].text, expected_bytes_written),
245 "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
246 ok(!strncmp(dest + expected_bytes_written, origdest
247 + expected_bytes_written, nBuf - expected_bytes_written),
248 "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
252 DestroyWindow(hwndRichEdit);
255 static int get_scroll_pos_y(HWND hwnd)
258 SendMessage(hwnd, EM_GETSCROLLPOS, 0, (LPARAM) &p);
259 ok(p.x != -1 && p.y != -1, "p.x:%d p.y:%d\n", p.x, p.y);
263 static void move_cursor(HWND hwnd, long charindex)
266 cr.cpMax = charindex;
267 cr.cpMin = charindex;
268 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &cr);
271 static void line_scroll(HWND hwnd, int amount)
273 SendMessage(hwnd, EM_LINESCROLL, 0, amount);
276 static void test_EM_SCROLLCARET(void)
279 HWND hwndRichEdit = new_richedit(NULL);
280 const char text[] = "aa\n"
281 "this is a long line of text that should be longer than the "
290 /* Can't verify this */
291 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
293 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
295 /* Caret above visible window */
296 line_scroll(hwndRichEdit, 3);
297 prevY = get_scroll_pos_y(hwndRichEdit);
298 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
299 curY = get_scroll_pos_y(hwndRichEdit);
300 ok(prevY != curY, "%d == %d\n", prevY, curY);
302 /* Caret below visible window */
303 move_cursor(hwndRichEdit, sizeof(text) - 1);
304 line_scroll(hwndRichEdit, -3);
305 prevY = get_scroll_pos_y(hwndRichEdit);
306 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
307 curY = get_scroll_pos_y(hwndRichEdit);
308 ok(prevY != curY, "%d == %d\n", prevY, curY);
310 /* Caret in visible window */
311 move_cursor(hwndRichEdit, sizeof(text) - 2);
312 prevY = get_scroll_pos_y(hwndRichEdit);
313 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
314 curY = get_scroll_pos_y(hwndRichEdit);
315 ok(prevY == curY, "%d != %d\n", prevY, curY);
317 /* Caret still in visible window */
318 line_scroll(hwndRichEdit, -1);
319 prevY = get_scroll_pos_y(hwndRichEdit);
320 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
321 curY = get_scroll_pos_y(hwndRichEdit);
322 ok(prevY == curY, "%d != %d\n", prevY, curY);
324 DestroyWindow(hwndRichEdit);
327 static void test_EM_SETTEXTMODE(void)
329 HWND hwndRichEdit = new_richedit(NULL);
330 CHARFORMAT2 cf2, cf2test;
334 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
335 /*Insert text into the control*/
337 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
339 /*Attempt to change the control to plain text mode*/
340 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
341 ok(rc != 0, "EM_SETTEXTMODE: changed text mode in control containing text - returned: %d\n", rc);
343 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
344 If rich text is pasted, it should have the same formatting as the rest
345 of the text in the control*/
348 *NOTE: If the default text was already italicized, the test will simply
349 reverse; in other words, it will copy a regular "wine" into a plain
350 text window that uses an italicized format*/
351 cf2.cbSize = sizeof(CHARFORMAT2);
352 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
355 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
356 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
358 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
359 however, SCF_ALL has been implemented*/
360 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
361 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
363 /*Select the string "wine"*/
366 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
368 /*Copy the italicized "wine" to the clipboard*/
369 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
371 /*Reset the formatting to default*/
372 cf2.dwEffects = CFE_ITALIC^cf2.dwEffects;
373 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
375 /*Clear the text in the control*/
376 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
378 /*Switch to Plain Text Mode*/
379 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
380 ok(rc == 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc);
382 /*Input "wine" again in normal format*/
383 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
385 /*Paste the italicized "wine" into the control*/
386 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
388 /*Select a character from the first "wine" string*/
391 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
393 /*Retrieve its formatting*/
394 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
397 /*Select a character from the second "wine" string*/
400 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
402 /*Retrieve its formatting*/
403 cf2test.cbSize = sizeof(CHARFORMAT2);
404 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
407 /*Compare the two formattings*/
408 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
409 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n",
410 cf2.dwEffects, cf2test.dwEffects);
411 /*Test TM_RICHTEXT by: switching back to Rich Text mode
412 printing "wine" in the current format(normal)
413 pasting "wine" from the clipboard(italicized)
414 comparing the two formats(should differ)*/
416 /*Attempt to switch with text in control*/
417 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
418 ok(rc != 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc);
421 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
423 /*Switch into Rich Text mode*/
424 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
425 ok(rc == 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc);
427 /*Print "wine" in normal formatting into the control*/
428 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
430 /*Paste italicized "wine" into the control*/
431 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
433 /*Select text from the first "wine" string*/
436 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
438 /*Retrieve its formatting*/
439 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
442 /*Select text from the second "wine" string*/
445 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
447 /*Retrieve its formatting*/
448 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
451 /*Test that the two formattings are not the same*/
452 todo_wine ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects != cf2test.dwEffects),
453 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
454 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
456 DestroyWindow(hwndRichEdit);
459 static void test_TM_PLAINTEXT(void)
461 /*Tests plain text properties*/
463 HWND hwndRichEdit = new_richedit(NULL);
464 CHARFORMAT2 cf2, cf2test;
467 /*Switch to plain text mode*/
469 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
470 SendMessage(hwndRichEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
472 /*Fill control with text*/
474 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "Is Wine an emulator? No it's not");
476 /*Select some text and bold it*/
480 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
481 cf2.cbSize = sizeof(CHARFORMAT2);
482 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
485 cf2.dwMask = CFM_BOLD | cf2.dwMask;
486 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
488 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
490 /*Get the formatting of those characters*/
492 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
494 /*Get the formatting of some other characters*/
495 cf2test.cbSize = sizeof(CHARFORMAT2);
498 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
499 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
501 /*Test that they are the same as plain text allows only one formatting*/
503 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
504 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
505 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
507 /*Fill the control with a "wine" string, which when inserted will be bold*/
509 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
511 /*Copy the bolded "wine" string*/
515 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
516 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
518 /*Swap back to rich text*/
520 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
521 SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
523 /*Set the default formatting to bold italics*/
525 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT, (LPARAM) &cf2);
526 cf2.dwMask |= CFM_ITALIC;
527 cf2.dwEffects ^= CFE_ITALIC;
528 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
530 /*Set the text in the control to "wine", which will be bold and italicized*/
532 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
534 /*Paste the plain text "wine" string, which should take the insert
535 formatting, which at the moment is bold italics*/
537 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
539 /*Select the first "wine" string and retrieve its formatting*/
543 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
544 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
546 /*Select the second "wine" string and retrieve its formatting*/
550 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
551 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
553 /*Compare the two formattings. They should be the same.*/
555 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
556 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
557 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
558 DestroyWindow(hwndRichEdit);
561 static void test_WM_GETTEXT(void)
563 HWND hwndRichEdit = new_richedit(NULL);
564 static const char text[] = "Hello. My name is RichEdit!";
565 char buffer[1024] = {0};
568 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
569 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
570 result = strcmp(buffer,text);
572 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
573 DestroyWindow(hwndRichEdit);
576 /* FIXME: need to test unimplemented options and robustly test wparam */
577 static void test_EM_SETOPTIONS(void)
579 HWND hwndRichEdit = new_richedit(NULL);
580 static const char text[] = "Hello. My name is RichEdit!";
581 char buffer[1024] = {0};
583 /* NEGATIVE TESTING - NO OPTIONS SET */
584 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
585 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, 0);
587 /* testing no readonly by sending 'a' to the control*/
588 SetFocus(hwndRichEdit);
589 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
590 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
592 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text, buffer);
593 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
595 /* READONLY - sending 'a' to the control */
596 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
597 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, ECO_READONLY);
598 SetFocus(hwndRichEdit);
599 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
600 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
601 ok(buffer[0]==text[0],
602 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer);
604 DestroyWindow(hwndRichEdit);
607 static void check_CFE_LINK_rcvd(HWND hwnd, int is_url)
609 CHARFORMAT2W text_format;
610 int link_present = 0;
611 text_format.cbSize = sizeof(text_format);
612 SendMessage(hwnd, EM_SETSEL, 0, 0);
613 SendMessage(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &text_format);
614 link_present = text_format.dwEffects & CFE_LINK;
616 { /* control text is url; should get CFE_LINK */
617 ok(0 != link_present, "URL Case: CFE_LINK not set.\n");
621 ok(0 == link_present, "Non-URL Case: CFE_LINK set.\n");
625 static HWND new_static_wnd(HWND parent) {
626 return new_window("Static", 0, parent);
629 static void test_EM_AUTOURLDETECT(void)
636 {"http://www.winehq.org", 1},
637 {"http//winehq.org", 0},
638 {"ww.winehq.org", 0},
639 {"www.winehq.org", 1},
640 {"ftp://192.168.1.1", 1},
641 {"ftp//192.168.1.1", 0},
642 {"mailto:your@email.com", 1},
643 {"prospero:prosperoserver", 1},
645 {"news:newserver", 1},
646 {"wais:waisserver", 1}
651 HWND hwndRichEdit, parent;
653 parent = new_static_wnd(NULL);
654 hwndRichEdit = new_richedit(parent);
655 /* Try and pass EM_AUTOURLDETECT some test wParam values */
656 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
657 ok(urlRet==0, "Good wParam: urlRet is: %d\n", urlRet);
658 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 1, 0);
659 ok(urlRet==0, "Good wParam2: urlRet is: %d\n", urlRet);
660 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
661 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 8, 0);
662 ok(urlRet==E_INVALIDARG, "Bad wParam: urlRet is: %d\n", urlRet);
663 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM)"h", (LPARAM)"h");
664 ok(urlRet==E_INVALIDARG, "Bad wParam2: urlRet is: %d\n", urlRet);
665 /* for each url, check the text to see if CFE_LINK effect is present */
666 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) {
667 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
668 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
669 SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
670 check_CFE_LINK_rcvd(hwndRichEdit, 0);
671 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
672 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
673 SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
674 check_CFE_LINK_rcvd(hwndRichEdit, urls[i].is_url);
676 DestroyWindow(hwndRichEdit);
677 DestroyWindow(parent);
680 static void test_EM_SCROLL(void)
683 int r; /* return value */
684 int expr; /* expected return value */
685 HWND hwndRichEdit = new_richedit(NULL);
686 int y_before, y_after; /* units of lines of text */
688 /* test a richedit box containing a single line of text */
689 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a");/* one line of text */
691 for (i = 0; i < 4; i++) {
692 static const int cmd[4] = { SB_PAGEDOWN, SB_PAGEUP, SB_LINEDOWN, SB_LINEUP };
694 r = SendMessage(hwndRichEdit, EM_SCROLL, cmd[i], 0);
695 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
696 ok(expr == r, "EM_SCROLL improper return value returned (i == %d). "
697 "Got 0x%08x, expected 0x%08x\n", i, r, expr);
698 ok(y_after == 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
699 "(i == %d)\n", y_after, i);
703 * test a richedit box that will scroll. There are two general
704 * cases: the case without any long lines and the case with a long
707 for (i = 0; i < 2; i++) { /* iterate through different bodies of text */
709 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a\nb\nc\nd\ne");
711 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)
712 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
713 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
714 "LONG LINE \nb\nc\nd\ne");
715 for (j = 0; j < 12; j++) /* reset scrol position to top */
716 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0);
718 /* get first visible line */
719 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
720 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); /* page down */
722 /* get new current first visible line */
723 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
725 ok(((r & 0xffffff00) == 0x00010000) &&
726 ((r & 0x000000ff) != 0x00000000),
727 "EM_SCROLL page down didn't scroll by a small positive number of "
728 "lines (r == 0x%08x)\n", r);
729 ok(y_after > y_before, "EM_SCROLL page down not functioning "
730 "(line %d scrolled to line %d\n", y_before, y_after);
734 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); /* page up */
735 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
736 ok(((r & 0xffffff00) == 0x0001ff00),
737 "EM_SCROLL page up didn't scroll by a small negative number of lines "
738 "(r == 0x%08x)\n", r);
739 ok(y_after < y_before, "EM_SCROLL page up not functioning (line "
740 "%d scrolled to line %d\n", y_before, y_after);
744 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
746 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
748 ok(r == 0x00010001, "EM_SCROLL line down didn't scroll by one line "
749 "(r == 0x%08x)\n", r);
750 ok(y_after -1 == y_before, "EM_SCROLL line down didn't go down by "
751 "1 line (%d scrolled to %d)\n", y_before, y_after);
755 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
757 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
759 ok(r == 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
760 "(r == 0x%08x)\n", r);
761 ok(y_after +1 == y_before, "EM_SCROLL line up didn't go up by 1 "
762 "line (%d scrolled to %d)\n", y_before, y_after);
766 r = SendMessage(hwndRichEdit, EM_SCROLL,
767 SB_LINEUP, 0); /* lineup beyond top */
769 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
772 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r);
773 ok(y_before == y_after,
774 "EM_SCROLL line up beyond top worked (%d)\n", y_after);
778 r = SendMessage(hwndRichEdit, EM_SCROLL,
779 SB_PAGEUP, 0);/*page up beyond top */
781 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
784 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r);
785 ok(y_before == y_after,
786 "EM_SCROLL page up beyond top worked (%d)\n", y_after);
788 for (j = 0; j < 12; j++) /* page down all the way to the bottom */
789 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0);
790 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
791 r = SendMessage(hwndRichEdit, EM_SCROLL,
792 SB_PAGEDOWN, 0); /* page down beyond bot */
793 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
796 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r);
797 ok(y_before == y_after,
798 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
801 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
802 SendMessage(hwndRichEdit, EM_SCROLL,
803 SB_LINEDOWN, 0); /* line down beyond bot */
804 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
807 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r);
808 ok(y_before == y_after,
809 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
812 DestroyWindow(hwndRichEdit);
815 static void test_EM_SETUNDOLIMIT(void)
817 /* cases we test for:
818 * default behaviour - limiting at 100 undo's
819 * undo disabled - setting a limit of 0
820 * undo limited - undo limit set to some to some number, like 2
821 * bad input - sending a negative number should default to 100 undo's */
823 HWND hwndRichEdit = new_richedit(NULL);
828 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
831 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
832 /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
833 also, multiple pastes don't combine like WM_CHAR would */
834 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
836 /* first case - check the default */
837 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
838 for (i=0; i<101; i++) /* Put 101 undo's on the stack */
839 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
840 for (i=0; i<100; i++) /* Undo 100 of them */
841 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
842 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
843 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
845 /* second case - cannot undo */
846 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
847 SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, 0, 0);
848 SendMessage(hwndRichEdit,
849 WM_PASTE, 0, 0); /* Try to put something in the undo stack */
850 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
851 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
853 /* third case - set it to an arbitrary number */
854 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
855 SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, 2, 0);
856 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
857 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
858 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
859 /* If SETUNDOLIMIT is working, there should only be two undo's after this */
860 ok(SendMessage(hwndRichEdit, EM_CANUNDO, 0,0),
861 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
862 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
863 ok(SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
864 "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
865 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
866 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
867 "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
869 /* fourth case - setting negative numbers should default to 100 undos */
870 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
871 result = SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, -1, 0);
873 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result);
875 DestroyWindow(hwndRichEdit);
878 static void test_ES_PASSWORD(void)
880 /* This isn't hugely testable, so we're just going to run it through it's paces. */
882 HWND hwndRichEdit = new_richedit(NULL);
885 /* First, check the default of a regular control */
886 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
888 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result);
890 /* Now, set it to something normal */
891 SendMessage(hwndRichEdit, EM_SETPASSWORDCHAR, 'x', 0);
892 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
894 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
896 /* Now, set it to something odd */
897 SendMessage(hwndRichEdit, EM_SETPASSWORDCHAR, (WCHAR)1234, 0);
898 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
900 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
901 DestroyWindow(hwndRichEdit);
904 static void test_EM_SETTEXTEX(void)
906 HWND hwndRichEdit = new_richedit(NULL);
909 WCHAR TestItem1[] = {'T', 'e', 's', 't',
911 'T', 'e', 'x', 't', 0};
912 #define MAX_BUF_LEN 1024
913 WCHAR buf[MAX_BUF_LEN];
917 setText.codepage = 1200; /* no constant for unicode */
918 getText.codepage = 1200; /* no constant for unicode */
919 getText.cb = MAX_BUF_LEN;
920 getText.flags = GT_DEFAULT;
923 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
924 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
925 ok(lstrcmpW(buf, TestItem1) == 0,
926 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
928 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
929 (WPARAM)&setText, (LPARAM) NULL);
930 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
933 "EM_SETTEXTEX returned %d, instead of 1\n",result);
934 ok(lstrlenW(buf) == 0,
935 "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
937 /* put some text back */
939 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
940 /* select some text */
943 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
944 /* replace current selection */
945 setText.flags = ST_SELECTION;
946 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
947 (WPARAM)&setText, (LPARAM) NULL);
949 "EM_SETTEXTEX with NULL lParam to replace selection"
950 " with no text should return 0. Got %i\n",
953 /* put some text back */
955 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
956 /* select some text */
959 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
960 /* replace current selection */
961 setText.flags = ST_SELECTION;
962 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
963 (WPARAM)&setText, (LPARAM) TestItem1);
965 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
966 ok(result == lstrlenW(TestItem1),
967 "EM_SETTEXTEX with NULL lParam to replace selection"
968 " with no text should return 0. Got %i\n",
970 ok(lstrlenW(buf) == 22,
971 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
974 DestroyWindow(hwndRichEdit);
978 static void test_EM_EXLIMITTEXT(void)
980 int i, selBegin, selEnd, len1, len2;
982 int textlimit = 0; /* multiple of 100 */
983 HWND hwndRichEdit = new_richedit(NULL);
985 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
986 ok(32767 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i); /* default */
989 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
990 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
992 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
995 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
996 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
998 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
1000 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, 0);
1001 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1002 /* default for WParam = 0 */
1003 ok(65536 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i);
1005 textlimit = sizeof(text)-1;
1006 memset(text, 'W', textlimit);
1007 text[sizeof(text)-1] = 0;
1008 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1009 /* maxed out text */
1010 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1012 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */
1013 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1014 len1 = selEnd - selBegin;
1016 SendMessage(hwndRichEdit, WM_KEYDOWN, VK_BACK, 1);
1017 SendMessage(hwndRichEdit, WM_CHAR, VK_BACK, 1);
1018 SendMessage(hwndRichEdit, WM_KEYUP, VK_BACK, 1);
1019 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1020 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1021 len2 = selEnd - selBegin;
1024 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1027 SendMessage(hwndRichEdit, WM_KEYDOWN, 'A', 1);
1028 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1029 SendMessage(hwndRichEdit, WM_KEYUP, 'A', 1);
1030 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1031 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1032 len1 = selEnd - selBegin;
1035 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1038 SendMessage(hwndRichEdit, WM_KEYDOWN, 'A', 1);
1039 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1040 SendMessage(hwndRichEdit, WM_KEYUP, 'A', 1); /* full; should be no effect */
1041 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1042 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1043 len2 = selEnd - selBegin;
1046 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1049 DestroyWindow(hwndRichEdit);
1052 static void test_EM_GETLIMITTEXT(void)
1055 HWND hwndRichEdit = new_richedit(NULL);
1057 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1058 ok(32767 == i, "expected: %d, actual: %d\n", 32767, i); /* default value */
1060 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, 50000);
1061 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1062 ok(50000 == i, "expected: %d, actual: %d\n", 50000, i);
1064 DestroyWindow(hwndRichEdit);
1067 static void test_WM_SETFONT(void)
1069 /* There is no invalid input or error conditions for this function.
1070 * NULL wParam and lParam just fall back to their default values
1071 * It should be noted that even if you use a gibberish name for your fonts
1072 * here, it will still work because the name is stored. They will display as
1073 * System, but will report their name to be whatever they were created as */
1075 HWND hwndRichEdit = new_richedit(NULL);
1076 HFONT testFont1 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1077 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1078 FF_DONTCARE, "Marlett");
1079 HFONT testFont2 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1080 OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1081 FF_DONTCARE, "MS Sans Serif");
1082 HFONT testFont3 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1083 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1084 FF_DONTCARE, "Courier");
1085 LOGFONTA sentLogFont;
1086 CHARFORMAT2A returnedCF2A;
1088 returnedCF2A.cbSize = sizeof(returnedCF2A);
1090 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
1091 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont1,(LPARAM) MAKELONG((WORD) TRUE, 0));
1092 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1094 GetObjectA(testFont1, sizeof(LOGFONTA), &sentLogFont);
1095 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1096 "EM_GETCHARFOMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
1097 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1099 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont2,(LPARAM) MAKELONG((WORD) TRUE, 0));
1100 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1101 GetObjectA(testFont2, sizeof(LOGFONTA), &sentLogFont);
1102 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1103 "EM_GETCHARFOMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
1104 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1106 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont3,(LPARAM) MAKELONG((WORD) TRUE, 0));
1107 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1108 GetObjectA(testFont3, sizeof(LOGFONTA), &sentLogFont);
1109 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1110 "EM_GETCHARFOMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
1111 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1113 /* This last test is special since we send in NULL. We clear the variables
1114 * and just compare to "System" instead of the sent in font name. */
1115 ZeroMemory(&returnedCF2A,sizeof(returnedCF2A));
1116 ZeroMemory(&sentLogFont,sizeof(sentLogFont));
1117 returnedCF2A.cbSize = sizeof(returnedCF2A);
1119 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)NULL,(LPARAM) MAKELONG((WORD) TRUE, 0));
1120 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1121 GetObjectA(NULL, sizeof(LOGFONTA), &sentLogFont);
1122 ok (!strcmp("System",returnedCF2A.szFaceName),
1123 "EM_GETCHARFOMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A.szFaceName);
1125 DestroyWindow(hwndRichEdit);
1129 static DWORD CALLBACK test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie,
1134 const char** str = (const char**)dwCookie;
1135 int size = strlen(*str);
1136 if(size > 3) /* let's make it peice-meal for fun */
1143 memcpy(pbBuff, *str, *pcb);
1149 static void test_EM_GETMODIFY(void)
1151 HWND hwndRichEdit = new_richedit(NULL);
1154 WCHAR TestItem1[] = {'T', 'e', 's', 't',
1156 'T', 'e', 'x', 't', 0};
1157 WCHAR TestItem2[] = {'T', 'e', 's', 't',
1159 'O', 't', 'h', 'e', 'r',
1160 'T', 'e', 'x', 't', 0};
1161 const char* streamText = "hello world";
1166 HFONT testFont = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1167 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1168 FF_DONTCARE, "Courier");
1170 setText.codepage = 1200; /* no constant for unicode */
1171 setText.flags = ST_KEEPUNDO;
1174 /* modify flag shouldn't be set when richedit is first created */
1175 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1177 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
1179 /* setting modify flag should actually set it */
1180 SendMessage(hwndRichEdit, EM_SETMODIFY, TRUE, 0);
1181 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1183 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
1185 /* clearing modify flag should actually clear it */
1186 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1187 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1189 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
1191 /* setting font doesn't change modify flag */
1192 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1193 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont,(LPARAM) MAKELONG((WORD) TRUE, 0));
1194 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1196 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
1198 /* setting text should set modify flag */
1199 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1200 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1201 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1203 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
1205 /* undo previous text doesn't reset modify flag */
1206 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
1207 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1209 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
1211 /* set text with no flag to keep undo stack should not set modify flag */
1212 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1214 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1215 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1217 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
1219 /* WM_SETTEXT doesn't modify */
1220 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1221 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2);
1222 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1225 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
1228 /* clear the text */
1229 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1230 SendMessage(hwndRichEdit, WM_CLEAR, 0, 0);
1231 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1233 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
1236 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1237 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1238 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1239 SendMessage(hwndRichEdit, EM_REPLACESEL, TRUE, (LPARAM)TestItem2);
1240 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1242 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
1244 /* copy/paste text 1 */
1245 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1246 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1247 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1248 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1249 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1251 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
1253 /* copy/paste text 2 */
1254 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1255 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1256 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1257 SendMessage(hwndRichEdit, EM_SETSEL, 0, 3);
1258 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1259 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1261 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
1264 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1265 SendMessage(hwndRichEdit, EM_SETSEL, 0, 1);
1266 SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1267 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1269 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
1271 /* set char format */
1272 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1273 cf2.cbSize = sizeof(CHARFORMAT2);
1274 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
1276 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
1277 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
1278 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
1279 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1281 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
1283 /* set para format */
1284 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1285 pf2.cbSize = sizeof(PARAFORMAT2);
1286 SendMessage(hwndRichEdit, EM_GETPARAFORMAT, 0,
1288 pf2.dwMask = PFM_ALIGNMENT | pf2.dwMask;
1289 pf2.wAlignment = PFA_RIGHT;
1290 SendMessage(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM) &pf2);
1291 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1293 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
1296 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1297 es.dwCookie = (DWORD_PTR)&streamText;
1299 es.pfnCallback = test_EM_GETMODIFY_esCallback;
1300 SendMessage(hwndRichEdit, EM_STREAMIN,
1301 (WPARAM)(SF_TEXT), (LPARAM)&es);
1302 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1304 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
1306 DestroyWindow(hwndRichEdit);
1312 long expected_retval;
1313 int expected_getsel_start;
1314 int expected_getsel_end;
1315 int _exsetsel_todo_wine;
1316 int _getsel_todo_wine;
1319 const struct exsetsel_s exsetsel_tests[] = {
1321 {5, 10, 10, 5, 10, 0, 0},
1322 {15, 17, 17, 15, 17, 0, 0},
1323 /* test cpMax > strlen() */
1324 {0, 100, 18, 0, 18, 0, 1},
1325 /* test cpMin == cpMax */
1326 {5, 5, 5, 5, 5, 0, 0},
1327 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
1328 {-1, 0, 5, 5, 5, 0, 0},
1329 {-1, 17, 5, 5, 5, 0, 0},
1330 {-1, 18, 5, 5, 5, 0, 0},
1331 /* test cpMin < 0 && cpMax < 0 */
1332 {-1, -1, 17, 17, 17, 0, 0},
1333 {-4, -5, 17, 17, 17, 0, 0},
1334 /* test cMin >=0 && cpMax < 0 (bug 6814) */
1335 {0, -1, 18, 0, 18, 0, 1},
1336 {17, -5, 18, 17, 18, 0, 1},
1337 {18, -3, 17, 17, 17, 0, 0},
1338 /* test if cpMin > cpMax */
1339 {15, 19, 18, 15, 18, 0, 1},
1340 {19, 15, 18, 15, 18, 0, 1}
1343 static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) {
1348 cr.cpMin = setsel->min;
1349 cr.cpMax = setsel->max;
1350 result = SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &cr);
1352 if (setsel->_exsetsel_todo_wine) {
1354 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1357 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1360 SendMessage(hwnd, EM_GETSEL, (WPARAM) &start, (LPARAM) &end);
1362 if (setsel->_getsel_todo_wine) {
1364 ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end);
1367 ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end);
1371 static void test_EM_EXSETSEL(void)
1373 HWND hwndRichEdit = new_richedit(NULL);
1375 const int num_tests = sizeof(exsetsel_tests)/sizeof(struct exsetsel_s);
1377 /* sending some text to the window */
1378 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "testing selection");
1379 /* 01234567890123456*/
1382 for (i = 0; i < num_tests; i++) {
1383 check_EM_EXSETSEL(hwndRichEdit, &exsetsel_tests[i], i);
1386 DestroyWindow(hwndRichEdit);
1389 START_TEST( editor )
1394 /* Must explicitly LoadLibrary(). The test has no references to functions in
1395 * RICHED20.DLL, so the linker doesn't actually link to it. */
1396 hmoduleRichEdit = LoadLibrary("RICHED20.DLL");
1397 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
1400 test_EM_SCROLLCARET();
1402 test_EM_SETTEXTMODE();
1403 test_TM_PLAINTEXT();
1404 test_EM_SETOPTIONS();
1406 test_EM_AUTOURLDETECT();
1407 test_EM_SETUNDOLIMIT();
1409 test_EM_SETTEXTEX();
1410 test_EM_EXLIMITTEXT();
1411 test_EM_GETLIMITTEXT();
1413 test_EM_GETMODIFY();
1416 /* Set the environment variable WINETEST_RICHED20 to keep windows
1417 * responsive and open for 30 seconds. This is useful for debugging.
1419 * The message pump uses PeekMessage() to empty the queue and then sleeps for
1420 * 50ms before retrying the queue. */
1421 end = time(NULL) + 30;
1422 if (getenv( "WINETEST_RICHED20" )) {
1423 while (time(NULL) < end) {
1424 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1425 TranslateMessage(&msg);
1426 DispatchMessage(&msg);
1433 OleFlushClipboard();
1434 ok(FreeLibrary(hmoduleRichEdit) != 0, "error: %d\n", (int) GetLastError());