msi: Fix the registry root indices for Installer::RegistryValue.
[wine] / dlls / msi / tests / record.c
1 /*
2  * Copyright (C) 2005 Mike McCormack for CodeWeavers
3  *
4  * A test program for MSI records
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <windows.h>
22 #include <msi.h>
23 #include <msiquery.h>
24
25 #include "wine/test.h"
26
27 static BOOL create_temp_file(char *name)
28 {
29     UINT r;
30     unsigned char buffer[26], i;
31     DWORD sz;
32     HANDLE handle;
33     
34     r = GetTempFileName(".", "msitest",0,name);
35     if(!r)
36         return r;
37     handle = CreateFile(name, GENERIC_READ|GENERIC_WRITE, 
38         0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
39     if(handle==INVALID_HANDLE_VALUE)
40         return 0;
41     for(i=0; i<26; i++)
42         buffer[i]=i+'a';
43     r = WriteFile(handle,buffer,sizeof buffer,&sz,NULL);
44     CloseHandle(handle);
45     return r;
46 }
47
48 static void test_msirecord(void)
49 {
50     DWORD r, sz;
51     INT i;
52     MSIHANDLE h;
53     char buf[10];
54     WCHAR bufW[10];
55     const char str[] = "hello";
56     const WCHAR strW[] = { 'h','e','l','l','o',0};
57     char filename[MAX_PATH];
58
59     /* check behaviour with an invalid record */
60     r = MsiRecordGetFieldCount(0);
61     ok(r==-1, "field count for invalid record not -1\n");
62     SetLastError(0);
63     r = MsiRecordIsNull(0, 0);
64     ok(r==0, "invalid handle not considered to be non-null...\n");
65     ok(GetLastError()==0, "MsiRecordIsNull set LastError\n");
66     r = MsiRecordGetInteger(0,0);
67     ok(r == MSI_NULL_INTEGER, "got integer from invalid record\n");
68     r = MsiRecordSetInteger(0,0,0);
69     ok(r == ERROR_INVALID_HANDLE, "MsiRecordSetInteger returned wrong error\n");
70     r = MsiRecordSetInteger(0,-1,0);
71     ok(r == ERROR_INVALID_HANDLE, "MsiRecordSetInteger returned wrong error\n");
72     SetLastError(0);
73     h = MsiCreateRecord(-1);
74     ok(h==0, "created record with -1 elements\n");
75     h = MsiCreateRecord(0x10000);
76     ok(h==0, "created record with 0x10000 elements\n");
77     /* doesn't set LastError */
78     ok(GetLastError()==0, "MsiCreateRecord set last error\n");
79     r = MsiRecordClearData(0);
80     ok(r == ERROR_INVALID_HANDLE, "MsiRecordClearData returned wrong error\n");
81     r = MsiRecordDataSize(0,0);
82     ok(r == 0, "MsiRecordDataSize returned wrong error\n");
83
84
85     /* check behaviour of a record with 0 elements */
86     h = MsiCreateRecord(0);
87     ok(h!=0, "couldn't create record with zero elements\n");
88     r = MsiRecordGetFieldCount(h);
89     ok(r==0, "field count should be zero\n");
90     r = MsiRecordIsNull(h,0);
91     ok(r, "new record wasn't null\n");
92     r = MsiRecordIsNull(h,1);
93     ok(r, "out of range record wasn't null\n");
94     r = MsiRecordIsNull(h,-1);
95     ok(r, "out of range record wasn't null\n");
96     r = MsiRecordDataSize(h,0);
97     ok(r==0, "size of null record is 0\n");
98     sz = sizeof buf;
99     strcpy(buf,"x");
100     r = MsiRecordGetString(h, 0, buf, &sz);
101     ok(r==ERROR_SUCCESS, "failed to get null string\n");
102     ok(sz==0, "null string too long\n");
103     ok(buf[0]==0, "null string not set\n");
104
105     /* same record, but add an integer to it */
106     r = MsiRecordSetInteger(h, 0, 0);
107     ok(r == ERROR_SUCCESS, "Failed to set integer at 0 to 0\n");
108     r = MsiRecordIsNull(h,0);
109     ok(r==0, "new record is null after setting an integer\n");
110     r = MsiRecordDataSize(h,0);
111     ok(r==sizeof(DWORD), "size of integer record is 4\n");
112     r = MsiRecordSetInteger(h, 0, 1);
113     ok(r == ERROR_SUCCESS, "Failed to set integer at 0 to 1\n");
114     r = MsiRecordSetInteger(h, 1, 1);
115     ok(r == ERROR_INVALID_PARAMETER, "set integer at 1\n");
116     r = MsiRecordSetInteger(h, -1, 0);
117     ok(r == ERROR_INVALID_PARAMETER, "set integer at -1\n");
118     r = MsiRecordIsNull(h,0);
119     ok(r==0, "new record is null after setting an integer\n");
120     r = MsiRecordGetInteger(h, 0);
121     ok(r == 1, "failed to get integer\n");
122
123     /* same record, but add a string to it */
124     r = MsiRecordSetString(h, 0, NULL);
125     ok(r == ERROR_SUCCESS, "Failed to set null string at 0\n");
126     r = MsiRecordIsNull(h, 0);
127     ok(r == TRUE, "null string not null field\n");
128     r = MsiRecordSetString(h, 0, "");
129     ok(r == ERROR_SUCCESS, "Failed to set empty string at 0\n");
130     r = MsiRecordIsNull(h, 0);
131     ok(r == TRUE, "null string not null field\n");
132     r = MsiRecordSetString(h,0,str);
133     ok(r == ERROR_SUCCESS, "Failed to set string at 0\n");
134     r = MsiRecordGetInteger(h, 0);
135     ok(r == MSI_NULL_INTEGER, "should get invalid integer\n");
136     r = MsiRecordDataSize(h,0);
137     ok(r==sizeof str-1, "size of string record is strlen\n");
138     buf[0]=0;
139     sz = sizeof buf;
140     r = MsiRecordGetString(h,0,buf,&sz);
141     ok(r == ERROR_SUCCESS, "Failed to get string at 0\n");
142     ok(0==strcmp(buf,str), "MsiRecordGetString returned the wrong string\n");
143     ok(sz == sizeof str-1, "MsiRecordGetString returned the wrong length\n");
144     buf[0]=0;
145     sz = sizeof str - 2;
146     r = MsiRecordGetString(h,0,buf,&sz);
147     ok(r == ERROR_MORE_DATA, "small buffer should yield ERROR_MORE_DATA\n");
148     ok(sz == sizeof str-1, "MsiRecordGetString returned the wrong length\n");
149     ok(0==strncmp(buf,str,sizeof str-3), "MsiRecordGetString returned the wrong string\n");
150     ok(buf[sizeof str - 3]==0, "string wasn't nul terminated\n");
151
152     buf[0]=0;
153     sz = sizeof str;
154     r = MsiRecordGetString(h,0,buf,&sz);
155     ok(r == ERROR_SUCCESS, "wrong error\n");
156     ok(sz == sizeof str-1, "MsiRecordGetString returned the wrong length\n");
157     ok(0==strcmp(buf,str), "MsiRecordGetString returned the wrong string\n");
158
159
160     memset(bufW, 0, sizeof bufW);
161     sz = 5;
162     r = MsiRecordGetStringW(h,0,bufW,&sz);
163     ok(r == ERROR_MORE_DATA, "wrong error\n");
164     ok(sz == 5, "MsiRecordGetString returned the wrong length\n");
165     ok(0==memcmp(bufW,strW,8), "MsiRecordGetString returned the wrong string\n");
166
167     sz = 0;
168     bufW[0] = 'x';
169     r = MsiRecordGetStringW(h,0,bufW,&sz);
170     ok(r == ERROR_MORE_DATA, "wrong error\n");
171     ok(sz == 5, "MsiRecordGetString returned the wrong length\n");
172     ok('x'==bufW[0], "MsiRecordGetString returned the wrong string\n");
173
174     memset(buf, 0, sizeof buf);
175     sz = 5;
176     r = MsiRecordGetStringA(h,0,buf,&sz);
177     ok(r == ERROR_MORE_DATA, "wrong error\n");
178     ok(sz == 5, "MsiRecordGetString returned the wrong length\n");
179     ok(0==memcmp(buf,str,4), "MsiRecordGetString returned the wrong string\n");
180
181     sz = 0;
182     buf[0] = 'x';
183     r = MsiRecordGetStringA(h,0,buf,&sz);
184     ok(r == ERROR_MORE_DATA, "wrong error\n");
185     ok(sz == 5, "MsiRecordGetString returned the wrong length\n");
186     ok('x'==buf[0], "MsiRecordGetString returned the wrong string\n");
187
188     /* same record, check we can wipe all the data */
189     r = MsiRecordClearData(h);
190     ok(r == ERROR_SUCCESS, "Failed to clear record\n");
191     r = MsiRecordClearData(h);
192     ok(r == ERROR_SUCCESS, "Failed to clear record again\n");
193     r = MsiRecordIsNull(h,0);
194     ok(r, "cleared record wasn't null\n");
195
196     /* same record, try converting strings to integers */
197     i = MsiRecordSetString(h,0,"42");
198     ok(i == ERROR_SUCCESS, "Failed to set string at 0\n");
199     i = MsiRecordGetInteger(h, 0);
200     ok(i == 42, "should get invalid integer\n");
201     i = MsiRecordSetString(h,0,"-42");
202     ok(i == ERROR_SUCCESS, "Failed to set string at 0\n");
203     i = MsiRecordGetInteger(h, 0);
204     ok(i == -42, "should get invalid integer\n");
205     i = MsiRecordSetString(h,0," 42");
206     ok(i == ERROR_SUCCESS, "Failed to set string at 0\n");
207     i = MsiRecordGetInteger(h, 0);
208     ok(i == MSI_NULL_INTEGER, "should get invalid integer\n");
209     i = MsiRecordSetString(h,0,"42 ");
210     ok(i == ERROR_SUCCESS, "Failed to set string at 0\n");
211     i = MsiRecordGetInteger(h, 0);
212     ok(i == MSI_NULL_INTEGER, "should get invalid integer\n");
213     i = MsiRecordSetString(h,0,"42.0");
214     ok(i == ERROR_SUCCESS, "Failed to set string at 0\n");
215     i = MsiRecordGetInteger(h, 0);
216     ok(i == MSI_NULL_INTEGER, "should get invalid integer\n");
217     i = MsiRecordSetString(h,0,"0x42");
218     ok(i == ERROR_SUCCESS, "Failed to set string at 0\n");
219     i = MsiRecordGetInteger(h, 0);
220     ok(i == MSI_NULL_INTEGER, "should get invalid integer\n");
221     i = MsiRecordSetString(h,0,"1000000000000000");
222     ok(i == ERROR_SUCCESS, "Failed to set string at 0\n");
223     i = MsiRecordGetInteger(h, 0);
224     ok(i == -1530494976, "should get truncated integer\n");
225     i = MsiRecordSetString(h,0,"2147483647");
226     ok(i == ERROR_SUCCESS, "Failed to set string at 0\n");
227     i = MsiRecordGetInteger(h, 0);
228     ok(i == 2147483647, "should get maxint\n");
229     i = MsiRecordSetString(h,0,"-2147483647");
230     ok(i == ERROR_SUCCESS, "Failed to set string at 0\n");
231     i = MsiRecordGetInteger(h, 0);
232     ok(i == -2147483647, "should get -maxint-1\n");
233     i = MsiRecordSetString(h,0,"4294967297");
234     ok(i == ERROR_SUCCESS, "Failed to set string at 0\n");
235     i = MsiRecordGetInteger(h, 0);
236     ok(i == 1, "should get one\n");
237     i = MsiRecordSetString(h,0,"foo");
238     ok(i == ERROR_SUCCESS, "Failed to set string at 0\n");
239     i = MsiRecordGetInteger(h, 0);
240     ok(i == MSI_NULL_INTEGER, "should get zero\n");
241     i = MsiRecordSetString(h,0,"");
242     ok(i == ERROR_SUCCESS, "Failed to set string at 0\n");
243     i = MsiRecordGetInteger(h, 0);
244     ok(i == MSI_NULL_INTEGER, "should get zero\n");
245     i = MsiRecordSetString(h,0,"+1");
246     ok(i == ERROR_SUCCESS, "Failed to set string at 0\n");
247     i = MsiRecordGetInteger(h, 0);
248     ok(i == MSI_NULL_INTEGER, "should get zero\n");
249
250     /* same record, try converting integers to strings */
251     r = MsiRecordSetInteger(h, 0, 32);
252     ok(r == ERROR_SUCCESS, "Failed to set integer at 0 to 32\n");
253     sz = 1;
254     r = MsiRecordGetString(h, 0, NULL, &sz);
255     ok(r == ERROR_SUCCESS, "failed to get string from integer\n");
256     ok(sz == 2, "length wrong\n");
257     buf[0]=0;
258     sz = sizeof buf;
259     r = MsiRecordGetString(h, 0, buf, &sz);
260     ok(r == ERROR_SUCCESS, "failed to get string from integer\n");
261     ok(0==strcmp(buf,"32"), "failed to get string from integer\n");
262     r = MsiRecordSetInteger(h, 0, -32);
263     ok(r == ERROR_SUCCESS, "Failed to set integer at 0 to 32\n");
264     buf[0]=0;
265     sz = 1;
266     r = MsiRecordGetString(h, 0, NULL, &sz);
267     ok(r == ERROR_SUCCESS, "failed to get string from integer\n");
268     ok(sz == 3, "length wrong\n");
269     sz = sizeof buf;
270     r = MsiRecordGetString(h, 0, buf, &sz);
271     ok(r == ERROR_SUCCESS, "failed to get string from integer\n");
272     ok(0==strcmp(buf,"-32"), "failed to get string from integer\n");
273     buf[0]=0;
274
275     /* same record, now try streams */
276     r = MsiRecordSetStream(h, 0, NULL);
277     ok(r == ERROR_INVALID_PARAMETER, "set NULL stream\n");
278     sz = sizeof buf;
279     r = MsiRecordReadStream(h, 0, buf, &sz);
280     ok(r == ERROR_INVALID_DATATYPE, "read non-stream type\n");
281     ok(sz == sizeof buf, "set sz\n");
282     r = MsiRecordDataSize( h, -1);
283     ok(r == 0,"MsiRecordDataSize returned wrong size\n");
284     r = MsiRecordDataSize( h, 0);
285     ok(r == 4,"MsiRecordDataSize returned wrong size\n");
286
287     /* same record, now close it */
288     r = MsiCloseHandle(h);
289     ok(r == ERROR_SUCCESS, "Failed to close handle\n");
290
291     /* now try streams in a new record - need to create a file to play with */
292     r = create_temp_file(filename); 
293     if(!r)
294         return;
295
296     /* streams can't be inserted in field 0 for some reason */
297     h = MsiCreateRecord(2);
298     ok(h, "couldn't create a two field record\n");
299     r = MsiRecordSetStream(h, 0, filename);
300     ok(r == ERROR_INVALID_PARAMETER, "added stream to field 0\n");
301     r = MsiRecordSetStream(h, 1, filename);
302     ok(r == ERROR_SUCCESS, "failed to add stream to record\n");
303     r = MsiRecordReadStream(h, 1, buf, NULL);
304     ok(r == ERROR_INVALID_PARAMETER, "should return error\n");
305     /* http://test.winehq.org/data/200503181000/98_jmelgarejo98casa/msi:record.txt */
306     DeleteFile(filename); /* Windows 98 doesn't like this at all, so don't check return. */
307     r = MsiRecordReadStream(h, 1, NULL, NULL);
308     ok(r == ERROR_INVALID_PARAMETER, "should return error\n");
309     sz = sizeof buf;
310     r = MsiRecordReadStream(h, 1, NULL, &sz);
311     ok(r == ERROR_SUCCESS, "failed to read stream\n");
312     ok(sz==26,"couldn't get size of stream\n");
313     sz = 0;
314     r = MsiRecordReadStream(h, 1, buf, &sz);
315     ok(r == ERROR_SUCCESS, "failed to read stream\n");
316     ok(sz==0,"short read\n");
317     sz = sizeof buf;
318     r = MsiRecordReadStream(h, 1, buf, &sz);
319     ok(r == ERROR_SUCCESS, "failed to read stream\n");
320     ok(sz==sizeof buf,"short read\n");
321     ok(!strncmp(buf,"abcdefghij",10), "read the wrong thing\n");
322     sz = sizeof buf;
323     r = MsiRecordReadStream(h, 1, buf, &sz);
324     ok(r == ERROR_SUCCESS, "failed to read stream\n");
325     ok(sz==sizeof buf,"short read\n");
326     ok(!strncmp(buf,"klmnopqrst",10), "read the wrong thing\n");
327     memset(buf,0,sizeof buf);
328     sz = sizeof buf;
329     r = MsiRecordReadStream(h, 1, buf, &sz);
330     ok(r == ERROR_SUCCESS, "failed to read stream\n");
331     ok(sz==6,"short read\n");
332     ok(!strcmp(buf,"uvwxyz"), "read the wrong thing\n");
333     memset(buf,0,sizeof buf);
334     sz = sizeof buf;
335     r = MsiRecordReadStream(h, 1, buf, &sz);
336     ok(r == ERROR_SUCCESS, "failed to read stream\n");
337     ok(sz==0,"size non-zero at end of stream\n");
338     ok(buf[0]==0, "read something at end of the stream\n");
339     r = MsiRecordSetStream(h, 1, NULL);
340     ok(r == ERROR_SUCCESS, "failed to reset stream\n");
341     sz = 0;
342     r = MsiRecordReadStream(h, 1, NULL, &sz);
343     ok(r == ERROR_SUCCESS, "bytes left wrong after reset\n");
344     ok(sz==26,"couldn't get size of stream\n");
345     r = MsiRecordDataSize(h,1);
346     ok(r == 26,"MsiRecordDataSize returned wrong size\n");
347
348     /* now close the stream record */
349     r = MsiCloseHandle(h);
350     ok(r == ERROR_SUCCESS, "Failed to close handle\n");
351     DeleteFile(filename); /* Delete it for sure, when everything else is closed. */
352 }
353
354 static void test_MsiRecordGetString(void)
355 {
356     MSIHANDLE rec;
357     CHAR buf[MAX_PATH];
358     DWORD sz;
359     UINT r;
360
361     rec = MsiCreateRecord(2);
362     ok(rec != 0, "Expected a valid handle\n");
363
364     sz = MAX_PATH;
365     lstrcpyA(buf, "apple");
366     r = MsiRecordGetString(rec, 1, buf, &sz);
367     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
368     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
369     ok(sz == 0, "Expected 0, got %d\n", sz);
370
371     sz = MAX_PATH;
372     lstrcpyA(buf, "apple");
373     r = MsiRecordGetString(rec, 10, buf, &sz);
374     ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
375     ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
376     ok(sz == 0, "Expected 0, got %d\n", sz);
377
378     MsiCloseHandle(rec);
379 }
380
381 START_TEST(record)
382 {
383     test_msirecord();
384     test_MsiRecordGetString();
385 }