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 %ld\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 %ld\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:%ld p.y:%ld\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: %lx cf2test.dwEffects: %lx\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: %lx, cf2test.dwMask: %lx, cf2.dwEffects: %lx, cf2test.dwEffects: %lx\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: %lx, cf2test.dwMask %lx, cf2.dwEffects: %lx, cf2test.dwEffects: %lx\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: %lx, cf2test.dwMask: %lx, cf2.dwEffects: %lx, cf2test.dwEffects: %lx\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);
575 /* FIXME: need to test unimplemented options and robustly test wparam */
576 static void test_EM_SETOPTIONS(void)
578 HWND hwndRichEdit = new_richedit(NULL);
579 static const char text[] = "Hello. My name is RichEdit!";
580 char buffer[1024] = {0};
582 /* NEGATIVE TESTING - NO OPTIONS SET */
583 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
584 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, 0);
586 /* testing no readonly by sending 'a' to the control*/
587 SetFocus(hwndRichEdit);
588 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
589 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
591 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text, buffer);
592 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
594 /* READONLY - sending 'a' to the control */
595 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
596 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, ECO_READONLY);
597 SetFocus(hwndRichEdit);
598 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
599 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
600 ok(buffer[0]==text[0],
601 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer);
603 DestroyWindow(hwndRichEdit);
606 static void check_CFE_LINK_rcvd(HWND hwnd, int is_url)
608 CHARFORMAT2W text_format;
609 int link_present = 0;
610 text_format.cbSize = sizeof(text_format);
611 SendMessage(hwnd, EM_SETSEL, 0, 0);
612 SendMessage(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &text_format);
613 link_present = text_format.dwEffects & CFE_LINK;
615 { /* control text is url; should get CFE_LINK */
616 ok(0 != link_present, "URL Case: CFE_LINK not set.\n");
620 ok(0 == link_present, "Non-URL Case: CFE_LINK set.\n");
624 static HWND new_static_wnd(HWND parent) {
625 return new_window("Static", 0, parent);
628 static void test_EM_AUTOURLDETECT(void)
635 {"http://www.winehq.org", 1},
636 {"http//winehq.org", 0},
637 {"ww.winehq.org", 0},
638 {"www.winehq.org", 1},
639 {"ftp://192.168.1.1", 1},
640 {"ftp//192.168.1.1", 0},
641 {"mailto:your@email.com", 1},
642 {"prospero:prosperoserver", 1},
644 {"news:newserver", 1},
645 {"wais:waisserver", 1}
650 HWND hwndRichEdit, parent;
652 parent = new_static_wnd(NULL);
653 hwndRichEdit = new_richedit(parent);
654 /* Try and pass EM_AUTOURLDETECT some test wParam values */
655 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
656 ok(urlRet==0, "Good wParam: urlRet is: %d\n", urlRet);
657 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 1, 0);
658 ok(urlRet==0, "Good wParam2: urlRet is: %d\n", urlRet);
659 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
660 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 8, 0);
661 ok(urlRet==E_INVALIDARG, "Bad wParam: urlRet is: %d\n", urlRet);
662 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM)"h", (LPARAM)"h");
663 ok(urlRet==E_INVALIDARG, "Bad wParam2: urlRet is: %d\n", urlRet);
664 /* for each url, check the text to see if CFE_LINK effect is present */
665 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) {
666 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
667 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
668 SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
669 check_CFE_LINK_rcvd(hwndRichEdit, 0);
670 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
671 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
672 SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
673 check_CFE_LINK_rcvd(hwndRichEdit, urls[i].is_url);
675 DestroyWindow(hwndRichEdit);
676 DestroyWindow(parent);
679 static void test_EM_SCROLL(void)
682 int r; /* return value */
683 int expr; /* expected return value */
684 HWND hwndRichEdit = new_richedit(NULL);
685 int y_before, y_after; /* units of lines of text */
687 /* test a richedit box containing a single line of text */
688 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a");/* one line of text */
690 for (i = 0; i < 4; i++) {
691 static const int cmd[4] = { SB_PAGEDOWN, SB_PAGEUP, SB_LINEDOWN, SB_LINEUP };
693 r = SendMessage(hwndRichEdit, EM_SCROLL, cmd[i], 0);
694 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
695 ok(expr == r, "EM_SCROLL improper return value returned (i == %d). "
696 "Got 0x%08x, expected 0x%08x\n", i, r, expr);
697 ok(y_after == 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
698 "(i == %d)\n", y_after, i);
702 * test a richedit box that will scroll. There are two general
703 * cases: the case without any long lines and the case with a long
706 for (i = 0; i < 2; i++) { /* iterate through different bodies of text */
708 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a\nb\nc\nd\ne");
710 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)
711 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
712 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
713 "LONG LINE \nb\nc\nd\ne");
714 for (j = 0; j < 12; j++) /* reset scrol position to top */
715 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0);
717 /* get first visible line */
718 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
719 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); /* page down */
721 /* get new current first visible line */
722 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
724 ok(((r & 0xffffff00) == 0x00010000) &&
725 ((r & 0x000000ff) != 0x00000000),
726 "EM_SCROLL page down didn't scroll by a small positive number of "
727 "lines (r == 0x%08x)\n", r);
728 ok(y_after > y_before, "EM_SCROLL page down not functioning "
729 "(line %d scrolled to line %d\n", y_before, y_after);
733 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); /* page up */
734 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
735 ok(((r & 0xffffff00) == 0x0001ff00),
736 "EM_SCROLL page up didn't scroll by a small negative number of lines "
737 "(r == 0x%08x)\n", r);
738 ok(y_after < y_before, "EM_SCROLL page up not functioning (line "
739 "%d scrolled to line %d\n", y_before, y_after);
743 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
745 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
747 ok(r == 0x00010001, "EM_SCROLL line down didn't scroll by one line "
748 "(r == 0x%08x)\n", r);
749 ok(y_after -1 == y_before, "EM_SCROLL line down didn't go down by "
750 "1 line (%d scrolled to %d)\n", y_before, y_after);
754 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
756 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
758 ok(r == 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
759 "(r == 0x%08x)\n", r);
760 ok(y_after +1 == y_before, "EM_SCROLL line up didn't go up by 1 "
761 "line (%d scrolled to %d)\n", y_before, y_after);
765 r = SendMessage(hwndRichEdit, EM_SCROLL,
766 SB_LINEUP, 0); /* lineup beyond top */
768 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
771 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r);
772 ok(y_before == y_after,
773 "EM_SCROLL line up beyond top worked (%d)\n", y_after);
777 r = SendMessage(hwndRichEdit, EM_SCROLL,
778 SB_PAGEUP, 0);/*page up beyond top */
780 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
783 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r);
784 ok(y_before == y_after,
785 "EM_SCROLL page up beyond top worked (%d)\n", y_after);
787 for (j = 0; j < 12; j++) /* page down all the way to the bottom */
788 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0);
789 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
790 r = SendMessage(hwndRichEdit, EM_SCROLL,
791 SB_PAGEDOWN, 0); /* page down beyond bot */
792 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
795 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r);
796 ok(y_before == y_after,
797 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
800 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
801 SendMessage(hwndRichEdit, EM_SCROLL,
802 SB_LINEDOWN, 0); /* line down beyond bot */
803 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
806 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r);
807 ok(y_before == y_after,
808 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
811 DestroyWindow(hwndRichEdit);
814 static void test_EM_SETUNDOLIMIT(void)
816 /* cases we test for:
817 * default behaviour - limiting at 100 undo's
818 * undo disabled - setting a limit of 0
819 * undo limited - undo limit set to some to some number, like 2
820 * bad input - sending a negative number should default to 100 undo's */
822 HWND hwndRichEdit = new_richedit(NULL);
827 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
830 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
831 /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
832 also, multiple pastes don't combine like WM_CHAR would */
833 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
835 /* first case - check the default */
836 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
837 for (i=0; i<101; i++) /* Put 101 undo's on the stack */
838 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
839 for (i=0; i<100; i++) /* Undo 100 of them */
840 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
841 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
842 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
844 /* second case - cannot undo */
845 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
846 SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, 0, 0);
847 SendMessage(hwndRichEdit,
848 WM_PASTE, 0, 0); /* Try to put something in the undo stack */
849 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
850 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
852 /* third case - set it to an arbitrary number */
853 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
854 SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, 2, 0);
855 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
856 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
857 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
858 /* If SETUNDOLIMIT is working, there should only be two undo's after this */
859 ok(SendMessage(hwndRichEdit, EM_CANUNDO, 0,0),
860 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
861 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
862 ok(SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
863 "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
864 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
865 ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
866 "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
868 /* fourth case - setting negative numbers should default to 100 undos */
869 SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
870 result = SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, -1, 0);
872 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result);
874 DestroyWindow(hwndRichEdit);
877 static void test_ES_PASSWORD()
879 /* This isn't hugely testable, so we're just going to run it through it's paces. */
881 HWND hwndRichEdit = new_richedit(NULL);
884 /* First, check the default of a regular control */
885 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
887 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result);
889 /* Now, set it to something normal */
890 SendMessage(hwndRichEdit, EM_SETPASSWORDCHAR, 'x', 0);
891 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
893 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
895 /* Now, set it to something odd */
896 SendMessage(hwndRichEdit, EM_SETPASSWORDCHAR, (WCHAR)1234, 0);
897 result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
899 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
902 static void test_EM_SETTEXTEX()
904 HWND hwndRichEdit = new_richedit(NULL);
907 WCHAR TestItem1[] = {'T', 'e', 's', 't',
909 'T', 'e', 'x', 't', 0};
910 #define MAX_BUF_LEN 1024
911 WCHAR buf[MAX_BUF_LEN];
915 setText.codepage = 1200; /* no constant for unicode */
916 getText.codepage = 1200; /* no constant for unicode */
917 getText.cb = MAX_BUF_LEN;
918 getText.flags = GT_DEFAULT;
921 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
922 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
923 ok(lstrcmpW(buf, TestItem1) == 0,
924 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
926 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
927 (WPARAM)&setText, (LPARAM) NULL);
928 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
931 "EM_SETTEXTEX returned %d, instead of 1\n",result);
932 ok(lstrlenW(buf) == 0,
933 "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
935 /* put some text back */
937 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
938 /* select some text */
941 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
942 /* replace current selection */
943 setText.flags = ST_SELECTION;
944 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
945 (WPARAM)&setText, (LPARAM) NULL);
947 "EM_SETTEXTEX with NULL lParam to replace selection"
948 " with no text should return 0. Got %i\n",
951 /* put some text back */
953 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
954 /* select some text */
957 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
958 /* replace current selection */
959 setText.flags = ST_SELECTION;
960 result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
961 (WPARAM)&setText, (LPARAM) TestItem1);
963 SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
964 ok(result == lstrlenW(TestItem1),
965 "EM_SETTEXTEX with NULL lParam to replace selection"
966 " with no text should return 0. Got %i\n",
968 ok(lstrlenW(buf) == 22,
969 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
972 DestroyWindow(hwndRichEdit);
976 static void test_EM_EXLIMITTEXT(void)
978 int i, selBegin, selEnd, len1, len2;
980 char text[BUFSIZE+1];
981 int textlimit = 0; /* multiple of 100 */
982 HWND hwndRichEdit = new_richedit(NULL);
984 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
985 ok(32767 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i); /* default */
988 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
989 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
991 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
994 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
995 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
997 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
999 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, 0);
1000 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1001 /* default for WParam = 0 */
1002 ok(65536 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i);
1004 textlimit = BUFSIZE;
1005 memset(text, 'W', textlimit);
1007 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1008 /* maxed out text */
1009 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1011 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */
1012 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1013 len1 = selEnd - selBegin;
1015 SendMessage(hwndRichEdit, WM_KEYDOWN, VK_BACK, 1);
1016 SendMessage(hwndRichEdit, WM_CHAR, VK_BACK, 1);
1017 SendMessage(hwndRichEdit, WM_KEYUP, VK_BACK, 1);
1018 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1019 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1020 len2 = selEnd - selBegin;
1023 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1026 SendMessage(hwndRichEdit, WM_KEYDOWN, 'A', 1);
1027 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1028 SendMessage(hwndRichEdit, WM_KEYUP, 'A', 1);
1029 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1030 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1031 len1 = selEnd - selBegin;
1034 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1037 SendMessage(hwndRichEdit, WM_KEYDOWN, 'A', 1);
1038 SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1039 SendMessage(hwndRichEdit, WM_KEYUP, 'A', 1); /* full; should be no effect */
1040 SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1041 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1042 len2 = selEnd - selBegin;
1045 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1048 DestroyWindow(hwndRichEdit);
1051 static void test_EM_GETLIMITTEXT(void)
1054 HWND hwndRichEdit = new_richedit(NULL);
1056 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1057 ok(32767 == i, "expected: %d, actual: %d\n", 32767, i); /* default value */
1059 SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, 50000);
1060 i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1061 ok(50000 == i, "expected: %d, actual: %d\n", 50000, i);
1063 DestroyWindow(hwndRichEdit);
1066 static void test_WM_SETFONT()
1068 /* There is no invalid input or error conditions for this function.
1069 * NULL wParam and lParam just fall back to their default values
1070 * It should be noted that even if you use a gibberish name for your fonts
1071 * here, it will still work because the name is stored. They will display as
1072 * System, but will report their name to be whatever they were created as */
1074 HWND hwndRichEdit = new_richedit(NULL);
1075 HFONT testFont1 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1076 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1077 FF_DONTCARE, "Marlett");
1078 HFONT testFont2 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1079 OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1080 FF_DONTCARE, "MS Sans Serif");
1081 HFONT testFont3 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1082 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1083 FF_DONTCARE, "Courier");
1084 LOGFONTA sentLogFont;
1085 CHARFORMAT2A returnedCF2A;
1087 returnedCF2A.cbSize = sizeof(returnedCF2A);
1089 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
1090 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont1,(LPARAM) MAKELONG((WORD) TRUE, 0));
1091 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1093 GetObjectA(testFont1, sizeof(LOGFONTA), &sentLogFont);
1094 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1095 "EM_GETCHARFOMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
1096 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1098 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont2,(LPARAM) MAKELONG((WORD) TRUE, 0));
1099 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1100 GetObjectA(testFont2, sizeof(LOGFONTA), &sentLogFont);
1101 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1102 "EM_GETCHARFOMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
1103 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1105 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont3,(LPARAM) MAKELONG((WORD) TRUE, 0));
1106 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1107 GetObjectA(testFont3, sizeof(LOGFONTA), &sentLogFont);
1108 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1109 "EM_GETCHARFOMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
1110 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1112 /* This last test is special since we send in NULL. We clear the variables
1113 * and just compare to "System" instead of the sent in font name. */
1114 ZeroMemory(&returnedCF2A,sizeof(returnedCF2A));
1115 ZeroMemory(&sentLogFont,sizeof(sentLogFont));
1116 returnedCF2A.cbSize = sizeof(returnedCF2A);
1118 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)NULL,(LPARAM) MAKELONG((WORD) TRUE, 0));
1119 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &returnedCF2A);
1120 GetObjectA(NULL, sizeof(LOGFONTA), &sentLogFont);
1121 ok (!strcmp("System",returnedCF2A.szFaceName),
1122 "EM_GETCHARFOMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A.szFaceName);
1124 DestroyWindow(hwndRichEdit);
1128 static DWORD CALLBACK test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie,
1133 const char** str = (const char**)dwCookie;
1134 int size = strlen(*str);
1135 if(size > 3) /* let's make it peice-meal for fun */
1142 memcpy(pbBuff, *str, *pcb);
1148 static void test_EM_GETMODIFY(void)
1150 HWND hwndRichEdit = new_richedit(NULL);
1153 WCHAR TestItem1[] = {'T', 'e', 's', 't',
1155 'T', 'e', 'x', 't', 0};
1156 WCHAR TestItem2[] = {'T', 'e', 's', 't',
1158 'O', 't', 'h', 'e', 'r',
1159 'T', 'e', 'x', 't', 0};
1160 const char* streamText = "hello world";
1165 HFONT testFont = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
1166 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH |
1167 FF_DONTCARE, "Courier");
1169 setText.codepage = 1200; /* no constant for unicode */
1170 setText.flags = ST_KEEPUNDO;
1173 /* modify flag shouldn't be set when richedit is first created */
1174 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1176 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
1178 /* setting modify flag should actually set it */
1179 SendMessage(hwndRichEdit, EM_SETMODIFY, TRUE, 0);
1180 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1182 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
1184 /* clearing modify flag should actually clear it */
1185 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1186 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1188 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
1190 /* setting font doesn't change modify flag */
1191 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1192 SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont,(LPARAM) MAKELONG((WORD) TRUE, 0));
1193 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1196 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
1199 /* setting text should set modify flag */
1200 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1201 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1202 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1204 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
1206 /* undo previous text doesn't reset modify flag */
1207 SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
1208 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1211 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
1214 /* set text with no flag to keep undo stack should not set modify flag */
1215 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1217 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1218 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1221 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
1224 /* WM_SETTEXT doesn't modify */
1225 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1226 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2);
1227 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1230 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
1233 /* clear the text */
1234 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1235 SendMessage(hwndRichEdit, WM_CLEAR, 0, 0);
1236 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1238 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
1241 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1242 SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1243 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1244 SendMessage(hwndRichEdit, EM_REPLACESEL, TRUE, (LPARAM)TestItem2);
1245 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1247 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
1249 /* copy/paste text 1 */
1250 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1251 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1252 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1253 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1254 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1256 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
1258 /* copy/paste text 2 */
1259 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1260 SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1261 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1262 SendMessage(hwndRichEdit, EM_SETSEL, 0, 3);
1263 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1264 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1266 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
1269 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1270 SendMessage(hwndRichEdit, EM_SETSEL, 0, 1);
1271 SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1272 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1274 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
1276 /* set char format */
1277 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1278 cf2.cbSize = sizeof(CHARFORMAT2);
1279 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
1281 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
1282 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
1283 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
1284 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1286 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
1288 /* set para format */
1289 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1290 pf2.cbSize = sizeof(PARAFORMAT2);
1291 SendMessage(hwndRichEdit, EM_GETPARAFORMAT, 0,
1293 pf2.dwMask = PFM_ALIGNMENT | pf2.dwMask;
1294 pf2.wAlignment = PFA_RIGHT;
1295 SendMessage(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM) &pf2);
1296 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1299 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
1303 SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1304 es.dwCookie = (DWORD_PTR)&streamText;
1306 es.pfnCallback = test_EM_GETMODIFY_esCallback;
1307 SendMessage(hwndRichEdit, EM_STREAMIN,
1308 (WPARAM)(SF_TEXT), (LPARAM)&es);
1309 result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1312 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
1316 DestroyWindow(hwndRichEdit);
1319 static void test_EM_EXSETSEL(void)
1321 HWND hwndRichEdit = new_richedit(NULL);
1326 /* sending some text to the window */
1327 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "testing selection");
1328 /* 01234567890123456*/
1331 /* EM_EXSETSEL returns (cr.cpMax < strlen+1 ? cr.cpMax:strlen+1 if cpMin is positive */
1334 result = SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1335 ok(result == 18, "EM_EXSETSEL: expected: 18 actual: %ld\n", result);
1336 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM) &start, (LPARAM) &end);
1338 /* FIXME: EM_GETSEL needs to return proper ending value */
1341 ok(start == 0 && end == 18, "EM_EXSETSEL: expected (0,18) actual:(%d,%d)\n", start,end);
1346 result = SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1347 ok(result == 10, "EM_EXSETSEL: expected: 10 actual: %ld\n", result);
1348 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM) &start, (LPARAM) &end);
1349 ok(start == 5 && end == 10, "EM_EXSETSEL: expected (5,10) actual:(%d,%d)\n", start,end);
1353 result = SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1354 ok(result == 17, "EM_EXSETSEL: expected: 17 actual: %ld\n", result);
1355 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM) &start, (LPARAM) &end);
1356 ok(start == 15 && end == 17, "EM_EXSETSEL: expected (15,17) actual:(%d,%d)\n", start,end);
1358 /* bug 4462 - the following values get used in FileZilla */
1359 /* when min < 0, selection is deselected and caret is moved to end of last selection */
1362 result = SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1363 ok(result == 17, "EM_EXSETSEL: expected: 17 actual: %ld\n", result);
1364 SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM) &start, (LPARAM) &end);
1365 ok(start == 17 && end == 17, "EM_EXSETSEL: expected (17,17) actual:(%d,%d)\n", start,end);
1367 DestroyWindow(hwndRichEdit);
1370 START_TEST( editor )
1375 /* Must explicitly LoadLibrary(). The test has no references to functions in
1376 * RICHED20.DLL, so the linker doesn't actually link to it. */
1377 hmoduleRichEdit = LoadLibrary("RICHED20.DLL");
1378 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
1381 test_EM_SCROLLCARET();
1383 test_EM_SETTEXTMODE();
1384 test_TM_PLAINTEXT();
1385 test_EM_SETOPTIONS();
1387 test_EM_AUTOURLDETECT();
1388 test_EM_SETUNDOLIMIT();
1390 test_EM_SETTEXTEX();
1391 test_EM_EXLIMITTEXT();
1392 test_EM_GETLIMITTEXT();
1394 test_EM_GETMODIFY();
1397 /* Set the environment variable WINETEST_RICHED20 to keep windows
1398 * responsive and open for 30 seconds. This is useful for debugging.
1400 * The message pump uses PeekMessage() to empty the queue and then sleeps for
1401 * 50ms before retrying the queue. */
1402 end = time(NULL) + 30;
1403 if (getenv( "WINETEST_RICHED20" )) {
1404 while (time(NULL) < end) {
1405 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1406 TranslateMessage(&msg);
1407 DispatchMessage(&msg);
1414 ok(FreeLibrary(hmoduleRichEdit) != 0, "error: %d\n", (int) GetLastError());