Added a few more Unicode digits from Unicode version 4.1.
[wine] / dlls / user / tests / edit.c
1 /* Unit test suite for edit control.
2  *
3  * Copyright 2004 Vitaliy Margolen
4  * Copyright 2005 C. Scott Ananian
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include <assert.h>
22 #include <windows.h>
23 #include <windowsx.h>
24 #include <commctrl.h>
25
26 #include "wine/test.h"
27
28 #ifndef ES_COMBO
29 #define ES_COMBO 0x200
30 #endif
31
32 #define ID_EDITTEST2 99
33 #define MAXLEN 200
34
35 struct edit_notify {
36     int en_change, en_maxtext, en_update;
37 };
38
39 static struct edit_notify notifications;
40
41 static HINSTANCE hinst;
42 static HWND hwndET2;
43 static char szEditTest2Class[] = "EditTest2Class";
44 static char szEditTest3Class[] = "EditTest3Class";
45 static char szEditTextPositionClass[] = "EditTextPositionWindowClass";
46
47 static HWND create_editcontrol (DWORD style, DWORD exstyle)
48 {
49     HWND handle;
50
51     handle = CreateWindowEx(exstyle,
52                           "EDIT",
53                           "Test Text",
54                           ES_AUTOHSCROLL | ES_AUTOVSCROLL | style,
55                           10, 10, 300, 300,
56                           NULL, NULL, hinst, NULL);
57     assert (handle);
58     if (winetest_interactive)
59         ShowWindow (handle, SW_SHOW);
60     return handle;
61 }
62
63 static HWND create_child_editcontrol (DWORD style, DWORD exstyle)
64 {
65     HWND parentWnd;
66     HWND editWnd;
67     RECT rect;
68     
69     rect.left = 0;
70     rect.top = 0;
71     rect.right = 300;
72     rect.bottom = 300;
73     assert(AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE));
74     
75     parentWnd = CreateWindowEx(0,
76                             szEditTextPositionClass,
77                             "Edit Test",
78                             WS_OVERLAPPEDWINDOW,
79                             CW_USEDEFAULT, CW_USEDEFAULT,
80                             rect.right - rect.left, rect.bottom - rect.top,
81                             NULL, NULL, hinst, NULL);
82     assert(parentWnd);
83
84     editWnd = CreateWindowEx(exstyle,
85                             "EDIT",
86                             "Test Text",
87                             WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_AUTOVSCROLL | style,
88                             0, 0, 300, 300,
89                             parentWnd, NULL, hinst, NULL);
90     assert(editWnd);
91     if (winetest_interactive)
92         ShowWindow (parentWnd, SW_SHOW);
93     return editWnd;
94 }
95
96 static void destroy_child_editcontrol (HWND hwndEdit)
97 {
98     if (GetParent(hwndEdit))
99         DestroyWindow(GetParent(hwndEdit));
100     else {
101         trace("Edit control has no parent!\n");
102         DestroyWindow(hwndEdit);
103     }
104 }
105
106 static LONG get_edit_style (HWND hwnd)
107 {
108     return GetWindowLongA( hwnd, GWL_STYLE ) & (
109         ES_LEFT |
110 /* FIXME: not implemented
111         ES_CENTER |
112         ES_RIGHT |
113         ES_OEMCONVERT |
114 */
115         ES_MULTILINE |
116         ES_UPPERCASE |
117         ES_LOWERCASE |
118         ES_PASSWORD |
119         ES_AUTOVSCROLL |
120         ES_AUTOHSCROLL |
121         ES_NOHIDESEL |
122         ES_COMBO |
123         ES_READONLY |
124         ES_WANTRETURN |
125         ES_NUMBER
126         );
127 }
128
129 static void set_client_height(HWND Wnd, unsigned Height)
130 {
131     RECT ClientRect, WindowRect;
132
133     GetWindowRect(Wnd, &WindowRect);
134     GetClientRect(Wnd, &ClientRect);
135     SetWindowPos(Wnd, NULL, 0, 0,
136                  WindowRect.right - WindowRect.left,
137                  Height + (WindowRect.bottom - WindowRect.top) -
138                  (ClientRect.bottom - ClientRect.top),
139                  SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
140
141     /* Workaround for a bug in Windows' edit control
142        (multi-line mode) */
143     GetWindowRect(Wnd, &WindowRect);             
144     SetWindowPos(Wnd, NULL, 0, 0,
145                  WindowRect.right - WindowRect.left + 1,
146                  WindowRect.bottom - WindowRect.top + 1,
147                  SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
148     SetWindowPos(Wnd, NULL, 0, 0,
149                  WindowRect.right - WindowRect.left,
150                  WindowRect.bottom - WindowRect.top,
151                  SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
152
153     GetClientRect(Wnd, &ClientRect);
154     ok(ClientRect.bottom - ClientRect.top == Height,
155         "The client height should be %ld, but is %ld\n",
156         (long)Height, (long)(ClientRect.bottom - ClientRect.top));
157 }
158
159 static void test_edit_control_1(void)
160 {
161     HWND hwEdit;
162     MSG msMessage;
163     int i;
164     LONG r;
165
166     msMessage.message = WM_KEYDOWN;
167
168     trace("EDIT: Single line\n");
169     hwEdit = create_editcontrol(0, 0);
170     r = get_edit_style(hwEdit);
171     ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL), "Wrong style expected 0xc0 got: 0x%lx\n", r); 
172     for (i=0;i<65535;i++)
173     {
174         msMessage.wParam = i;
175         r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
176         ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS),
177             "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %lx\n", r);
178     }
179     DestroyWindow (hwEdit);
180
181     trace("EDIT: Single line want returns\n");
182     hwEdit = create_editcontrol(ES_WANTRETURN, 0);
183     r = get_edit_style(hwEdit);
184     ok(r == (ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN), "Wrong style expected 0x10c0 got: 0x%lx\n", r); 
185     for (i=0;i<65535;i++)
186     {
187         msMessage.wParam = i;
188         r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
189         ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS),
190             "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS got %lx\n", r);
191     }
192     DestroyWindow (hwEdit);
193
194     trace("EDIT: Multiline line\n");
195     hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOVSCROLL, 0);
196     r = get_edit_style(hwEdit);
197     ok(r == (ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0xc4 got: 0x%lx\n", r); 
198     for (i=0;i<65535;i++)
199     {
200         msMessage.wParam = i;
201         r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
202         ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS),
203             "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %lx\n", r);
204     }
205     DestroyWindow (hwEdit);
206
207     trace("EDIT: Multi line want returns\n");
208     hwEdit = create_editcontrol(ES_MULTILINE | WS_VSCROLL | ES_AUTOVSCROLL | ES_WANTRETURN, 0);
209     r = get_edit_style(hwEdit);
210     ok(r == (ES_WANTRETURN | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE), "Wrong style expected 0x10c4 got: 0x%lx\n", r); 
211     for (i=0;i<65535;i++)
212     {
213         msMessage.wParam = i;
214         r = SendMessage(hwEdit, WM_GETDLGCODE, 0, (LPARAM) &msMessage);
215         ok(r == (DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS),
216             "Expected DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTALLKEYS | DLGC_WANTARROWS got %lx\n", r);
217     }
218     DestroyWindow (hwEdit);
219 }
220
221 /* WM_SETTEXT is implemented by selecting all text, and then replacing the
222  * selection.  This test checks that the first 'select all' doesn't generate
223  * an UPDATE message which can escape and (via a handler) change the
224  * selection, which would cause WM_SETTEXT to break.  This old bug
225  * was fixed 18-Mar-2005; we check here to ensure it doesn't regress.
226  */
227 static void test_edit_control_2(void)
228 {
229     HWND hwndMain;
230     char szLocalString[MAXLEN];
231
232     /* Create main and edit windows. */
233     hwndMain = CreateWindow(szEditTest2Class, "ET2", WS_OVERLAPPEDWINDOW,
234                             0, 0, 200, 200, NULL, NULL, hinst, NULL);
235     assert(hwndMain);
236     if (winetest_interactive)
237         ShowWindow (hwndMain, SW_SHOW);
238
239     hwndET2 = CreateWindow("EDIT", NULL,
240                            WS_CHILD|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL,
241                            0, 0, 150, 50, /* important this not be 0 size. */
242                            hwndMain, (HMENU) ID_EDITTEST2, hinst, NULL);
243     assert(hwndET2);
244     if (winetest_interactive)
245         ShowWindow (hwndET2, SW_SHOW);
246
247     trace("EDIT: SETTEXT atomicity\n");
248     /* Send messages to "type" in the word 'foo'. */
249     SendMessage(hwndET2, WM_CHAR, 'f', 1);
250     SendMessage(hwndET2, WM_CHAR, 'o', 1);
251     SendMessage(hwndET2, WM_CHAR, 'o', 1);
252     /* 'foo' should have been changed to 'bar' by the UPDATE handler. */
253     GetWindowText(hwndET2, szLocalString, MAXLEN);
254     ok(lstrcmp(szLocalString, "bar")==0,
255        "Wrong contents of edit: %s\n", szLocalString);
256
257     /* OK, done! */
258     DestroyWindow (hwndET2);
259     DestroyWindow (hwndMain);
260 }
261
262 static void ET2_check_change(void) {
263    char szLocalString[MAXLEN];
264    /* This EN_UPDATE handler changes any 'foo' to 'bar'. */
265    GetWindowText(hwndET2, szLocalString, MAXLEN);
266    if (lstrcmp(szLocalString, "foo")==0) {
267        lstrcpy(szLocalString, "bar");
268        SendMessage(hwndET2, WM_SETTEXT, 0, (LPARAM) szLocalString);
269    }
270    /* always leave the cursor at the end. */
271    SendMessage(hwndET2, EM_SETSEL, MAXLEN - 1, MAXLEN - 1);
272 }
273 static void ET2_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
274 {
275     if (id==ID_EDITTEST2 && codeNotify == EN_UPDATE)
276         ET2_check_change();
277 }
278 static LRESULT CALLBACK ET2_WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
279 {
280     switch (iMsg) {
281         HANDLE_MSG(hwnd, WM_COMMAND, ET2_OnCommand);
282     }
283     return DefWindowProc(hwnd, iMsg, wParam, lParam);
284 }
285
286 static void zero_notify(void)
287 {
288     notifications.en_change = 0;
289     notifications.en_maxtext = 0;
290     notifications.en_update = 0;
291 }
292
293 #define test_notify(enchange, enmaxtext, enupdate) \
294     ok(notifications.en_change == enchange, "expected %d EN_CHANGE notifications, " \
295     "got %d\n", enchange, notifications.en_change); \
296     ok(notifications.en_maxtext == enmaxtext, "expected %d EN_MAXTEXT notifications, " \
297     "got %d\n", enmaxtext, notifications.en_maxtext); \
298     ok(notifications.en_update == enupdate, "expected %d EN_UPDATE notifications, " \
299     "got %d\n", enupdate, notifications.en_update)
300
301
302 static LRESULT CALLBACK edit3_wnd_procA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
303 {
304     switch (msg) {
305         case WM_COMMAND:
306             switch (HIWORD(wParam)) {
307                 case EN_MAXTEXT:
308                     notifications.en_maxtext++;
309                     break;
310                 case EN_UPDATE:
311                     notifications.en_update++;
312                     break;
313                 case EN_CHANGE:
314                     notifications.en_change++;
315                     break;
316             }
317             break;
318     }
319     return DefWindowProcA(hWnd, msg, wParam, lParam);
320 }
321
322 /* Test behaviour of WM_SETTEXT, WM_REPLACESEL and notificatisons sent in response
323  * to these messages.
324  */
325 static void test_edit_control_3(void)
326 {
327     HWND hWnd;
328     HWND hParent;
329     int len;
330     static const char *str = "this is a long string.";
331     static const char *str2 = "this is a long string.\r\nthis is a long string.\r\nthis is a long string.\r\nthis is a long string.";
332
333     trace("EDIT: Test notifications\n");
334
335     hParent = CreateWindowExA(0,
336               szEditTest3Class,
337               NULL,
338               0,
339               CW_USEDEFAULT, CW_USEDEFAULT, 10, 10,
340               NULL, NULL, NULL, NULL);
341     assert(hParent);
342
343     trace("EDIT: Single line, no ES_AUTOHSCROLL\n");
344     hWnd = CreateWindowExA(0,
345               "EDIT",
346               NULL,
347               0,
348               10, 10, 50, 50,
349               hParent, NULL, NULL, NULL);
350     assert(hWnd);
351
352     zero_notify();
353     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
354     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
355     ok(lstrlenA(str) > len, "text should have been truncated\n");
356     test_notify(1, 1, 1);
357
358     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
359     zero_notify();
360     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
361     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
362     ok(1 == len, "wrong text length, expected 1, got %d\n", len);
363     test_notify(1, 0, 1);
364
365     zero_notify();
366     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
367     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
368     ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
369     test_notify(1, 0, 1);
370
371     SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
372
373     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
374     zero_notify();
375     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
376     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
377     ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
378     test_notify(1, 1, 1);
379
380     zero_notify();
381     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
382     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
383     ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
384     test_notify(1, 0, 1);
385
386     DestroyWindow(hWnd);
387
388     trace("EDIT: Single line, ES_AUTOHSCROLL\n");
389     hWnd = CreateWindowExA(0,
390               "EDIT",
391               NULL,
392               ES_AUTOHSCROLL,
393               10, 10, 50, 50,
394               hParent, NULL, NULL, NULL);
395     assert(hWnd);
396
397     zero_notify();
398     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
399     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
400     ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
401     test_notify(1, 0, 1);
402
403     zero_notify();
404     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
405     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
406     ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
407     test_notify(1, 0, 1);
408
409     SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
410
411     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
412     zero_notify();
413     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
414     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
415     ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
416     test_notify(1, 1, 1);
417
418     zero_notify();
419     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
420     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
421     ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
422     test_notify(1, 0, 1);
423
424     DestroyWindow(hWnd);
425
426     trace("EDIT: Multline, no ES_AUTOHSCROLL, no ES_AUTOVSCROLL\n");
427     hWnd = CreateWindowExA(0,
428               "EDIT",
429               NULL,
430               ES_MULTILINE,
431               10, 10, 50, 50,
432               hParent, NULL, NULL, NULL);
433     assert(hWnd);
434
435     zero_notify();
436     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
437     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
438     ok(0 == len, "text should have been truncated, expected 0, got %d\n", len);
439     test_notify(1, 1, 1);
440
441     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
442     zero_notify();
443     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
444     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
445     ok(1 == SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0), "wrong text length, expected 1, got %d\n", len);
446     test_notify(1, 0, 1);
447
448     zero_notify();
449     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
450     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
451     ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
452     test_notify(0, 0, 0);
453
454     SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
455
456     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
457     zero_notify();
458     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str);
459     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
460     ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
461     test_notify(1, 1, 1);
462
463     zero_notify();
464     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str);
465     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
466     ok(lstrlenA(str) == len, "text shouldn't have been truncated\n");
467     test_notify(0, 0, 0);
468
469     DestroyWindow(hWnd);
470
471     trace("EDIT: Multline, ES_AUTOHSCROLL, no ES_AUTOVSCROLL\n");
472     hWnd = CreateWindowExA(0,
473               "EDIT",
474               NULL,
475               ES_MULTILINE | ES_AUTOHSCROLL,
476               10, 10, 50, 50,
477               hParent, NULL, NULL, NULL);
478     assert(hWnd);
479
480     zero_notify();
481     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
482     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
483     ok(0 == len, "text should have been truncated, expected 0, got %d\n", len);
484     test_notify(1, 1, 1);
485
486     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
487     zero_notify();
488     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)"a");
489     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
490     ok(1 == SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0), "wrong text length, expected 1, got %d\n", len);
491     test_notify(1, 0, 1);
492
493     zero_notify();
494     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
495     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
496     ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
497     test_notify(0, 0, 0);
498
499     SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
500
501     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
502     zero_notify();
503     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
504     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
505     ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
506     test_notify(1, 1, 1);
507
508     zero_notify();
509     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
510     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
511     ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
512     test_notify(0, 0, 0);
513
514     DestroyWindow(hWnd);
515
516     trace("EDIT: Multline, ES_AUTOHSCROLL and ES_AUTOVSCROLL\n");
517     hWnd = CreateWindowExA(0,
518               "EDIT",
519               NULL,
520               ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
521               10, 10, 50, 50,
522               hParent, NULL, NULL, NULL);
523     assert(hWnd);
524
525     zero_notify();
526     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
527     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
528     ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
529     test_notify(1, 0, 1);
530
531     zero_notify();
532     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
533     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
534     ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
535     test_notify(0, 0, 0);
536
537     SendMessageA(hWnd, EM_SETLIMITTEXT, 5, 0);
538
539     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"");
540     zero_notify();
541     SendMessageA(hWnd, EM_REPLACESEL, 0, (LPARAM)str2);
542     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
543     ok(5 == len, "text should have been truncated to limit, expected 5, got %d\n", len);
544     test_notify(1, 1, 1);
545
546     zero_notify();
547     SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)str2);
548     len = SendMessageA(hWnd, WM_GETTEXTLENGTH, 0, 0);
549     ok(lstrlenA(str2) == len, "text shouldn't have been truncated\n");
550     test_notify(0, 0, 0);
551
552     DestroyWindow(hWnd);
553 }
554
555 /* Test EM_CHARFROMPOS and EM_POSFROMCHAR
556  */
557 static void test_edit_control_4(void)
558 {
559     HWND hwEdit;
560     int lo, hi, mid;
561     int ret;
562     int i;
563
564     trace("EDIT: Test EM_CHARFROMPOS and EM_POSFROMCHAR\n");
565     hwEdit = create_editcontrol(0, 0);
566     SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
567     lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
568     hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
569     mid = lo + (hi - lo) / 2;
570
571     for (i = lo; i < mid; i++) {
572        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
573        ok(0 == ret, "expected 0 got %d\n", ret);
574     }
575     for (i = mid; i <= hi; i++) {
576        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
577        ok(1 == ret, "expected 1 got %d\n", ret);
578     }
579     ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
580     ok(-1 == ret, "expected -1 got %d\n", ret);
581     DestroyWindow(hwEdit);
582
583     hwEdit = create_editcontrol(ES_RIGHT, 0);
584     SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
585     lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
586     hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
587     mid = lo + (hi - lo) / 2;
588
589     for (i = lo; i < mid; i++) {
590        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
591        ok(0 == ret, "expected 0 got %d\n", ret);
592     }
593     for (i = mid; i <= hi; i++) {
594        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
595        ok(1 == ret, "expected 1 got %d\n", ret);
596     }
597     ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
598     ok(-1 == ret, "expected -1 got %d\n", ret);
599     DestroyWindow(hwEdit);
600
601     hwEdit = create_editcontrol(ES_CENTER, 0);
602     SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
603     lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
604     hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
605     mid = lo + (hi - lo) / 2;
606
607     for (i = lo; i < mid; i++) {
608        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
609        ok(0 == ret, "expected 0 got %d\n", ret);
610     }
611     for (i = mid; i <= hi; i++) {
612        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
613        ok(1 == ret, "expected 1 got %d\n", ret);
614     }
615     ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
616     ok(-1 == ret, "expected -1 got %d\n", ret);
617     DestroyWindow(hwEdit);
618
619     hwEdit = create_editcontrol(ES_MULTILINE, 0);
620     SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
621     lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
622     hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
623     mid = lo + (hi - lo) / 2 +1;
624
625     for (i = lo; i < mid; i++) {
626        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
627        ok(0 == ret, "expected 0 got %d\n", ret);
628     }
629     for (i = mid; i <= hi; i++) {
630        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
631        ok(1 == ret, "expected 1 got %d\n", ret);
632     }
633     ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
634     ok(-1 == ret, "expected -1 got %d\n", ret);
635     DestroyWindow(hwEdit);
636
637     hwEdit = create_editcontrol(ES_MULTILINE | ES_RIGHT, 0);
638     SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
639     lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
640     hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
641     mid = lo + (hi - lo) / 2 +1;
642
643     for (i = lo; i < mid; i++) {
644        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
645        ok(0 == ret, "expected 0 got %d\n", ret);
646     }
647     for (i = mid; i <= hi; i++) {
648        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
649        ok(1 == ret, "expected 1 got %d\n", ret);
650     }
651     ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
652     ok(-1 == ret, "expected -1 got %d\n", ret);
653     DestroyWindow(hwEdit);
654
655     hwEdit = create_editcontrol(ES_MULTILINE | ES_CENTER, 0);
656     SendMessage(hwEdit, WM_SETTEXT, 0, (LPARAM) "aa");
657     lo = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 0, 0));
658     hi = LOWORD(SendMessage(hwEdit, EM_POSFROMCHAR, 1, 0));
659     mid = lo + (hi - lo) / 2 +1;
660
661     for (i = lo; i < mid; i++) {
662        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
663        ok(0 == ret, "expected 0 got %d\n", ret);
664     }
665     for (i = mid; i <= hi; i++) {
666        ret = LOWORD(SendMessage(hwEdit, EM_CHARFROMPOS, 0, (LPARAM) i));
667        ok(1 == ret, "expected 1 got %d\n", ret);
668     }
669     ret = SendMessage(hwEdit, EM_POSFROMCHAR, 2, 0);
670     ok(-1 == ret, "expected -1 got %d\n", ret);
671     DestroyWindow(hwEdit);
672 }
673
674 static void test_margins(void)
675 {
676     HWND hwEdit;
677     RECT old_rect, new_rect;
678     INT old_left_margin, old_right_margin;
679     DWORD old_margins, new_margins;
680
681     hwEdit = create_editcontrol(WS_BORDER, 0);
682     
683     old_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
684     old_left_margin = LOWORD(old_margins);
685     old_right_margin = HIWORD(old_margins);
686     
687     /* Check if setting the margins works */
688     
689     SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN, MAKELONG(10, 0));
690     new_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
691     ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins));
692     ok(HIWORD(new_margins) == old_right_margin, "Wrong right margin: %d\n", HIWORD(new_margins));
693     
694     SendMessage(hwEdit, EM_SETMARGINS, EC_RIGHTMARGIN, MAKELONG(0, 10));
695     new_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
696     ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins));
697     ok(HIWORD(new_margins) == 10, "Wrong right margin: %d\n", HIWORD(new_margins));
698     
699     
700     /* The size of the rectangle must decrease if we increase the margin */
701     
702     SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(5, 5));
703     SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
704     SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(15, 20));
705     SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
706     ok(new_rect.left == old_rect.left + 10, "The left border of the rectangle is wrong\n");
707     ok(new_rect.right == old_rect.right - 15, "The right border of the rectangle is wrong\n");
708     ok(new_rect.top == old_rect.top, "The top border of the rectangle must not change\n");
709     ok(new_rect.bottom == old_rect.bottom, "The bottom border of the rectangle must not change\n");
710     
711     
712     /* If we set the margin to same value as the current margin,
713        the rectangle must not change */
714     
715     SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10));
716     old_rect.left = 1;
717     old_rect.right = 99;
718     old_rect.top = 1;
719     old_rect.bottom = 99;
720     SendMessage(hwEdit, EM_SETRECT, 0, (LPARAM)&old_rect);    
721     SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
722     SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10));
723     SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
724     ok(new_rect.left == old_rect.left, "The left border of the rectangle has changed\n");
725     ok(new_rect.right == old_rect.right, "The right border of the rectangle has changed\n");
726     ok(new_rect.top == old_rect.top, "The top border of the rectangle has changed\n");
727     ok(new_rect.bottom == old_rect.bottom, "The bottom border of the rectangle has changed\n");
728     
729     DestroyWindow (hwEdit);
730 }
731
732 #define edit_pos_ok(exp, got, txt) \
733     ok(exp == got, "wrong " #txt " expected %d got %ld\n", exp, got);
734
735 #define check_pos(hwEdit, set_height, test_top, test_height, test_left) \
736 do { \
737     RECT format_rect; \
738     int left_margin; \
739     set_client_height(hwEdit, set_height); \
740     SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM) &format_rect); \
741     left_margin = LOWORD(SendMessage(hwEdit, EM_GETMARGINS, 0, 0)); \
742     edit_pos_ok(test_top, format_rect.top, vertical position); \
743     edit_pos_ok((int)test_height, format_rect.bottom - format_rect.top, height); \
744     edit_pos_ok(test_left, format_rect.left - left_margin, left); \
745 } while(0)
746
747 void test_text_position_style(DWORD style)
748 {
749     HWND hwEdit;
750     HFONT font, oldFont;
751     HDC dc;
752     TEXTMETRIC metrics;
753     INT b, bm, b2, b3;
754     BOOL single_line = !(style & ES_MULTILINE);
755
756     b = GetSystemMetrics(SM_CYBORDER) + 1;
757     b2 = 2 * b;
758     b3 = 3 * b;
759     bm = b2 - 1;
760     
761     /* Get a stock font for which we can determine the metrics */
762     assert(font = GetStockObject(SYSTEM_FONT));
763     assert(dc = GetDC(NULL));
764     oldFont = SelectObject(dc, font);
765     assert(GetTextMetrics(dc, &metrics));    
766     SelectObject(dc, oldFont);
767     ReleaseDC(NULL, dc);
768     
769     /* Windows' edit control has some bugs in multi-line mode:
770      * - Sometimes the format rectangle doesn't get updated
771      *   (see workaround in set_client_height())
772      * - If the height of the control is smaller than the height of a text
773      *   line, the format rectangle is still as high as a text line
774      *   (higher than the client rectangle) and the caret is not shown
775      */
776     
777     /* Edit controls that are in a parent window */
778        
779     hwEdit = create_child_editcontrol(style, 0);
780     SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
781     if (single_line)
782     check_pos(hwEdit, metrics.tmHeight -  1, 0, metrics.tmHeight - 1, 0);
783     check_pos(hwEdit, metrics.tmHeight     , 0, metrics.tmHeight    , 0);
784     check_pos(hwEdit, metrics.tmHeight +  1, 0, metrics.tmHeight    , 0);
785     check_pos(hwEdit, metrics.tmHeight +  2, 0, metrics.tmHeight    , 0);
786     check_pos(hwEdit, metrics.tmHeight + 10, 0, metrics.tmHeight    , 0);
787     destroy_child_editcontrol(hwEdit);
788
789     hwEdit = create_child_editcontrol(style | WS_BORDER, 0);
790     SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
791     if (single_line)
792     check_pos(hwEdit, metrics.tmHeight -  1, 0, metrics.tmHeight - 1, b);
793     check_pos(hwEdit, metrics.tmHeight     , 0, metrics.tmHeight    , b);
794     check_pos(hwEdit, metrics.tmHeight +  1, 0, metrics.tmHeight    , b);
795     check_pos(hwEdit, metrics.tmHeight + bm, 0, metrics.tmHeight    , b);
796     check_pos(hwEdit, metrics.tmHeight + b2, b, metrics.tmHeight    , b);
797     check_pos(hwEdit, metrics.tmHeight + b3, b, metrics.tmHeight    , b);
798     destroy_child_editcontrol(hwEdit);
799
800     hwEdit = create_child_editcontrol(style, WS_EX_CLIENTEDGE);
801     SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
802     if (single_line)
803     check_pos(hwEdit, metrics.tmHeight -  1, 0, metrics.tmHeight - 1, 1);
804     check_pos(hwEdit, metrics.tmHeight     , 0, metrics.tmHeight    , 1);
805     check_pos(hwEdit, metrics.tmHeight +  1, 0, metrics.tmHeight    , 1);
806     check_pos(hwEdit, metrics.tmHeight +  2, 1, metrics.tmHeight    , 1);
807     check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight    , 1);
808     destroy_child_editcontrol(hwEdit);
809
810     hwEdit = create_child_editcontrol(style | WS_BORDER, WS_EX_CLIENTEDGE);
811     SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
812     if (single_line)
813     check_pos(hwEdit, metrics.tmHeight -  1, 0, metrics.tmHeight - 1, 1);
814     check_pos(hwEdit, metrics.tmHeight     , 0, metrics.tmHeight    , 1);
815     check_pos(hwEdit, metrics.tmHeight +  1, 0, metrics.tmHeight    , 1);
816     check_pos(hwEdit, metrics.tmHeight +  2, 1, metrics.tmHeight    , 1);
817     check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight    , 1);
818     destroy_child_editcontrol(hwEdit);
819
820
821     /* Edit controls that are popup windows */
822     
823     hwEdit = create_editcontrol(style | WS_POPUP, 0);
824     SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
825     if (single_line)
826     check_pos(hwEdit, metrics.tmHeight -  1, 0, metrics.tmHeight - 1, 0);
827     check_pos(hwEdit, metrics.tmHeight     , 0, metrics.tmHeight    , 0);
828     check_pos(hwEdit, metrics.tmHeight +  1, 0, metrics.tmHeight    , 0);
829     check_pos(hwEdit, metrics.tmHeight +  2, 0, metrics.tmHeight    , 0);
830     check_pos(hwEdit, metrics.tmHeight + 10, 0, metrics.tmHeight    , 0);
831     DestroyWindow(hwEdit);
832
833     hwEdit = create_editcontrol(style | WS_POPUP | WS_BORDER, 0);
834     SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
835     if (single_line)
836     check_pos(hwEdit, metrics.tmHeight -  1, 0, metrics.tmHeight - 1, b);
837     check_pos(hwEdit, metrics.tmHeight     , 0, metrics.tmHeight    , b);
838     check_pos(hwEdit, metrics.tmHeight +  1, 0, metrics.tmHeight    , b);
839     check_pos(hwEdit, metrics.tmHeight + bm, 0, metrics.tmHeight    , b);
840     check_pos(hwEdit, metrics.tmHeight + b2, b, metrics.tmHeight    , b);
841     check_pos(hwEdit, metrics.tmHeight + b3, b, metrics.tmHeight    , b);
842     DestroyWindow(hwEdit);
843
844     hwEdit = create_editcontrol(style | WS_POPUP, WS_EX_CLIENTEDGE);
845     SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
846     if (single_line)
847     check_pos(hwEdit, metrics.tmHeight -  1, 0, metrics.tmHeight - 1, 1);
848     check_pos(hwEdit, metrics.tmHeight     , 0, metrics.tmHeight    , 1);
849     check_pos(hwEdit, metrics.tmHeight +  1, 0, metrics.tmHeight    , 1);
850     check_pos(hwEdit, metrics.tmHeight +  2, 1, metrics.tmHeight    , 1);
851     check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight    , 1);
852     DestroyWindow(hwEdit);
853
854     hwEdit = create_editcontrol(style | WS_POPUP | WS_BORDER, WS_EX_CLIENTEDGE);
855     SendMessage(hwEdit, WM_SETFONT, (WPARAM) font, (LPARAM) FALSE);
856     if (single_line)
857     check_pos(hwEdit, metrics.tmHeight -  1, 0, metrics.tmHeight - 1, 1);
858     check_pos(hwEdit, metrics.tmHeight     , 0, metrics.tmHeight    , 1);
859     check_pos(hwEdit, metrics.tmHeight +  1, 0, metrics.tmHeight    , 1);
860     check_pos(hwEdit, metrics.tmHeight +  2, 1, metrics.tmHeight    , 1);
861     check_pos(hwEdit, metrics.tmHeight + 10, 1, metrics.tmHeight    , 1);
862     DestroyWindow(hwEdit);
863 }
864
865 void test_text_position(void)
866 {
867     trace("EDIT: Text position (Single line)\n");
868     test_text_position_style(0);
869     trace("EDIT: Text position (Multi line)\n");
870     test_text_position_style(ES_MULTILINE);
871 }
872
873 static BOOL RegisterWindowClasses (void)
874 {
875     WNDCLASSA test2;
876     WNDCLASSA test3;
877     WNDCLASSA text_position;
878     
879     test2.style = 0;
880     test2.lpfnWndProc = ET2_WndProc;
881     test2.cbClsExtra = 0;
882     test2.cbWndExtra = 0;
883     test2.hInstance = hinst;
884     test2.hIcon = NULL;
885     test2.hCursor = LoadCursorA (NULL, IDC_ARROW);
886     test2.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
887     test2.lpszMenuName = NULL;
888     test2.lpszClassName = szEditTest2Class;
889     if (!RegisterClassA(&test2)) return FALSE;
890
891     test3.style = 0;
892     test3.lpfnWndProc = edit3_wnd_procA;
893     test3.cbClsExtra = 0;
894     test3.cbWndExtra = 0;
895     test3.hInstance = hinst;
896     test3.hIcon = 0;
897     test3.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
898     test3.hbrBackground = GetStockObject(WHITE_BRUSH);
899     test3.lpszMenuName = NULL;
900     test3.lpszClassName = szEditTest3Class;
901     if (!RegisterClassA(&test3)) return FALSE;
902
903     text_position.style = CS_HREDRAW | CS_VREDRAW;
904     text_position.cbClsExtra = 0;
905     text_position.cbWndExtra = 0;
906     text_position.hInstance = hinst;
907     text_position.hIcon = NULL;
908     text_position.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_ARROW));
909     text_position.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
910     text_position.lpszMenuName = NULL;
911     text_position.lpszClassName = szEditTextPositionClass;
912     text_position.lpfnWndProc = DefWindowProc;
913     if (!RegisterClassA(&text_position)) return FALSE;
914
915     return TRUE;
916 }
917
918 static void UnregisterWindowClasses (void)
919 {
920     UnregisterClassA(szEditTest2Class, hinst);
921     UnregisterClassA(szEditTest3Class, hinst);
922     UnregisterClassA(szEditTextPositionClass, hinst);
923 }
924
925 START_TEST(edit)
926 {
927     hinst = GetModuleHandleA(NULL);
928     assert(RegisterWindowClasses());
929
930     test_edit_control_1();
931     test_edit_control_2();
932     test_edit_control_3();
933     test_edit_control_4();
934     test_margins();
935     test_text_position();
936     
937     UnregisterWindowClasses();
938 }