dmloader: complete rewrite and full implementation.
[wine] / dlls / kernel / tests / console.c
1 /*
2  * Unit tests for console API
3  *
4  * Copyright (c) 2003 Eric Pouech
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 "wine/test.h"
22 #include <windows.h>
23 #include <stdio.h>
24
25 /* DEFAULT_ATTRIB is used for all initial filling of the console.
26  * all modifications are made with TEST_ATTRIB so that we could check
27  * what has to be modified or not
28  */
29 #define TEST_ATTRIB    (BACKGROUND_BLUE | FOREGROUND_GREEN)
30 #define DEFAULT_ATTRIB (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED)
31 /* when filling the screen with non-blank chars, this macro defines
32  * what character should be at position 'c'
33  */
34 #define CONTENT(c)    ('A' + (((c).Y * 17 + (c).X) % 23))
35
36 #define okCURSOR(hCon, c) do { \
37   CONSOLE_SCREEN_BUFFER_INFO __sbi; \
38   BOOL expect = GetConsoleScreenBufferInfo((hCon), &__sbi) && \
39                 __sbi.dwCursorPosition.X == (c).X && __sbi.dwCursorPosition.Y == (c).Y; \
40   ok(expect, "Expected cursor at (%d,%d), got (%d,%d)\n", \
41      (c).X, (c).Y, __sbi.dwCursorPosition.X, __sbi.dwCursorPosition.Y); \
42 } while (0)
43
44 #define okCHAR(hCon, c, ch, attr) do { \
45   char __ch; WORD __attr; DWORD __len; BOOL expect; \
46   expect = ReadConsoleOutputCharacter((hCon), &__ch, 1, (c), &__len) == 1 && __len == 1 && __ch == (ch); \
47   ok(expect, "At (%d,%d): expecting char '%c'/%02x got '%c'/%02x\n", (c).X, (c).Y, (ch), (ch), __ch, __ch); \
48   expect = ReadConsoleOutputAttribute((hCon), &__attr, 1, (c), &__len) == 1 && __len == 1 && __attr == (attr); \
49   ok(expect, "At (%d,%d): expecting attr %04x got %04x\n", (c).X, (c).Y, (attr), __attr); \
50 } while (0)
51
52 /* FIXME: this could be optimized on a speed point of view */
53 static void resetContent(HANDLE hCon, COORD sbSize, BOOL content)
54 {
55     COORD       c;
56     WORD        attr = DEFAULT_ATTRIB;
57     char        ch;
58     DWORD       len;
59
60     for (c.X = 0; c.X < sbSize.X; c.X++)
61     {
62         for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
63         {
64             ch = (content) ? CONTENT(c) : ' ';
65             WriteConsoleOutputAttribute(hCon, &attr, 1, c, &len);
66             WriteConsoleOutputCharacterA(hCon, &ch, 1, c, &len);
67         }
68     }
69 }
70
71 static void testCursor(HANDLE hCon, COORD sbSize)
72 {
73     COORD               c;
74
75     c.X = c.Y = 0;
76     ok(SetConsoleCursorPosition(0, c) == 0, "No handle\n");
77     ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %lu\n",
78        ERROR_INVALID_HANDLE, GetLastError());
79
80     c.X = c.Y = 0;
81     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
82     okCURSOR(hCon, c);
83
84     c.X = sbSize.X - 1;
85     c.Y = sbSize.Y - 1;
86     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in lower-right\n");
87     okCURSOR(hCon, c);
88
89     c.X = sbSize.X;
90     c.Y = sbSize.Y - 1;
91     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
92     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
93        ERROR_INVALID_PARAMETER, GetLastError());
94
95     c.X = sbSize.X - 1;
96     c.Y = sbSize.Y;
97     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
98     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
99        ERROR_INVALID_PARAMETER, GetLastError());
100
101     c.X = -1;
102     c.Y = 0;
103     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
104     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
105        ERROR_INVALID_PARAMETER, GetLastError());
106
107     c.X = 0;
108     c.Y = -1;
109     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
110     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
111        ERROR_INVALID_PARAMETER, GetLastError());
112 }
113
114 static void testWriteSimple(HANDLE hCon, COORD sbSize)
115 {
116     COORD               c;
117     DWORD               len;
118     const char*         mytest = "abcdefg";
119     const int   mylen = strlen(mytest);
120
121     /* single line write */
122     c.X = c.Y = 0;
123     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
124
125     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
126     c.Y = 0;
127     for (c.X = 0; c.X < mylen; c.X++)
128     {
129         okCHAR(hCon, c, mytest[c.X], TEST_ATTRIB);
130     }
131
132     okCURSOR(hCon, c);
133     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
134 }
135
136 static void testWriteNotWrappedNotProcessed(HANDLE hCon, COORD sbSize)
137 {
138     COORD               c;
139     DWORD               len, mode;
140     char*               mytest;
141     int                 mylen;
142     int                 ret;
143     int                 p;
144
145     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode & ~(ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT)),
146        "clearing wrap at EOL & processed output\n");
147
148     /* write line, wrapping disabled, buffer exceeds sb width */
149     c.X = sbSize.X - 3; c.Y = 0;
150     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
151
152     mytest = "123";
153
154     mylen = strlen(mytest);
155
156     ret = WriteConsole(hCon, mytest, mylen, &len, NULL);
157     ok(ret != 0 && len == mylen, "Couldn't write, ret = %d, len = %ld\n", ret, len);
158     c.Y = 0;
159     for (p = mylen - 3; p < mylen; p++)
160     {
161         c.X = sbSize.X - 3 + p % 3;
162         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
163     }
164
165     c.X = 0; c.Y = 1;
166     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
167
168     p = sbSize.X - 3 + mylen % 3;
169     c.X = p; c.Y = 0;
170
171     /* write line, wrapping disabled, strings end on end of line */
172     c.X = sbSize.X - mylen; c.Y = 0;
173     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
174
175     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
176 }
177
178 static void testWriteNotWrappedProcessed(HANDLE hCon, COORD sbSize)
179 {
180     COORD               c;
181     DWORD               len, mode;
182     const char*         mytest = "abcd\nf\tg";
183     const int   mylen = strlen(mytest);
184     const int   mylen2 = strchr(mytest, '\n') - mytest;
185     int                 p;
186
187     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, (mode | ENABLE_PROCESSED_OUTPUT) & ~ENABLE_WRAP_AT_EOL_OUTPUT),
188        "clearing wrap at EOL & setting processed output\n");
189
190     /* write line, wrapping disabled, buffer exceeds sb width */
191     c.X = sbSize.X - 5; c.Y = 0;
192     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-5\n");
193
194     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
195     c.Y = 0;
196     for (c.X = sbSize.X - 5; c.X < sbSize.X - 1; c.X++)
197     {
198         okCHAR(hCon, c, mytest[c.X - sbSize.X + 5], TEST_ATTRIB);
199     }
200     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
201
202     c.X = 0; c.Y++;
203     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
204     for (c.X = 1; c.X < 8; c.X++)
205         okCHAR(hCon, c, ' ', TEST_ATTRIB);
206     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
207     c.X++;
208     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
209
210     okCURSOR(hCon, c);
211
212     /* write line, wrapping disabled, strings end on end of line */
213     c.X = sbSize.X - 4; c.Y = 0;
214     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
215
216     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
217     c.Y = 0;
218     for (c.X = sbSize.X - 4; c.X < sbSize.X; c.X++)
219     {
220         okCHAR(hCon, c, mytest[c.X - sbSize.X + 4], TEST_ATTRIB);
221     }
222     c.X = 0; c.Y++;
223     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
224     for (c.X = 1; c.X < 8; c.X++)
225         okCHAR(hCon, c, ' ', TEST_ATTRIB);
226     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
227     c.X++;
228     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
229
230     okCURSOR(hCon, c);
231
232     /* write line, wrapping disabled, strings end after end of line */
233     c.X = sbSize.X - 3; c.Y = 0;
234     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
235
236     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
237     c.Y = 0;
238     for (p = mylen2 - 3; p < mylen2; p++)
239     {
240         c.X = sbSize.X - 3 + p % 3;
241         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
242     }
243     c.X = 0; c.Y = 1;
244     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
245     for (c.X = 1; c.X < 8; c.X++)
246         okCHAR(hCon, c, ' ', TEST_ATTRIB);
247     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
248     c.X++;
249     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
250
251     okCURSOR(hCon, c);
252 }
253
254 static void testWriteWrappedNotProcessed(HANDLE hCon, COORD sbSize)
255 {
256     COORD               c;
257     DWORD               len, mode;
258     const char*         mytest = "abcd\nf\tg";
259     const int   mylen = strlen(mytest);
260     int                 p;
261
262     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon,(mode | ENABLE_WRAP_AT_EOL_OUTPUT) & ~(ENABLE_PROCESSED_OUTPUT)),
263        "setting wrap at EOL & clearing processed output\n");
264
265     /* write line, wrapping enabled, buffer doesn't exceed sb width */
266     c.X = sbSize.X - 9; c.Y = 0;
267     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
268
269     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
270     c.Y = 0;
271     for (p = 0; p < mylen; p++)
272     {
273         c.X = sbSize.X - 9 + p;
274         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
275     }
276     c.X = sbSize.X - 9 + mylen;
277     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
278     c.X = 0; c.Y = 1;
279     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
280
281     /* write line, wrapping enabled, buffer does exceed sb width */
282     c.X = sbSize.X - 3; c.Y = 0;
283     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
284
285     c.Y = 1;
286     c.X = mylen - 3;
287     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
288 }
289
290 static void testWriteWrappedProcessed(HANDLE hCon, COORD sbSize)
291 {
292     COORD               c;
293     DWORD               len, mode;
294     const char*         mytest = "abcd\nf\tg";
295     const int   mylen = strlen(mytest);
296     int                 p;
297
298     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode | (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)),
299        "setting wrap at EOL & processed output\n");
300
301     /* write line, wrapping enabled, buffer doesn't exceed sb width */
302     c.X = sbSize.X - 9; c.Y = 0;
303     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
304
305     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
306     for (p = 0; p < 4; p++)
307     {
308         c.X = sbSize.X - 9 + p;
309         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
310     }
311     c.X = sbSize.X - 9 + p;
312     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
313     c.X = 0; c.Y++;
314     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
315     for (c.X = 1; c.X < 8; c.X++)
316         okCHAR(hCon, c, ' ', TEST_ATTRIB);
317     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
318     c.X++;
319     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
320     okCURSOR(hCon, c);
321
322     /* write line, wrapping enabled, buffer does exceed sb width */
323     c.X = sbSize.X - 3; c.Y = 2;
324     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
325
326     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
327     for (p = 0; p < 3; p++)
328     {
329         c.X = sbSize.X - 3 + p;
330         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
331     }
332     c.X = 0; c.Y++;
333     okCHAR(hCon, c, mytest[3], TEST_ATTRIB);
334     c.X++;
335     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
336
337     c.X = 0; c.Y++;
338     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
339     for (c.X = 1; c.X < 8; c.X++)
340         okCHAR(hCon, c, ' ', TEST_ATTRIB);
341     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
342     c.X++;
343     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
344     okCURSOR(hCon, c);
345 }
346
347 static void testWrite(HANDLE hCon, COORD sbSize)
348 {
349     /* FIXME: should in fact insure that the sb is at least 10 character wide */
350     ok(SetConsoleTextAttribute(hCon, TEST_ATTRIB), "Setting default text color\n");
351     resetContent(hCon, sbSize, FALSE);
352     testWriteSimple(hCon, sbSize);
353     resetContent(hCon, sbSize, FALSE);
354     testWriteNotWrappedNotProcessed(hCon, sbSize);
355     resetContent(hCon, sbSize, FALSE);
356     testWriteNotWrappedProcessed(hCon, sbSize);
357     resetContent(hCon, sbSize, FALSE);
358     testWriteWrappedNotProcessed(hCon, sbSize);
359     resetContent(hCon, sbSize, FALSE);
360     testWriteWrappedProcessed(hCon, sbSize);
361 }
362
363 #if 0
364 static void testScroll(HANDLE hCon, COORD sbSize)
365 {
366     SMALL_RECT  scroll, clip;
367     COORD       dst, c, tc;
368     CHAR_INFO   ci;
369
370 #define W 11
371 #define H 7
372
373     /* no clipping, src & dst rect don't overlap */
374     resetContent(hCon, sbSize, TRUE);
375
376 #define IN_SRECT(r,c) ((r).Left <= (c).X && (c).X <= (r).Right && (r).Top <= (c).Y && (c).Y <= (r).Bottom)
377 #define IN_SRECT2(r,d,c) ((d).X <= (c).X && (c).X <= (d).X + (r).Right - (r).Left && (d).Y <= (c).Y && (c).Y <= (d).Y + (r).Bottom - (r).Top)
378
379     scroll.Left = 0;
380     scroll.Right = W - 1;
381     scroll.Top = 0;
382     scroll.Bottom = H - 1;
383     dst.X = W + 3;
384     dst.Y = H + 3;
385     ci.Char.UnicodeChar = '#';
386     ci.Attributes = TEST_ATTRIB;
387
388     clip.Left = 0;
389     clip.Right = sbSize.X - 1;
390     clip.Top = 0;
391     clip.Bottom = sbSize.Y - 1;
392
393     ok(ScrollConsoleScreenBuffer(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
394
395     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
396     {
397         for (c.X = 0; c.X < sbSize.X; c.X++)
398         {
399             if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
400             {
401                 tc.X = c.X - dst.X;
402                 tc.Y = c.Y - dst.Y;
403                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
404             }
405             else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
406                 okCHAR(hCon, c, '#', TEST_ATTRIB);
407             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
408         }
409     }
410
411     /* no clipping, src & dst rect do overlap */
412     resetContent(hCon, sbSize, TRUE);
413
414     scroll.Left = 0;
415     scroll.Right = W - 1;
416     scroll.Top = 0;
417     scroll.Bottom = H - 1;
418     dst.X = W /2;
419     dst.Y = H / 2;
420     ci.Char.UnicodeChar = '#';
421     ci.Attributes = TEST_ATTRIB;
422
423     clip.Left = 0;
424     clip.Right = sbSize.X - 1;
425     clip.Top = 0;
426     clip.Bottom = sbSize.Y - 1;
427
428     ok(ScrollConsoleScreenBuffer(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
429
430     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
431     {
432         for (c.X = 0; c.X < sbSize.X; c.X++)
433         {
434             if (dst.X <= c.X && c.X < dst.X + W && dst.Y <= c.Y && c.Y < dst.Y + H)
435             {
436                 tc.X = c.X - dst.X;
437                 tc.Y = c.Y - dst.Y;
438                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
439             }
440             else if (c.X < W && c.Y < H) okCHAR(hCon, c, '#', TEST_ATTRIB);
441             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
442         }
443     }
444
445     /* clipping, src & dst rect don't overlap */
446     resetContent(hCon, sbSize, TRUE);
447
448     scroll.Left = 0;
449     scroll.Right = W - 1;
450     scroll.Top = 0;
451     scroll.Bottom = H - 1;
452     dst.X = W + 3;
453     dst.Y = H + 3;
454     ci.Char.UnicodeChar = '#';
455     ci.Attributes = TEST_ATTRIB;
456
457     clip.Left = W / 2;
458     clip.Right = min(W + W / 2, sbSize.X - 1);
459     clip.Top = H / 2;
460     clip.Bottom = min(H + H / 2, sbSize.Y - 1);
461
462     ok(ScrollConsoleScreenBuffer(hCon, &scroll, &clip, dst, &ci), "Scrolling SB\n");
463
464     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
465     {
466         for (c.X = 0; c.X < sbSize.X; c.X++)
467         {
468             if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
469             {
470                 tc.X = c.X - dst.X;
471                 tc.Y = c.Y - dst.Y;
472                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
473             }
474             else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
475                 okCHAR(hCon, c, '#', TEST_ATTRIB);
476             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
477         }
478     }
479
480     /* clipping, src & dst rect do overlap */
481     resetContent(hCon, sbSize, TRUE);
482
483     scroll.Left = 0;
484     scroll.Right = W - 1;
485     scroll.Top = 0;
486     scroll.Bottom = H - 1;
487     dst.X = W / 2 - 3;
488     dst.Y = H / 2 - 3;
489     ci.Char.UnicodeChar = '#';
490     ci.Attributes = TEST_ATTRIB;
491
492     clip.Left = W / 2;
493     clip.Right = min(W + W / 2, sbSize.X - 1);
494     clip.Top = H / 2;
495     clip.Bottom = min(H + H / 2, sbSize.Y - 1);
496
497     ok(ScrollConsoleScreenBuffer(hCon, &scroll, &clip, dst, &ci), "Scrolling SB\n");
498
499     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
500     {
501         for (c.X = 0; c.X < sbSize.X; c.X++)
502         {
503             if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
504             {
505                 tc.X = c.X - dst.X;
506                 tc.Y = c.Y - dst.Y;
507                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
508             }
509             else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
510                 okCHAR(hCon, c, '#', TEST_ATTRIB);
511             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
512         }
513     }
514 }
515 #endif
516
517 START_TEST(console)
518 {
519     HANDLE hConIn, hConOut;
520     BOOL ret;
521     CONSOLE_SCREEN_BUFFER_INFO  sbi;
522
523     /* be sure we have a clean console (and that's our own)
524      * FIXME: this will make the test fail (currently) if we don't run
525      * under X11
526      * Another solution would be to rerun the test under wineconsole with
527      * the curses backend
528      */
529
530     hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
531     hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
532
533     /* first, we need to be sure we're attached to a console */
534     if (hConIn == INVALID_HANDLE_VALUE || hConOut == INVALID_HANDLE_VALUE)
535     {
536         /* we're not attached to a console, let's do it */
537         AllocConsole();
538         hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
539         hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
540     }
541     /* now verify everything's ok */
542     ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
543     ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
544
545     ok(ret = GetConsoleScreenBufferInfo(hConOut, &sbi), "Getting sb info\n");
546     if (!ret) return;
547
548     /* Non interactive tests */
549     testCursor(hConOut, sbi.dwSize);
550     /* will test wrapped (on/off) & processed (on/off) strings output */
551     testWrite(hConOut, sbi.dwSize);
552     /* will test line scrolling at the bottom of the screen */
553     /* testBottomScroll(); */
554     /* will test all the scrolling operations */
555     /* this one is disabled for now, Wine's result are way too bad */
556     /* testScroll(hCon, sbi.dwSize); */
557     /* will test sb creation / modification... */
558     /* testScreenBuffer() */
559
560     /* still to be done: events generation, access rights & access on objects */
561 }