mirror of
https://github.com/golang/sys.git
synced 2026-02-08 11:46:04 +03:00
This test's existence was predicated upon assumptions about the full range of known data types and known data into those types. However, we've learned from Microsoft that there are several undocumented secret registry types that are in use by various parts of Windows, and we've learned from inspection that many Microsoft uses of registry types don't strictly adhere to the recommended value size. It's therefore foolhardy to make any assumptions about what goes in and out of the registry, and so this test is meaningless and error-prone. Updates golang/go#35084 Change-Id: Ie545229afd8dc5bde90fffa0f735f7102cd4a6eb Reviewed-on: https://go-review.googlesource.com/c/sys/+/203605 Run-TryBot: Jason A. Donenfeld <Jason@zx2c4.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
677 lines
19 KiB
Go
677 lines
19 KiB
Go
// 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 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
|
|
}
|