| // Copyright 2015 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // +build windows |
| |
| package registry_test |
| |
| import ( |
| "bytes" |
| "crypto/rand" |
| "os" |
| "syscall" |
| "testing" |
| "time" |
| "unsafe" |
| |
| "golang.org/x/sys/windows/registry" |
| ) |
| |
| func randKeyName(prefix string) string { |
| const numbers = "0123456789" |
| buf := make([]byte, 10) |
| rand.Read(buf) |
| for i, b := range buf { |
| buf[i] = numbers[b%byte(len(numbers))] |
| } |
| return prefix + string(buf) |
| } |
| |
| func TestReadSubKeyNames(t *testing.T) { |
| k, err := registry.OpenKey(registry.CLASSES_ROOT, "TypeLib", registry.ENUMERATE_SUB_KEYS) |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer k.Close() |
| |
| names, err := k.ReadSubKeyNames(-1) |
| if err != nil { |
| t.Fatal(err) |
| } |
| var foundStdOle bool |
| for _, name := range names { |
| // Every PC has "stdole 2.0 OLE Automation" library installed. |
| if name == "{00020430-0000-0000-C000-000000000046}" { |
| foundStdOle = true |
| } |
| } |
| if !foundStdOle { |
| t.Fatal("could not find stdole 2.0 OLE Automation") |
| } |
| } |
| |
| func TestCreateOpenDeleteKey(t *testing.T) { |
| k, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE) |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer k.Close() |
| |
| testKName := randKeyName("TestCreateOpenDeleteKey_") |
| |
| testK, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY) |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer testK.Close() |
| |
| if exist { |
| t.Fatalf("key %q already exists", testKName) |
| } |
| |
| testKAgain, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY) |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer testKAgain.Close() |
| |
| if !exist { |
| t.Fatalf("key %q should already exist", testKName) |
| } |
| |
| testKOpened, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS) |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer testKOpened.Close() |
| |
| err = registry.DeleteKey(k, testKName) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| testKOpenedAgain, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS) |
| if err == nil { |
| defer testKOpenedAgain.Close() |
| t.Fatalf("key %q should already been deleted", testKName) |
| } |
| if err != registry.ErrNotExist { |
| t.Fatalf(`unexpected error ("not exist" expected): %v`, err) |
| } |
| } |
| |
| func equalStringSlice(a, b []string) bool { |
| if len(a) != len(b) { |
| return false |
| } |
| if a == nil { |
| return true |
| } |
| for i := range a { |
| if a[i] != b[i] { |
| return false |
| } |
| } |
| return true |
| } |
| |
| type ValueTest struct { |
| Type uint32 |
| Name string |
| Value interface{} |
| WillFail bool |
| } |
| |
| var ValueTests = []ValueTest{ |
| {Type: registry.SZ, Name: "String1", Value: ""}, |
| {Type: registry.SZ, Name: "String2", Value: "\000", WillFail: true}, |
| {Type: registry.SZ, Name: "String3", Value: "Hello World"}, |
| {Type: registry.SZ, Name: "String4", Value: "Hello World\000", WillFail: true}, |
| {Type: registry.EXPAND_SZ, Name: "ExpString1", Value: ""}, |
| {Type: registry.EXPAND_SZ, Name: "ExpString2", Value: "\000", WillFail: true}, |
| {Type: registry.EXPAND_SZ, Name: "ExpString3", Value: "Hello World"}, |
| {Type: registry.EXPAND_SZ, Name: "ExpString4", Value: "Hello\000World", WillFail: true}, |
| {Type: registry.EXPAND_SZ, Name: "ExpString5", Value: "%PATH%"}, |
| {Type: registry.EXPAND_SZ, Name: "ExpString6", Value: "%NO_SUCH_VARIABLE%"}, |
| {Type: registry.EXPAND_SZ, Name: "ExpString7", Value: "%PATH%;."}, |
| {Type: registry.BINARY, Name: "Binary1", Value: []byte{}}, |
| {Type: registry.BINARY, Name: "Binary2", Value: []byte{1, 2, 3}}, |
| {Type: registry.BINARY, Name: "Binary3", Value: []byte{3, 2, 1, 0, 1, 2, 3}}, |
| {Type: registry.DWORD, Name: "Dword1", Value: uint64(0)}, |
| {Type: registry.DWORD, Name: "Dword2", Value: uint64(1)}, |
| {Type: registry.DWORD, Name: "Dword3", Value: uint64(0xff)}, |
| {Type: registry.DWORD, Name: "Dword4", Value: uint64(0xffff)}, |
| {Type: registry.QWORD, Name: "Qword1", Value: uint64(0)}, |
| {Type: registry.QWORD, Name: "Qword2", Value: uint64(1)}, |
| {Type: registry.QWORD, Name: "Qword3", Value: uint64(0xff)}, |
| {Type: registry.QWORD, Name: "Qword4", Value: uint64(0xffff)}, |
| {Type: registry.QWORD, Name: "Qword5", Value: uint64(0xffffff)}, |
| {Type: registry.QWORD, Name: "Qword6", Value: uint64(0xffffffff)}, |
| {Type: registry.MULTI_SZ, Name: "MultiString1", Value: []string{"a", "b", "c"}}, |
| {Type: registry.MULTI_SZ, Name: "MultiString2", Value: []string{"abc", "", "cba"}}, |
| {Type: registry.MULTI_SZ, Name: "MultiString3", Value: []string{""}}, |
| {Type: registry.MULTI_SZ, Name: "MultiString4", Value: []string{"abcdef"}}, |
| {Type: registry.MULTI_SZ, Name: "MultiString5", Value: []string{"\000"}, WillFail: true}, |
| {Type: registry.MULTI_SZ, Name: "MultiString6", Value: []string{"a\000b"}, WillFail: true}, |
| {Type: registry.MULTI_SZ, Name: "MultiString7", Value: []string{"ab", "\000", "cd"}, WillFail: true}, |
| {Type: registry.MULTI_SZ, Name: "MultiString8", Value: []string{"\000", "cd"}, WillFail: true}, |
| {Type: registry.MULTI_SZ, Name: "MultiString9", Value: []string{"ab", "\000"}, WillFail: true}, |
| } |
| |
| func setValues(t *testing.T, k registry.Key) { |
| for _, test := range ValueTests { |
| var err error |
| switch test.Type { |
| case registry.SZ: |
| err = k.SetStringValue(test.Name, test.Value.(string)) |
| case registry.EXPAND_SZ: |
| err = k.SetExpandStringValue(test.Name, test.Value.(string)) |
| case registry.MULTI_SZ: |
| err = k.SetStringsValue(test.Name, test.Value.([]string)) |
| case registry.BINARY: |
| err = k.SetBinaryValue(test.Name, test.Value.([]byte)) |
| case registry.DWORD: |
| err = k.SetDWordValue(test.Name, uint32(test.Value.(uint64))) |
| case registry.QWORD: |
| err = k.SetQWordValue(test.Name, test.Value.(uint64)) |
| default: |
| t.Fatalf("unsupported type %d for %s value", test.Type, test.Name) |
| } |
| if test.WillFail { |
| if err == nil { |
| t.Fatalf("setting %s value %q should fail, but succeeded", test.Name, test.Value) |
| } |
| } else { |
| if err != nil { |
| t.Fatal(err) |
| } |
| } |
| } |
| } |
| |
| func enumerateValues(t *testing.T, k registry.Key) { |
| names, err := k.ReadValueNames(-1) |
| if err != nil { |
| t.Error(err) |
| return |
| } |
| haveNames := make(map[string]bool) |
| for _, n := range names { |
| haveNames[n] = false |
| } |
| for _, test := range ValueTests { |
| wantFound := !test.WillFail |
| _, haveFound := haveNames[test.Name] |
| if wantFound && !haveFound { |
| t.Errorf("value %s is not found while enumerating", test.Name) |
| } |
| if haveFound && !wantFound { |
| t.Errorf("value %s is found while enumerating, but expected to fail", test.Name) |
| } |
| if haveFound { |
| delete(haveNames, test.Name) |
| } |
| } |
| for n, v := range haveNames { |
| t.Errorf("value %s (%v) is found while enumerating, but has not been cretaed", n, v) |
| } |
| } |
| |
| func testErrNotExist(t *testing.T, name string, err error) { |
| if err == nil { |
| t.Errorf("%s value should not exist", name) |
| return |
| } |
| if err != registry.ErrNotExist { |
| t.Errorf("reading %s value should return 'not exist' error, but got: %s", name, err) |
| return |
| } |
| } |
| |
| func testErrUnexpectedType(t *testing.T, test ValueTest, gottype uint32, err error) { |
| if err == nil { |
| t.Errorf("GetXValue(%q) should not succeed", test.Name) |
| return |
| } |
| if err != registry.ErrUnexpectedType { |
| t.Errorf("reading %s value should return 'unexpected key value type' error, but got: %s", test.Name, err) |
| return |
| } |
| if gottype != test.Type { |
| t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) |
| return |
| } |
| } |
| |
| func testGetStringValue(t *testing.T, k registry.Key, test ValueTest) { |
| got, gottype, err := k.GetStringValue(test.Name) |
| if err != nil { |
| t.Errorf("GetStringValue(%s) failed: %v", test.Name, err) |
| return |
| } |
| if got != test.Value { |
| t.Errorf("want %s value %q, got %q", test.Name, test.Value, got) |
| return |
| } |
| if gottype != test.Type { |
| t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) |
| return |
| } |
| if gottype == registry.EXPAND_SZ { |
| _, err = registry.ExpandString(got) |
| if err != nil { |
| t.Errorf("ExpandString(%s) failed: %v", got, err) |
| return |
| } |
| } |
| } |
| |
| func testGetIntegerValue(t *testing.T, k registry.Key, test ValueTest) { |
| got, gottype, err := k.GetIntegerValue(test.Name) |
| if err != nil { |
| t.Errorf("GetIntegerValue(%s) failed: %v", test.Name, err) |
| return |
| } |
| if got != test.Value.(uint64) { |
| t.Errorf("want %s value %v, got %v", test.Name, test.Value, got) |
| return |
| } |
| if gottype != test.Type { |
| t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) |
| return |
| } |
| } |
| |
| func testGetBinaryValue(t *testing.T, k registry.Key, test ValueTest) { |
| got, gottype, err := k.GetBinaryValue(test.Name) |
| if err != nil { |
| t.Errorf("GetBinaryValue(%s) failed: %v", test.Name, err) |
| return |
| } |
| if !bytes.Equal(got, test.Value.([]byte)) { |
| t.Errorf("want %s value %v, got %v", test.Name, test.Value, got) |
| return |
| } |
| if gottype != test.Type { |
| t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) |
| return |
| } |
| } |
| |
| func testGetStringsValue(t *testing.T, k registry.Key, test ValueTest) { |
| got, gottype, err := k.GetStringsValue(test.Name) |
| if err != nil { |
| t.Errorf("GetStringsValue(%s) failed: %v", test.Name, err) |
| return |
| } |
| if !equalStringSlice(got, test.Value.([]string)) { |
| t.Errorf("want %s value %#v, got %#v", test.Name, test.Value, got) |
| return |
| } |
| if gottype != test.Type { |
| t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) |
| return |
| } |
| } |
| |
| func testGetValue(t *testing.T, k registry.Key, test ValueTest, size int) { |
| if size <= 0 { |
| return |
| } |
| // read data with no buffer |
| gotsize, gottype, err := k.GetValue(test.Name, nil) |
| if err != nil { |
| t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err) |
| return |
| } |
| if gotsize != size { |
| t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize) |
| return |
| } |
| if gottype != test.Type { |
| t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) |
| return |
| } |
| // read data with short buffer |
| gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size-1)) |
| if err == nil { |
| t.Errorf("GetValue(%s, [%d]byte) should fail, but succeeded", test.Name, size-1) |
| return |
| } |
| if err != registry.ErrShortBuffer { |
| t.Errorf("reading %s value should return 'short buffer' error, but got: %s", test.Name, err) |
| return |
| } |
| if gotsize != size { |
| t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize) |
| return |
| } |
| if gottype != test.Type { |
| t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) |
| return |
| } |
| // read full data |
| gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size)) |
| if err != nil { |
| t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err) |
| return |
| } |
| if gotsize != size { |
| t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize) |
| return |
| } |
| if gottype != test.Type { |
| t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) |
| return |
| } |
| // check GetValue returns ErrNotExist as required |
| _, _, err = k.GetValue(test.Name+"_not_there", make([]byte, size)) |
| if err == nil { |
| t.Errorf("GetValue(%q) should not succeed", test.Name) |
| return |
| } |
| if err != registry.ErrNotExist { |
| t.Errorf("GetValue(%q) should return 'not exist' error, but got: %s", test.Name, err) |
| return |
| } |
| } |
| |
| func testValues(t *testing.T, k registry.Key) { |
| for _, test := range ValueTests { |
| switch test.Type { |
| case registry.SZ, registry.EXPAND_SZ: |
| if test.WillFail { |
| _, _, err := k.GetStringValue(test.Name) |
| testErrNotExist(t, test.Name, err) |
| } else { |
| testGetStringValue(t, k, test) |
| _, gottype, err := k.GetIntegerValue(test.Name) |
| testErrUnexpectedType(t, test, gottype, err) |
| // Size of utf16 string in bytes is not perfect, |
| // but correct for current test values. |
| // Size also includes terminating 0. |
| testGetValue(t, k, test, (len(test.Value.(string))+1)*2) |
| } |
| _, _, err := k.GetStringValue(test.Name + "_string_not_created") |
| testErrNotExist(t, test.Name+"_string_not_created", err) |
| case registry.DWORD, registry.QWORD: |
| testGetIntegerValue(t, k, test) |
| _, gottype, err := k.GetBinaryValue(test.Name) |
| testErrUnexpectedType(t, test, gottype, err) |
| _, _, err = k.GetIntegerValue(test.Name + "_int_not_created") |
| testErrNotExist(t, test.Name+"_int_not_created", err) |
| size := 8 |
| if test.Type == registry.DWORD { |
| size = 4 |
| } |
| testGetValue(t, k, test, size) |
| case registry.BINARY: |
| testGetBinaryValue(t, k, test) |
| _, gottype, err := k.GetStringsValue(test.Name) |
| testErrUnexpectedType(t, test, gottype, err) |
| _, _, err = k.GetBinaryValue(test.Name + "_byte_not_created") |
| testErrNotExist(t, test.Name+"_byte_not_created", err) |
| testGetValue(t, k, test, len(test.Value.([]byte))) |
| case registry.MULTI_SZ: |
| if test.WillFail { |
| _, _, err := k.GetStringsValue(test.Name) |
| testErrNotExist(t, test.Name, err) |
| } else { |
| testGetStringsValue(t, k, test) |
| _, gottype, err := k.GetStringValue(test.Name) |
| testErrUnexpectedType(t, test, gottype, err) |
| size := 0 |
| for _, s := range test.Value.([]string) { |
| size += len(s) + 1 // nil terminated |
| } |
| size += 1 // extra nil at the end |
| size *= 2 // count bytes, not uint16 |
| testGetValue(t, k, test, size) |
| } |
| _, _, err := k.GetStringsValue(test.Name + "_strings_not_created") |
| testErrNotExist(t, test.Name+"_strings_not_created", err) |
| default: |
| t.Errorf("unsupported type %d for %s value", test.Type, test.Name) |
| continue |
| } |
| } |
| } |
| |
| func testStat(t *testing.T, k registry.Key) { |
| subk, _, err := registry.CreateKey(k, "subkey", registry.CREATE_SUB_KEY) |
| if err != nil { |
| t.Error(err) |
| return |
| } |
| defer subk.Close() |
| |
| defer registry.DeleteKey(k, "subkey") |
| |
| ki, err := k.Stat() |
| if err != nil { |
| t.Error(err) |
| return |
| } |
| if ki.SubKeyCount != 1 { |
| t.Error("key must have 1 subkey") |
| } |
| if ki.MaxSubKeyLen != 6 { |
| t.Error("key max subkey name length must be 6") |
| } |
| if ki.ValueCount != 24 { |
| t.Errorf("key must have 24 values, but is %d", ki.ValueCount) |
| } |
| if ki.MaxValueNameLen != 12 { |
| t.Errorf("key max value name length must be 10, but is %d", ki.MaxValueNameLen) |
| } |
| if ki.MaxValueLen != 38 { |
| t.Errorf("key max value length must be 38, but is %d", ki.MaxValueLen) |
| } |
| if mt, ct := ki.ModTime(), time.Now(); ct.Sub(mt) > 100*time.Millisecond { |
| t.Errorf("key mod time is not close to current time: mtime=%v current=%v delta=%v", mt, ct, ct.Sub(mt)) |
| } |
| } |
| |
| func deleteValues(t *testing.T, k registry.Key) { |
| for _, test := range ValueTests { |
| if test.WillFail { |
| continue |
| } |
| err := k.DeleteValue(test.Name) |
| if err != nil { |
| t.Error(err) |
| continue |
| } |
| } |
| names, err := k.ReadValueNames(-1) |
| if err != nil { |
| t.Error(err) |
| return |
| } |
| if len(names) != 0 { |
| t.Errorf("some values remain after deletion: %v", names) |
| } |
| } |
| |
| func TestValues(t *testing.T) { |
| softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE) |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer softwareK.Close() |
| |
| testKName := randKeyName("TestValues_") |
| |
| k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE) |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer k.Close() |
| |
| if exist { |
| t.Fatalf("key %q already exists", testKName) |
| } |
| |
| defer registry.DeleteKey(softwareK, testKName) |
| |
| setValues(t, k) |
| |
| enumerateValues(t, k) |
| |
| testValues(t, k) |
| |
| testStat(t, k) |
| |
| deleteValues(t, k) |
| } |
| |
| func walkKey(t *testing.T, k registry.Key, kname string) { |
| names, err := k.ReadValueNames(-1) |
| if err != nil { |
| t.Fatalf("reading value names of %s failed: %v", kname, err) |
| } |
| for _, name := range names { |
| _, valtype, err := k.GetValue(name, nil) |
| if err != nil { |
| t.Fatalf("reading value type of %s of %s failed: %v", name, kname, err) |
| } |
| switch valtype { |
| case registry.NONE: |
| case registry.SZ: |
| _, _, err := k.GetStringValue(name) |
| if err != nil { |
| t.Error(err) |
| } |
| case registry.EXPAND_SZ: |
| s, _, err := k.GetStringValue(name) |
| if err != nil { |
| t.Error(err) |
| } |
| _, err = registry.ExpandString(s) |
| if err != nil { |
| t.Error(err) |
| } |
| case registry.DWORD, registry.QWORD: |
| _, _, err := k.GetIntegerValue(name) |
| if err != nil { |
| t.Error(err) |
| } |
| case registry.BINARY: |
| _, _, err := k.GetBinaryValue(name) |
| if err != nil { |
| t.Error(err) |
| } |
| case registry.MULTI_SZ: |
| _, _, err := k.GetStringsValue(name) |
| if err != nil { |
| t.Error(err) |
| } |
| case registry.FULL_RESOURCE_DESCRIPTOR, registry.RESOURCE_LIST, registry.RESOURCE_REQUIREMENTS_LIST: |
| // TODO: not implemented |
| default: |
| t.Fatalf("value type %d of %s of %s failed: %v", valtype, name, kname, err) |
| } |
| } |
| |
| names, err = k.ReadSubKeyNames(-1) |
| if err != nil { |
| t.Fatalf("reading sub-keys of %s failed: %v", kname, err) |
| } |
| for _, name := range names { |
| func() { |
| subk, err := registry.OpenKey(k, name, registry.ENUMERATE_SUB_KEYS|registry.QUERY_VALUE) |
| if err != nil { |
| if err == syscall.ERROR_ACCESS_DENIED { |
| // ignore error, if we are not allowed to access this key |
| return |
| } |
| t.Fatalf("opening sub-keys %s of %s failed: %v", name, kname, err) |
| } |
| defer subk.Close() |
| |
| walkKey(t, subk, kname+`\`+name) |
| }() |
| } |
| } |
| |
| func TestWalkFullRegistry(t *testing.T) { |
| if testing.Short() { |
| t.Skip("skipping long running test in short mode") |
| } |
| walkKey(t, registry.CLASSES_ROOT, "CLASSES_ROOT") |
| walkKey(t, registry.CURRENT_USER, "CURRENT_USER") |
| walkKey(t, registry.LOCAL_MACHINE, "LOCAL_MACHINE") |
| walkKey(t, registry.USERS, "USERS") |
| walkKey(t, registry.CURRENT_CONFIG, "CURRENT_CONFIG") |
| } |
| |
| func TestExpandString(t *testing.T) { |
| got, err := registry.ExpandString("%PATH%") |
| if err != nil { |
| t.Fatal(err) |
| } |
| want := os.Getenv("PATH") |
| if got != want { |
| t.Errorf("want %q string expanded, got %q", want, got) |
| } |
| } |
| |
| func TestInvalidValues(t *testing.T) { |
| softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE) |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer softwareK.Close() |
| |
| testKName := randKeyName("TestInvalidValues_") |
| |
| k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE) |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer k.Close() |
| |
| if exist { |
| t.Fatalf("key %q already exists", testKName) |
| } |
| |
| defer registry.DeleteKey(softwareK, testKName) |
| |
| var tests = []struct { |
| Type uint32 |
| Name string |
| Data []byte |
| }{ |
| {registry.DWORD, "Dword1", nil}, |
| {registry.DWORD, "Dword2", []byte{1, 2, 3}}, |
| {registry.QWORD, "Qword1", nil}, |
| {registry.QWORD, "Qword2", []byte{1, 2, 3}}, |
| {registry.QWORD, "Qword3", []byte{1, 2, 3, 4, 5, 6, 7}}, |
| {registry.MULTI_SZ, "MultiString1", nil}, |
| {registry.MULTI_SZ, "MultiString2", []byte{0}}, |
| {registry.MULTI_SZ, "MultiString3", []byte{'a', 'b', 0}}, |
| {registry.MULTI_SZ, "MultiString4", []byte{'a', 0, 0, 'b', 0}}, |
| {registry.MULTI_SZ, "MultiString5", []byte{'a', 0, 0}}, |
| } |
| |
| for _, test := range tests { |
| err := k.SetValue(test.Name, test.Type, test.Data) |
| if err != nil { |
| t.Fatalf("SetValue for %q failed: %v", test.Name, err) |
| } |
| } |
| |
| for _, test := range tests { |
| switch test.Type { |
| case registry.DWORD, registry.QWORD: |
| value, valType, err := k.GetIntegerValue(test.Name) |
| if err == nil { |
| t.Errorf("GetIntegerValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value) |
| } |
| case registry.MULTI_SZ: |
| value, valType, err := k.GetStringsValue(test.Name) |
| if err == nil { |
| if len(value) != 0 { |
| t.Errorf("GetStringsValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value) |
| } |
| } |
| default: |
| t.Errorf("unsupported type %d for %s value", test.Type, test.Name) |
| } |
| } |
| } |
| |
| func TestGetMUIStringValue(t *testing.T) { |
| if err := registry.LoadRegLoadMUIString(); err != nil { |
| t.Skip("regLoadMUIString not supported; skipping") |
| } |
| if err := procGetDynamicTimeZoneInformation.Find(); err != nil { |
| t.Skipf("%s not supported; skipping", procGetDynamicTimeZoneInformation.Name) |
| } |
| var dtzi DynamicTimezoneinformation |
| if _, err := GetDynamicTimeZoneInformation(&dtzi); err != nil { |
| t.Fatal(err) |
| } |
| tzKeyName := syscall.UTF16ToString(dtzi.TimeZoneKeyName[:]) |
| timezoneK, err := registry.OpenKey(registry.LOCAL_MACHINE, |
| `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\`+tzKeyName, registry.READ) |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer timezoneK.Close() |
| |
| type testType struct { |
| name string |
| want string |
| } |
| var tests = []testType{ |
| {"MUI_Std", syscall.UTF16ToString(dtzi.StandardName[:])}, |
| } |
| if dtzi.DynamicDaylightTimeDisabled == 0 { |
| tests = append(tests, testType{"MUI_Dlt", syscall.UTF16ToString(dtzi.DaylightName[:])}) |
| } |
| |
| for _, test := range tests { |
| got, err := timezoneK.GetMUIStringValue(test.name) |
| if err != nil { |
| t.Error("GetMUIStringValue:", err) |
| } |
| |
| if got != test.want { |
| t.Errorf("GetMUIStringValue: %s: Got %q, want %q", test.name, got, test.want) |
| } |
| } |
| } |
| |
| type DynamicTimezoneinformation struct { |
| Bias int32 |
| StandardName [32]uint16 |
| StandardDate syscall.Systemtime |
| StandardBias int32 |
| DaylightName [32]uint16 |
| DaylightDate syscall.Systemtime |
| DaylightBias int32 |
| TimeZoneKeyName [128]uint16 |
| DynamicDaylightTimeDisabled uint8 |
| } |
| |
| var ( |
| kernel32DLL = syscall.NewLazyDLL("kernel32") |
| |
| procGetDynamicTimeZoneInformation = kernel32DLL.NewProc("GetDynamicTimeZoneInformation") |
| ) |
| |
| func GetDynamicTimeZoneInformation(dtzi *DynamicTimezoneinformation) (rc uint32, err error) { |
| r0, _, e1 := syscall.Syscall(procGetDynamicTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(dtzi)), 0, 0) |
| rc = uint32(r0) |
| if rc == 0xffffffff { |
| if e1 != 0 { |
| err = error(e1) |
| } else { |
| err = syscall.EINVAL |
| } |
| } |
| return |
| } |