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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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";
53 struct find_s find_tests[] = {
54 /* Find in empty text */
55 {0, -1, "foo", FR_DOWN, -1, 0},
56 {0, -1, "foo", 0, -1, 0},
57 {0, -1, "", FR_DOWN, -1, 0},
58 {20, 5, "foo", FR_DOWN, -1, 0},
59 {5, 20, "foo", FR_DOWN, -1, 0}
62 struct find_s find_tests2[] = {
64 {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1, 0},
65 {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1, 0},
67 /* Subsequent finds */
68 {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4, 0},
69 {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13, 0},
70 {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0},
71 {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
74 {19, 20, "Wine", FR_MATCHCASE, 13, 0},
75 {10, 20, "Wine", FR_MATCHCASE, 4, 0},
76 {20, 10, "Wine", FR_MATCHCASE, 13, 0},
78 /* Case-insensitive */
79 {1, 31, "wInE", FR_DOWN, 4, 0},
80 {1, 31, "Wine", FR_DOWN, 4, 0},
82 /* High-to-low ranges */
83 {20, 5, "Wine", FR_DOWN, -1, 0},
84 {2, 1, "Wine", FR_DOWN, -1, 0},
85 {30, 29, "Wine", FR_DOWN, -1, 0},
86 {20, 5, "Wine", 0, 13, 0},
89 {5, 10, "", FR_DOWN, -1, 0},
90 {10, 5, "", FR_DOWN, -1, 0},
91 {0, -1, "", FR_DOWN, -1, 0},
92 {10, 5, "", 0, -1, 0},
94 /* Whole-word search */
95 {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 1},
96 {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1, 1},
99 {-20, 20, "Wine", FR_DOWN, -1, 0},
100 {-20, 20, "Wine", FR_DOWN, -1, 0},
101 {-15, -20, "Wine", FR_DOWN, -1, 0},
102 {1<<12, 1<<13, "Wine", FR_DOWN, -1, 0},
104 /* Check the case noted in bug 4479 where matches at end aren't recognized */
105 {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0},
106 {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
107 {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
108 {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0},
109 {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0},
111 /* The backwards case of bug 4479; bounds look right
112 * Fails because backward find is wrong */
113 {19, 20, "WINE", FR_MATCHCASE, 0, 0},
114 {0, 20, "WINE", FR_MATCHCASE, -1, 0}
117 static void check_EM_FINDTEXT(HWND hwnd, char *name, struct find_s *f, int id) {
120 memset(&ft, 0, sizeof(ft));
121 ft.chrg.cpMin = f->start;
122 ft.chrg.cpMax = f->end;
123 ft.lpstrText = f->needle;
124 findloc = SendMessage(hwnd, EM_FINDTEXT, f->flags, (LPARAM) &ft);
125 ok(findloc == f->expected_loc,
126 "EM_FINDTEXT(%s,%d) '%s' in range(%d,%d), flags %08x, got start at %d\n",
127 name, id, f->needle, f->start, f->end, f->flags, findloc);
130 static void check_EM_FINDTEXTEX(HWND hwnd, char *name, struct find_s *f,
134 memset(&ft, 0, sizeof(ft));
135 ft.chrg.cpMin = f->start;
136 ft.chrg.cpMax = f->end;
137 ft.lpstrText = f->needle;
138 findloc = SendMessage(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM) &ft);
139 ok(findloc == f->expected_loc,
140 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
141 name, id, f->needle, f->start, f->end, f->flags, findloc);
142 ok(ft.chrgText.cpMin == f->expected_loc,
143 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %ld\n",
144 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMin);
145 ok(ft.chrgText.cpMax == ((f->expected_loc == -1) ? -1
146 : f->expected_loc + strlen(f->needle)),
147 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %ld\n",
148 name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMax);
151 static void run_tests_EM_FINDTEXT(HWND hwnd, char *name, struct find_s *find,
156 for (i = 0; i < num_tests; i++) {
157 if (find[i]._todo_wine) {
159 check_EM_FINDTEXT(hwnd, name, &find[i], i);
160 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
163 check_EM_FINDTEXT(hwnd, name, &find[i], i);
164 check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
169 static void test_EM_FINDTEXT(void)
171 HWND hwndRichEdit = new_richedit(NULL);
173 /* Empty rich edit control */
174 run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests,
175 sizeof(find_tests)/sizeof(struct find_s));
177 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack);
180 run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2,
181 sizeof(find_tests2)/sizeof(struct find_s));
183 DestroyWindow(hwndRichEdit);
186 static int get_scroll_pos_y(HWND hwnd)
189 SendMessage(hwnd, EM_GETSCROLLPOS, 0, (LPARAM) &p);
190 ok(p.x != -1 && p.y != -1, "p.x:%ld p.y:%ld\n", p.x, p.y);
194 static void move_cursor(HWND hwnd, long charindex)
197 cr.cpMax = charindex;
198 cr.cpMin = charindex;
199 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &cr);
202 static void line_scroll(HWND hwnd, int amount)
204 SendMessage(hwnd, EM_LINESCROLL, 0, amount);
207 static void test_EM_SCROLLCARET(void)
210 HWND hwndRichEdit = new_richedit(NULL);
211 const char text[] = "aa\n"
212 "this is a long line of text that should be longer than the "
221 /* Can't verify this */
222 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
224 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
226 /* Caret above visible window */
227 line_scroll(hwndRichEdit, 3);
228 prevY = get_scroll_pos_y(hwndRichEdit);
229 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
230 curY = get_scroll_pos_y(hwndRichEdit);
231 ok(prevY != curY, "%d == %d\n", prevY, curY);
233 /* Caret below visible window */
234 move_cursor(hwndRichEdit, sizeof(text) - 1);
235 line_scroll(hwndRichEdit, -3);
236 prevY = get_scroll_pos_y(hwndRichEdit);
237 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
238 curY = get_scroll_pos_y(hwndRichEdit);
239 ok(prevY != curY, "%d == %d\n", prevY, curY);
241 /* Caret in visible window */
242 move_cursor(hwndRichEdit, sizeof(text) - 2);
243 prevY = get_scroll_pos_y(hwndRichEdit);
244 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
245 curY = get_scroll_pos_y(hwndRichEdit);
246 ok(prevY == curY, "%d != %d\n", prevY, curY);
248 /* Caret still in visible window */
249 line_scroll(hwndRichEdit, -1);
250 prevY = get_scroll_pos_y(hwndRichEdit);
251 SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
252 curY = get_scroll_pos_y(hwndRichEdit);
253 ok(prevY == curY, "%d != %d\n", prevY, curY);
255 DestroyWindow(hwndRichEdit);
258 static void test_EM_SETTEXTMODE(void)
260 HWND hwndRichEdit = new_richedit(NULL);
261 CHARFORMAT2 cf2, cf2test;
265 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
266 /*Insert text into the control*/
268 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
270 /*Attempt to change the control to plain text mode*/
271 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
272 ok(rc != 0, "EM_SETTEXTMODE: changed text mode in control containing text - returned: %d\n", rc);
274 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
275 If rich text is pasted, it should have the same formatting as the rest
276 of the text in the control*/
279 *NOTE: If the default text was already italicized, the test will simply
280 reverse; in other words, it will copy a regular "wine" into a plain
281 text window that uses an italicized format*/
282 cf2.cbSize = sizeof(CHARFORMAT2);
283 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
286 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
287 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
289 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
290 however, SCF_ALL has been implemented*/
291 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
292 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
294 /*Select the string "wine"*/
297 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
299 /*Copy the italicized "wine" to the clipboard*/
300 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
302 /*Reset the formatting to default*/
303 cf2.dwEffects = CFE_ITALIC^cf2.dwEffects;
304 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
306 /*Clear the text in the control*/
307 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
309 /*Switch to Plain Text Mode*/
310 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
311 ok(rc == 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc);
313 /*Input "wine" again in normal format*/
314 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
316 /*Paste the italicized "wine" into the control*/
317 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
319 /*Select a character from the first "wine" string*/
322 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
324 /*Retrieve its formatting*/
325 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
328 /*Select a character from the second "wine" string*/
331 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
333 /*Retrieve its formatting*/
334 cf2test.cbSize = sizeof(CHARFORMAT2);
335 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
338 /*Compare the two formattings*/
339 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
340 "two formats found in plain text mode - cf2.dwEffects: %f cf2test.dwEffects: %f\n",(double) cf2.dwEffects, (double) cf2test.dwEffects);
341 /*Test TM_RICHTEXT by: switching back to Rich Text mode
342 printing "wine" in the current format(normal)
343 pasting "wine" from the clipboard(italicized)
344 comparing the two formats(should differ)*/
346 /*Attempt to switch with text in control*/
347 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
348 ok(rc != 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc);
351 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
353 /*Switch into Rich Text mode*/
354 rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
355 ok(rc == 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc);
357 /*Print "wine" in normal formatting into the control*/
358 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
360 /*Paste italicized "wine" into the control*/
361 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
363 /*Select text from the first "wine" string*/
366 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
368 /*Retrieve its formatting*/
369 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
372 /*Select text from the second "wine" string*/
375 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
377 /*Retrieve its formatting*/
378 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
381 /*Test that the two formattings are not the same*/
382 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects != cf2test.dwEffects),
383 "expected different formats - cf2.dwMask: %f, cf2test.dwMask: %f, cf2.dwEffects: %f, cf2test.dwEffects: %f\n",
384 (double) cf2.dwMask, (double) cf2test.dwMask, (double) cf2.dwEffects, (double) cf2test.dwEffects);
386 DestroyWindow(hwndRichEdit);
389 static void test_TM_PLAINTEXT()
391 /*Tests plain text properties*/
393 HWND hwndRichEdit = new_richedit(NULL);
394 CHARFORMAT2 cf2, cf2test;
397 /*Switch to plain text mode*/
399 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
400 SendMessage(hwndRichEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
402 /*Fill control with text*/
404 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "Is Wine an emulator? No it's not");
406 /*Select some text and bold it*/
410 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
411 cf2.cbSize = sizeof(CHARFORMAT2);
412 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
415 cf2.dwMask = CFM_BOLD | cf2.dwMask;
416 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
418 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
420 /*Get the formatting of those characters*/
422 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
424 /*Get the formatting of some other characters*/
425 cf2test.cbSize = sizeof(CHARFORMAT2);
428 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
429 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
431 /*Test that they are the same as plain text allows only one formatting*/
433 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
434 "two selections' formats differ - cf2.dwMask: %f, cf2test.dwMask %f, cf2.dwEffects: %f, cf2test.dwEffects: %f\n",
435 (double) cf2.dwMask, (double) cf2test.dwMask, (double) cf2.dwEffects, (double) cf2test.dwEffects);
437 /*Fill the control with a "wine" string, which when inserted will be bold*/
439 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
441 /*Copy the bolded "wine" string*/
445 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
446 SendMessage(hwndRichEdit, WM_COPY, 0, 0);
448 /*Swap back to rich text*/
450 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
451 SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
453 /*Set the default formatting to bold italics*/
455 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT, (LPARAM) &cf2);
456 cf2.dwMask |= CFM_ITALIC;
457 cf2.dwEffects ^= CFE_ITALIC;
458 SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
460 /*Set the text in the control to "wine", which will be bold and italicized*/
462 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
464 /*Paste the plain text "wine" string, which should take the insert
465 formatting, which at the moment is bold italics*/
467 SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
469 /*Select the first "wine" string and retrieve its formatting*/
473 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
474 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
476 /*Select the second "wine" string and retrieve its formatting*/
480 SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
481 SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
483 /*Compare the two formattings. They should be the same.*/
485 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
486 "Copied text retained formatting - cf2.dwMask: %f, cf2test.dwMask: %f, cf2.dwEffects: %f, cf2test.dwEffects: %f\n",
487 (double) cf2.dwMask, (double) cf2test.dwMask, (double) cf2.dwEffects, (double) cf2test.dwEffects);
488 DestroyWindow(hwndRichEdit);
491 /* FIXME: Extra '\r' appended at end of gotten text*/
492 static void test_WM_GETTEXT()
494 HWND hwndRichEdit = new_richedit(NULL);
495 static const char text[] = "Hello. My name is RichEdit!";
496 char buffer[1024] = {0};
499 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
500 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
501 result = strcmp(buffer,text);
504 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
508 /* FIXME: need to test unimplemented options and robustly test wparam */
509 static void test_EM_SETOPTIONS()
511 HWND hwndRichEdit = new_richedit(NULL);
512 static const char text[] = "Hello. My name is RichEdit!";
513 char buffer[1024] = {0};
515 /* NEGATIVE TESTING - NO OPTIONS SET */
516 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
517 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, 0);
519 /* testing no readonly by sending 'a' to the control*/
520 SetFocus(hwndRichEdit);
521 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
522 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
524 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text, buffer);
525 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
527 /* READONLY - sending 'a' to the control */
528 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
529 SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, ECO_READONLY);
530 SetFocus(hwndRichEdit);
531 SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
532 SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
533 ok(buffer[0]==text[0],
534 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer);
536 DestroyWindow(hwndRichEdit);
539 static void check_CFE_LINK_rcvd(HWND hwnd, int is_url)
541 CHARFORMAT2W text_format;
542 int link_present = 0;
543 text_format.cbSize = sizeof(text_format);
544 SendMessage(hwnd, EM_SETSEL, 0, 0);
545 SendMessage(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &text_format);
546 link_present = text_format.dwEffects & CFE_LINK;
548 { /* control text is url; should get CFE_LINK */
549 ok(0 != link_present, "URL Case: CFE_LINK not set.\n");
553 ok(0 == link_present, "Non-URL Case: CFE_LINK set.\n");
557 static HWND new_static_wnd(HWND parent) {
558 return new_window("Static", 0, parent);
561 static void test_EM_AUTOURLDETECT(void)
568 {"http://www.winehq.org", 1},
569 {"http//winehq.org", 0},
570 {"ww.winehq.org", 0},
571 {"www.winehq.org", 1},
572 {"ftp://192.168.1.1", 1},
573 {"ftp//192.168.1.1", 0},
574 {"mailto:your@email.com", 1},
575 {"prospero:prosperoserver", 1},
577 {"news:newserver", 1},
578 {"wais:waisserver", 1}
583 HWND hwndRichEdit, parent;
585 parent = new_static_wnd(NULL);
586 hwndRichEdit = new_richedit(parent);
587 /* Try and pass EM_AUTOURLDETECT some test wParam values */
588 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
589 ok(urlRet==0, "Good wParam: urlRet is: %d\n", urlRet);
590 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 1, 0);
591 ok(urlRet==0, "Good wParam2: urlRet is: %d\n", urlRet);
592 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
593 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 8, 0);
594 ok(urlRet==E_INVALIDARG, "Bad wParam: urlRet is: %d\n", urlRet);
595 urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM)"h", (LPARAM)"h");
596 ok(urlRet==E_INVALIDARG, "Bad wParam2: urlRet is: %d\n", urlRet);
597 /* for each url, check the text to see if CFE_LINK effect is present */
598 for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) {
599 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
600 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
601 SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
602 check_CFE_LINK_rcvd(hwndRichEdit, 0);
603 SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
604 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
605 SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
606 check_CFE_LINK_rcvd(hwndRichEdit, urls[i].is_url);
608 DestroyWindow(hwndRichEdit);
609 DestroyWindow(parent);
612 static void test_EM_SCROLL()
615 int r; /* return value */
616 int expr; /* expected return value */
617 HWND hwndRichEdit = new_richedit(NULL);
618 int y_before, y_after; /* units of lines of text */
620 /* test a richedit box containing a single line of text */
621 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a");/* one line of text */
623 for (i = 0; i < 4; i++) {
626 case 0: cmd = SB_PAGEDOWN; break;
627 case 1: cmd = SB_PAGEUP; break;
628 case 2: cmd = SB_LINEDOWN; break;
629 case 3: cmd = SB_LINEUP; break;
632 r = SendMessage(hwndRichEdit, EM_SCROLL, cmd, 0);
633 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
634 ok(expr == r, "EM_SCROLL improper return value returned (i == %d). "
635 "Got 0x%08x, expected 0x%08x\n", i, r, expr);
636 ok(y_after == 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
637 "(i == %d)\n", y_after, i);
641 * test a richedit box that will scroll. There are two general
642 * cases: the case without any long lines and the case with a long
645 for (i = 0; i < 2; i++) { /* iterate through different bodies of text */
647 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a\nb\nc\nd\ne");
649 SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)
650 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
651 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
652 "LONG LINE \nb\nc\nd\ne");
653 for (j = 0; j < 12; j++) /* reset scrol position to top */
654 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0);
656 /* get first visible line */
657 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
658 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); /* page down */
660 /* get new current first visible line */
661 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
663 ok(((r & 0xffffff00) == 0x00010000) &&
664 ((r & 0x000000ff) != 0x00000000),
665 "EM_SCROLL page down didn't scroll by a small positive number of "
666 "lines (r == 0x%08x)\n", r);
667 ok(y_after > y_before, "EM_SCROLL page down not functioning "
668 "(line %d scrolled to line %d\n", y_before, y_after);
672 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); /* page up */
673 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
674 ok(((r & 0xffffff00) == 0x0001ff00),
675 "EM_SCROLL page up didn't scroll by a small negative number of lines "
676 "(r == 0x%08x)\n", r);
677 ok(y_after < y_before, "EM_SCROLL page up not functioning (line "
678 "%d scrolled to line %d\n", y_before, y_after);
682 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
684 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
686 ok(r == 0x00010001, "EM_SCROLL line down didn't scroll by one line "
687 "(r == 0x%08x)\n", r);
688 ok(y_after -1 == y_before, "EM_SCROLL line down didn't go down by "
689 "1 line (%d scrolled to %d)\n", y_before, y_after);
693 r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
695 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
697 ok(r == 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
698 "(r == 0x%08x)\n", r);
699 ok(y_after +1 == y_before, "EM_SCROLL line up didn't go up by 1 "
700 "line (%d scrolled to %d)\n", y_before, y_after);
704 r = SendMessage(hwndRichEdit, EM_SCROLL,
705 SB_LINEUP, 0); /* lineup beyond top */
707 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
710 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r);
711 ok(y_before == y_after,
712 "EM_SCROLL line up beyond top worked (%d)\n", y_after);
716 r = SendMessage(hwndRichEdit, EM_SCROLL,
717 SB_PAGEUP, 0);/*page up beyond top */
719 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
722 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r);
723 ok(y_before == y_after,
724 "EM_SCROLL page up beyond top worked (%d)\n", y_after);
726 for (j = 0; j < 12; j++) /* page down all the way to the bottom */
727 SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0);
728 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
729 r = SendMessage(hwndRichEdit, EM_SCROLL,
730 SB_PAGEDOWN, 0); /* page down beyond bot */
731 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
734 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r);
735 ok(y_before == y_after,
736 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
739 y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
740 SendMessage(hwndRichEdit, EM_SCROLL,
741 SB_LINEDOWN, 0); /* line down beyond bot */
742 y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
745 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r);
746 ok(y_before == y_after,
747 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
750 DestroyWindow(hwndRichEdit);
758 /* Must explicitly LoadLibrary(). The test has no references to functions in
759 * RICHED20.DLL, so the linker doesn't actually link to it. */
760 hmoduleRichEdit = LoadLibrary("RICHED20.DLL");
761 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
763 test_EM_SCROLLCARET();
765 test_EM_SETTEXTMODE();
767 test_EM_SETOPTIONS();
769 test_EM_AUTOURLDETECT();
771 /* Set the environment variable WINETEST_RICHED20 to keep windows
772 * responsive and open for 30 seconds. This is useful for debugging.
774 * The message pump uses PeekMessage() to empty the queue and then sleeps for
775 * 50ms before retrying the queue. */
776 end = time(NULL) + 30;
777 if (getenv( "WINETEST_RICHED20" )) {
778 while (time(NULL) < end) {
779 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
780 TranslateMessage(&msg);
781 DispatchMessage(&msg);
788 ok(FreeLibrary(hmoduleRichEdit) != 0, "error: %d\n", (int) GetLastError());