]>
Commit | Line | Data |
---|---|---|
af146490 ILT |
1 | // Copyright 2015 The Go Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style | |
3 | // license that can be found in the LICENSE file. | |
4 | ||
5 | // +build windows | |
6 | ||
7 | package registry_test | |
8 | ||
9 | import ( | |
10 | "bytes" | |
11 | "crypto/rand" | |
12 | "os" | |
13 | "syscall" | |
14 | "testing" | |
f98dd1a3 | 15 | "unsafe" |
af146490 ILT |
16 | |
17 | "internal/syscall/windows/registry" | |
18 | ) | |
19 | ||
20 | func randKeyName(prefix string) string { | |
21 | const numbers = "0123456789" | |
22 | buf := make([]byte, 10) | |
23 | rand.Read(buf) | |
24 | for i, b := range buf { | |
25 | buf[i] = numbers[b%byte(len(numbers))] | |
26 | } | |
27 | return prefix + string(buf) | |
28 | } | |
29 | ||
30 | func TestReadSubKeyNames(t *testing.T) { | |
dd931d9b | 31 | k, err := registry.OpenKey(registry.CLASSES_ROOT, "TypeLib", registry.ENUMERATE_SUB_KEYS) |
af146490 ILT |
32 | if err != nil { |
33 | t.Fatal(err) | |
34 | } | |
35 | defer k.Close() | |
36 | ||
37 | names, err := k.ReadSubKeyNames(-1) | |
38 | if err != nil { | |
39 | t.Fatal(err) | |
40 | } | |
41 | var foundStdOle bool | |
42 | for _, name := range names { | |
43 | // Every PC has "stdole 2.0 OLE Automation" library installed. | |
44 | if name == "{00020430-0000-0000-C000-000000000046}" { | |
45 | foundStdOle = true | |
46 | } | |
47 | } | |
48 | if !foundStdOle { | |
49 | t.Fatal("could not find stdole 2.0 OLE Automation") | |
50 | } | |
51 | } | |
52 | ||
53 | func TestCreateOpenDeleteKey(t *testing.T) { | |
54 | k, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE) | |
55 | if err != nil { | |
56 | t.Fatal(err) | |
57 | } | |
58 | defer k.Close() | |
59 | ||
60 | testKName := randKeyName("TestCreateOpenDeleteKey_") | |
61 | ||
62 | testK, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY) | |
63 | if err != nil { | |
64 | t.Fatal(err) | |
65 | } | |
66 | defer testK.Close() | |
67 | ||
68 | if exist { | |
69 | t.Fatalf("key %q already exists", testKName) | |
70 | } | |
71 | ||
72 | testKAgain, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY) | |
73 | if err != nil { | |
74 | t.Fatal(err) | |
75 | } | |
76 | defer testKAgain.Close() | |
77 | ||
78 | if !exist { | |
79 | t.Fatalf("key %q should already exist", testKName) | |
80 | } | |
81 | ||
82 | testKOpened, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS) | |
83 | if err != nil { | |
84 | t.Fatal(err) | |
85 | } | |
86 | defer testKOpened.Close() | |
87 | ||
88 | err = registry.DeleteKey(k, testKName) | |
89 | if err != nil { | |
90 | t.Fatal(err) | |
91 | } | |
92 | ||
93 | testKOpenedAgain, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS) | |
94 | if err == nil { | |
95 | defer testKOpenedAgain.Close() | |
96 | t.Fatalf("key %q should already been deleted", testKName) | |
97 | } | |
98 | if err != registry.ErrNotExist { | |
99 | t.Fatalf(`unexpected error ("not exist" expected): %v`, err) | |
100 | } | |
101 | } | |
102 | ||
103 | func equalStringSlice(a, b []string) bool { | |
104 | if len(a) != len(b) { | |
105 | return false | |
106 | } | |
107 | if a == nil { | |
108 | return true | |
109 | } | |
110 | for i := range a { | |
111 | if a[i] != b[i] { | |
112 | return false | |
113 | } | |
114 | } | |
115 | return true | |
116 | } | |
117 | ||
118 | type ValueTest struct { | |
119 | Type uint32 | |
120 | Name string | |
121 | Value interface{} | |
122 | WillFail bool | |
123 | } | |
124 | ||
125 | var ValueTests = []ValueTest{ | |
126 | {Type: registry.SZ, Name: "String1", Value: ""}, | |
127 | {Type: registry.SZ, Name: "String2", Value: "\000", WillFail: true}, | |
128 | {Type: registry.SZ, Name: "String3", Value: "Hello World"}, | |
129 | {Type: registry.SZ, Name: "String4", Value: "Hello World\000", WillFail: true}, | |
130 | {Type: registry.EXPAND_SZ, Name: "ExpString1", Value: ""}, | |
131 | {Type: registry.EXPAND_SZ, Name: "ExpString2", Value: "\000", WillFail: true}, | |
132 | {Type: registry.EXPAND_SZ, Name: "ExpString3", Value: "Hello World"}, | |
133 | {Type: registry.EXPAND_SZ, Name: "ExpString4", Value: "Hello\000World", WillFail: true}, | |
134 | {Type: registry.EXPAND_SZ, Name: "ExpString5", Value: "%PATH%"}, | |
135 | {Type: registry.EXPAND_SZ, Name: "ExpString6", Value: "%NO_SUCH_VARIABLE%"}, | |
136 | {Type: registry.EXPAND_SZ, Name: "ExpString7", Value: "%PATH%;."}, | |
137 | {Type: registry.BINARY, Name: "Binary1", Value: []byte{}}, | |
138 | {Type: registry.BINARY, Name: "Binary2", Value: []byte{1, 2, 3}}, | |
139 | {Type: registry.BINARY, Name: "Binary3", Value: []byte{3, 2, 1, 0, 1, 2, 3}}, | |
140 | {Type: registry.DWORD, Name: "Dword1", Value: uint64(0)}, | |
141 | {Type: registry.DWORD, Name: "Dword2", Value: uint64(1)}, | |
142 | {Type: registry.DWORD, Name: "Dword3", Value: uint64(0xff)}, | |
143 | {Type: registry.DWORD, Name: "Dword4", Value: uint64(0xffff)}, | |
144 | {Type: registry.QWORD, Name: "Qword1", Value: uint64(0)}, | |
145 | {Type: registry.QWORD, Name: "Qword2", Value: uint64(1)}, | |
146 | {Type: registry.QWORD, Name: "Qword3", Value: uint64(0xff)}, | |
147 | {Type: registry.QWORD, Name: "Qword4", Value: uint64(0xffff)}, | |
148 | {Type: registry.QWORD, Name: "Qword5", Value: uint64(0xffffff)}, | |
149 | {Type: registry.QWORD, Name: "Qword6", Value: uint64(0xffffffff)}, | |
150 | {Type: registry.MULTI_SZ, Name: "MultiString1", Value: []string{"a", "b", "c"}}, | |
151 | {Type: registry.MULTI_SZ, Name: "MultiString2", Value: []string{"abc", "", "cba"}}, | |
152 | {Type: registry.MULTI_SZ, Name: "MultiString3", Value: []string{""}}, | |
153 | {Type: registry.MULTI_SZ, Name: "MultiString4", Value: []string{"abcdef"}}, | |
154 | {Type: registry.MULTI_SZ, Name: "MultiString5", Value: []string{"\000"}, WillFail: true}, | |
155 | {Type: registry.MULTI_SZ, Name: "MultiString6", Value: []string{"a\000b"}, WillFail: true}, | |
156 | {Type: registry.MULTI_SZ, Name: "MultiString7", Value: []string{"ab", "\000", "cd"}, WillFail: true}, | |
157 | {Type: registry.MULTI_SZ, Name: "MultiString8", Value: []string{"\000", "cd"}, WillFail: true}, | |
158 | {Type: registry.MULTI_SZ, Name: "MultiString9", Value: []string{"ab", "\000"}, WillFail: true}, | |
159 | } | |
160 | ||
161 | func setValues(t *testing.T, k registry.Key) { | |
162 | for _, test := range ValueTests { | |
163 | var err error | |
164 | switch test.Type { | |
165 | case registry.SZ: | |
166 | err = k.SetStringValue(test.Name, test.Value.(string)) | |
167 | case registry.EXPAND_SZ: | |
168 | err = k.SetExpandStringValue(test.Name, test.Value.(string)) | |
169 | case registry.MULTI_SZ: | |
170 | err = k.SetStringsValue(test.Name, test.Value.([]string)) | |
171 | case registry.BINARY: | |
172 | err = k.SetBinaryValue(test.Name, test.Value.([]byte)) | |
173 | case registry.DWORD: | |
174 | err = k.SetDWordValue(test.Name, uint32(test.Value.(uint64))) | |
175 | case registry.QWORD: | |
176 | err = k.SetQWordValue(test.Name, test.Value.(uint64)) | |
177 | default: | |
178 | t.Fatalf("unsupported type %d for %s value", test.Type, test.Name) | |
179 | } | |
180 | if test.WillFail { | |
181 | if err == nil { | |
182 | t.Fatalf("setting %s value %q should fail, but succeeded", test.Name, test.Value) | |
183 | } | |
184 | } else { | |
185 | if err != nil { | |
186 | t.Fatal(err) | |
187 | } | |
188 | } | |
189 | } | |
190 | } | |
191 | ||
192 | func enumerateValues(t *testing.T, k registry.Key) { | |
193 | names, err := k.ReadValueNames(-1) | |
194 | if err != nil { | |
195 | t.Error(err) | |
196 | return | |
197 | } | |
198 | haveNames := make(map[string]bool) | |
199 | for _, n := range names { | |
200 | haveNames[n] = false | |
201 | } | |
202 | for _, test := range ValueTests { | |
203 | wantFound := !test.WillFail | |
204 | _, haveFound := haveNames[test.Name] | |
205 | if wantFound && !haveFound { | |
206 | t.Errorf("value %s is not found while enumerating", test.Name) | |
207 | } | |
208 | if haveFound && !wantFound { | |
209 | t.Errorf("value %s is found while enumerating, but expected to fail", test.Name) | |
210 | } | |
211 | if haveFound { | |
212 | delete(haveNames, test.Name) | |
213 | } | |
214 | } | |
215 | for n, v := range haveNames { | |
22b955cc | 216 | t.Errorf("value %s (%v) is found while enumerating, but has not been created", n, v) |
af146490 ILT |
217 | } |
218 | } | |
219 | ||
220 | func testErrNotExist(t *testing.T, name string, err error) { | |
221 | if err == nil { | |
222 | t.Errorf("%s value should not exist", name) | |
223 | return | |
224 | } | |
225 | if err != registry.ErrNotExist { | |
226 | t.Errorf("reading %s value should return 'not exist' error, but got: %s", name, err) | |
227 | return | |
228 | } | |
229 | } | |
230 | ||
231 | func testErrUnexpectedType(t *testing.T, test ValueTest, gottype uint32, err error) { | |
232 | if err == nil { | |
233 | t.Errorf("GetXValue(%q) should not succeed", test.Name) | |
234 | return | |
235 | } | |
236 | if err != registry.ErrUnexpectedType { | |
237 | t.Errorf("reading %s value should return 'unexpected key value type' error, but got: %s", test.Name, err) | |
238 | return | |
239 | } | |
240 | if gottype != test.Type { | |
241 | t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) | |
242 | return | |
243 | } | |
244 | } | |
245 | ||
246 | func testGetStringValue(t *testing.T, k registry.Key, test ValueTest) { | |
247 | got, gottype, err := k.GetStringValue(test.Name) | |
248 | if err != nil { | |
249 | t.Errorf("GetStringValue(%s) failed: %v", test.Name, err) | |
250 | return | |
251 | } | |
252 | if got != test.Value { | |
253 | t.Errorf("want %s value %q, got %q", test.Name, test.Value, got) | |
254 | return | |
255 | } | |
256 | if gottype != test.Type { | |
257 | t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) | |
258 | return | |
259 | } | |
260 | if gottype == registry.EXPAND_SZ { | |
261 | _, err = registry.ExpandString(got) | |
262 | if err != nil { | |
263 | t.Errorf("ExpandString(%s) failed: %v", got, err) | |
264 | return | |
265 | } | |
266 | } | |
267 | } | |
268 | ||
269 | func testGetIntegerValue(t *testing.T, k registry.Key, test ValueTest) { | |
270 | got, gottype, err := k.GetIntegerValue(test.Name) | |
271 | if err != nil { | |
272 | t.Errorf("GetIntegerValue(%s) failed: %v", test.Name, err) | |
273 | return | |
274 | } | |
275 | if got != test.Value.(uint64) { | |
276 | t.Errorf("want %s value %v, got %v", test.Name, test.Value, got) | |
277 | return | |
278 | } | |
279 | if gottype != test.Type { | |
280 | t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) | |
281 | return | |
282 | } | |
283 | } | |
284 | ||
285 | func testGetBinaryValue(t *testing.T, k registry.Key, test ValueTest) { | |
286 | got, gottype, err := k.GetBinaryValue(test.Name) | |
287 | if err != nil { | |
288 | t.Errorf("GetBinaryValue(%s) failed: %v", test.Name, err) | |
289 | return | |
290 | } | |
291 | if !bytes.Equal(got, test.Value.([]byte)) { | |
292 | t.Errorf("want %s value %v, got %v", test.Name, test.Value, got) | |
293 | return | |
294 | } | |
295 | if gottype != test.Type { | |
296 | t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) | |
297 | return | |
298 | } | |
299 | } | |
300 | ||
301 | func testGetStringsValue(t *testing.T, k registry.Key, test ValueTest) { | |
302 | got, gottype, err := k.GetStringsValue(test.Name) | |
303 | if err != nil { | |
304 | t.Errorf("GetStringsValue(%s) failed: %v", test.Name, err) | |
305 | return | |
306 | } | |
307 | if !equalStringSlice(got, test.Value.([]string)) { | |
308 | t.Errorf("want %s value %#v, got %#v", test.Name, test.Value, got) | |
309 | return | |
310 | } | |
311 | if gottype != test.Type { | |
312 | t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) | |
313 | return | |
314 | } | |
315 | } | |
316 | ||
317 | func testGetValue(t *testing.T, k registry.Key, test ValueTest, size int) { | |
318 | if size <= 0 { | |
319 | return | |
320 | } | |
321 | // read data with no buffer | |
322 | gotsize, gottype, err := k.GetValue(test.Name, nil) | |
323 | if err != nil { | |
324 | t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err) | |
325 | return | |
326 | } | |
327 | if gotsize != size { | |
328 | t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize) | |
329 | return | |
330 | } | |
331 | if gottype != test.Type { | |
332 | t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) | |
333 | return | |
334 | } | |
335 | // read data with short buffer | |
336 | gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size-1)) | |
337 | if err == nil { | |
22b955cc | 338 | t.Errorf("GetValue(%s, [%d]byte) should fail, but succeeded", test.Name, size-1) |
af146490 ILT |
339 | return |
340 | } | |
341 | if err != registry.ErrShortBuffer { | |
342 | t.Errorf("reading %s value should return 'short buffer' error, but got: %s", test.Name, err) | |
343 | return | |
344 | } | |
345 | if gotsize != size { | |
346 | t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize) | |
347 | return | |
348 | } | |
349 | if gottype != test.Type { | |
350 | t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) | |
351 | return | |
352 | } | |
353 | // read full data | |
354 | gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size)) | |
355 | if err != nil { | |
356 | t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err) | |
357 | return | |
358 | } | |
359 | if gotsize != size { | |
360 | t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize) | |
361 | return | |
362 | } | |
363 | if gottype != test.Type { | |
364 | t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) | |
365 | return | |
366 | } | |
367 | // check GetValue returns ErrNotExist as required | |
368 | _, _, err = k.GetValue(test.Name+"_not_there", make([]byte, size)) | |
369 | if err == nil { | |
370 | t.Errorf("GetValue(%q) should not succeed", test.Name) | |
371 | return | |
372 | } | |
373 | if err != registry.ErrNotExist { | |
374 | t.Errorf("GetValue(%q) should return 'not exist' error, but got: %s", test.Name, err) | |
375 | return | |
376 | } | |
377 | } | |
378 | ||
379 | func testValues(t *testing.T, k registry.Key) { | |
380 | for _, test := range ValueTests { | |
381 | switch test.Type { | |
382 | case registry.SZ, registry.EXPAND_SZ: | |
383 | if test.WillFail { | |
384 | _, _, err := k.GetStringValue(test.Name) | |
385 | testErrNotExist(t, test.Name, err) | |
386 | } else { | |
387 | testGetStringValue(t, k, test) | |
388 | _, gottype, err := k.GetIntegerValue(test.Name) | |
389 | testErrUnexpectedType(t, test, gottype, err) | |
390 | // Size of utf16 string in bytes is not perfect, | |
391 | // but correct for current test values. | |
392 | // Size also includes terminating 0. | |
393 | testGetValue(t, k, test, (len(test.Value.(string))+1)*2) | |
394 | } | |
395 | _, _, err := k.GetStringValue(test.Name + "_string_not_created") | |
396 | testErrNotExist(t, test.Name+"_string_not_created", err) | |
397 | case registry.DWORD, registry.QWORD: | |
398 | testGetIntegerValue(t, k, test) | |
399 | _, gottype, err := k.GetBinaryValue(test.Name) | |
400 | testErrUnexpectedType(t, test, gottype, err) | |
401 | _, _, err = k.GetIntegerValue(test.Name + "_int_not_created") | |
402 | testErrNotExist(t, test.Name+"_int_not_created", err) | |
403 | size := 8 | |
404 | if test.Type == registry.DWORD { | |
405 | size = 4 | |
406 | } | |
407 | testGetValue(t, k, test, size) | |
408 | case registry.BINARY: | |
409 | testGetBinaryValue(t, k, test) | |
410 | _, gottype, err := k.GetStringsValue(test.Name) | |
411 | testErrUnexpectedType(t, test, gottype, err) | |
412 | _, _, err = k.GetBinaryValue(test.Name + "_byte_not_created") | |
413 | testErrNotExist(t, test.Name+"_byte_not_created", err) | |
414 | testGetValue(t, k, test, len(test.Value.([]byte))) | |
415 | case registry.MULTI_SZ: | |
416 | if test.WillFail { | |
417 | _, _, err := k.GetStringsValue(test.Name) | |
418 | testErrNotExist(t, test.Name, err) | |
419 | } else { | |
420 | testGetStringsValue(t, k, test) | |
421 | _, gottype, err := k.GetStringValue(test.Name) | |
422 | testErrUnexpectedType(t, test, gottype, err) | |
423 | size := 0 | |
424 | for _, s := range test.Value.([]string) { | |
425 | size += len(s) + 1 // nil terminated | |
426 | } | |
427 | size += 1 // extra nil at the end | |
428 | size *= 2 // count bytes, not uint16 | |
429 | testGetValue(t, k, test, size) | |
430 | } | |
431 | _, _, err := k.GetStringsValue(test.Name + "_strings_not_created") | |
432 | testErrNotExist(t, test.Name+"_strings_not_created", err) | |
433 | default: | |
434 | t.Errorf("unsupported type %d for %s value", test.Type, test.Name) | |
435 | continue | |
436 | } | |
437 | } | |
438 | } | |
439 | ||
440 | func testStat(t *testing.T, k registry.Key) { | |
441 | subk, _, err := registry.CreateKey(k, "subkey", registry.CREATE_SUB_KEY) | |
442 | if err != nil { | |
443 | t.Error(err) | |
444 | return | |
445 | } | |
446 | defer subk.Close() | |
447 | ||
448 | defer registry.DeleteKey(k, "subkey") | |
449 | ||
450 | ki, err := k.Stat() | |
451 | if err != nil { | |
452 | t.Error(err) | |
453 | return | |
454 | } | |
455 | if ki.SubKeyCount != 1 { | |
456 | t.Error("key must have 1 subkey") | |
457 | } | |
458 | if ki.MaxSubKeyLen != 6 { | |
459 | t.Error("key max subkey name length must be 6") | |
460 | } | |
461 | if ki.ValueCount != 24 { | |
462 | t.Errorf("key must have 24 values, but is %d", ki.ValueCount) | |
463 | } | |
464 | if ki.MaxValueNameLen != 12 { | |
465 | t.Errorf("key max value name length must be 10, but is %d", ki.MaxValueNameLen) | |
466 | } | |
467 | if ki.MaxValueLen != 38 { | |
468 | t.Errorf("key max value length must be 38, but is %d", ki.MaxValueLen) | |
469 | } | |
470 | } | |
471 | ||
472 | func deleteValues(t *testing.T, k registry.Key) { | |
473 | for _, test := range ValueTests { | |
474 | if test.WillFail { | |
475 | continue | |
476 | } | |
477 | err := k.DeleteValue(test.Name) | |
478 | if err != nil { | |
479 | t.Error(err) | |
480 | continue | |
481 | } | |
482 | } | |
483 | names, err := k.ReadValueNames(-1) | |
484 | if err != nil { | |
485 | t.Error(err) | |
486 | return | |
487 | } | |
488 | if len(names) != 0 { | |
489 | t.Errorf("some values remain after deletion: %v", names) | |
490 | } | |
491 | } | |
492 | ||
493 | func TestValues(t *testing.T) { | |
494 | softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE) | |
495 | if err != nil { | |
496 | t.Fatal(err) | |
497 | } | |
498 | defer softwareK.Close() | |
499 | ||
500 | testKName := randKeyName("TestValues_") | |
501 | ||
502 | k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE) | |
503 | if err != nil { | |
504 | t.Fatal(err) | |
505 | } | |
506 | defer k.Close() | |
507 | ||
508 | if exist { | |
509 | t.Fatalf("key %q already exists", testKName) | |
510 | } | |
511 | ||
512 | defer registry.DeleteKey(softwareK, testKName) | |
513 | ||
514 | setValues(t, k) | |
515 | ||
516 | enumerateValues(t, k) | |
517 | ||
518 | testValues(t, k) | |
519 | ||
520 | testStat(t, k) | |
521 | ||
522 | deleteValues(t, k) | |
523 | } | |
524 | ||
af146490 ILT |
525 | func TestExpandString(t *testing.T) { |
526 | got, err := registry.ExpandString("%PATH%") | |
527 | if err != nil { | |
528 | t.Fatal(err) | |
529 | } | |
530 | want := os.Getenv("PATH") | |
531 | if got != want { | |
532 | t.Errorf("want %q string expanded, got %q", want, got) | |
533 | } | |
534 | } | |
535 | ||
536 | func TestInvalidValues(t *testing.T) { | |
537 | softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE) | |
538 | if err != nil { | |
539 | t.Fatal(err) | |
540 | } | |
541 | defer softwareK.Close() | |
542 | ||
543 | testKName := randKeyName("TestInvalidValues_") | |
544 | ||
545 | k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE) | |
546 | if err != nil { | |
547 | t.Fatal(err) | |
548 | } | |
549 | defer k.Close() | |
550 | ||
551 | if exist { | |
552 | t.Fatalf("key %q already exists", testKName) | |
553 | } | |
554 | ||
555 | defer registry.DeleteKey(softwareK, testKName) | |
556 | ||
557 | var tests = []struct { | |
558 | Type uint32 | |
559 | Name string | |
560 | Data []byte | |
561 | }{ | |
562 | {registry.DWORD, "Dword1", nil}, | |
563 | {registry.DWORD, "Dword2", []byte{1, 2, 3}}, | |
564 | {registry.QWORD, "Qword1", nil}, | |
565 | {registry.QWORD, "Qword2", []byte{1, 2, 3}}, | |
566 | {registry.QWORD, "Qword3", []byte{1, 2, 3, 4, 5, 6, 7}}, | |
567 | {registry.MULTI_SZ, "MultiString1", nil}, | |
568 | {registry.MULTI_SZ, "MultiString2", []byte{0}}, | |
569 | {registry.MULTI_SZ, "MultiString3", []byte{'a', 'b', 0}}, | |
570 | {registry.MULTI_SZ, "MultiString4", []byte{'a', 0, 0, 'b', 0}}, | |
571 | {registry.MULTI_SZ, "MultiString5", []byte{'a', 0, 0}}, | |
572 | } | |
573 | ||
574 | for _, test := range tests { | |
575 | err := k.SetValue(test.Name, test.Type, test.Data) | |
576 | if err != nil { | |
577 | t.Fatalf("SetValue for %q failed: %v", test.Name, err) | |
578 | } | |
579 | } | |
580 | ||
581 | for _, test := range tests { | |
582 | switch test.Type { | |
583 | case registry.DWORD, registry.QWORD: | |
584 | value, valType, err := k.GetIntegerValue(test.Name) | |
585 | if err == nil { | |
586 | t.Errorf("GetIntegerValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value) | |
587 | } | |
588 | case registry.MULTI_SZ: | |
589 | value, valType, err := k.GetStringsValue(test.Name) | |
590 | if err == nil { | |
591 | if len(value) != 0 { | |
592 | t.Errorf("GetStringsValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value) | |
593 | } | |
594 | } | |
595 | default: | |
596 | t.Errorf("unsupported type %d for %s value", test.Type, test.Name) | |
597 | } | |
598 | } | |
599 | } | |
f98dd1a3 ILT |
600 | |
601 | func TestGetMUIStringValue(t *testing.T) { | |
602 | if err := registry.LoadRegLoadMUIString(); err != nil { | |
603 | t.Skip("regLoadMUIString not supported; skipping") | |
604 | } | |
605 | if err := procGetDynamicTimeZoneInformation.Find(); err != nil { | |
606 | t.Skipf("%s not supported; skipping", procGetDynamicTimeZoneInformation.Name) | |
607 | } | |
608 | var dtzi DynamicTimezoneinformation | |
609 | if _, err := GetDynamicTimeZoneInformation(&dtzi); err != nil { | |
610 | t.Fatal(err) | |
611 | } | |
612 | tzKeyName := syscall.UTF16ToString(dtzi.TimeZoneKeyName[:]) | |
613 | timezoneK, err := registry.OpenKey(registry.LOCAL_MACHINE, | |
614 | `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\`+tzKeyName, registry.READ) | |
615 | if err != nil { | |
616 | t.Fatal(err) | |
617 | } | |
618 | defer timezoneK.Close() | |
619 | ||
620 | type testType struct { | |
621 | name string | |
622 | want string | |
623 | } | |
624 | var tests = []testType{ | |
625 | {"MUI_Std", syscall.UTF16ToString(dtzi.StandardName[:])}, | |
626 | } | |
627 | if dtzi.DynamicDaylightTimeDisabled == 0 { | |
628 | tests = append(tests, testType{"MUI_Dlt", syscall.UTF16ToString(dtzi.DaylightName[:])}) | |
629 | } | |
630 | ||
631 | for _, test := range tests { | |
632 | got, err := timezoneK.GetMUIStringValue(test.name) | |
633 | if err != nil { | |
634 | t.Error("GetMUIStringValue:", err) | |
635 | } | |
636 | ||
637 | if got != test.want { | |
638 | t.Errorf("GetMUIStringValue: %s: Got %q, want %q", test.name, got, test.want) | |
639 | } | |
640 | } | |
641 | } | |
642 | ||
643 | type DynamicTimezoneinformation struct { | |
644 | Bias int32 | |
645 | StandardName [32]uint16 | |
646 | StandardDate syscall.Systemtime | |
647 | StandardBias int32 | |
648 | DaylightName [32]uint16 | |
649 | DaylightDate syscall.Systemtime | |
650 | DaylightBias int32 | |
651 | TimeZoneKeyName [128]uint16 | |
652 | DynamicDaylightTimeDisabled uint8 | |
653 | } | |
654 | ||
655 | var ( | |
656 | kernel32DLL = syscall.NewLazyDLL("kernel32") | |
657 | ||
658 | procGetDynamicTimeZoneInformation = kernel32DLL.NewProc("GetDynamicTimeZoneInformation") | |
659 | ) | |
660 | ||
661 | func GetDynamicTimeZoneInformation(dtzi *DynamicTimezoneinformation) (rc uint32, err error) { | |
662 | r0, _, e1 := syscall.Syscall(procGetDynamicTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(dtzi)), 0, 0) | |
663 | rc = uint32(r0) | |
664 | if rc == 0xffffffff { | |
665 | if e1 != 0 { | |
666 | err = error(e1) | |
667 | } else { | |
668 | err = syscall.EINVAL | |
669 | } | |
670 | } | |
671 | return | |
672 | } |