github.com/go-xe2/third@v1.0.3/golang.org/x/sys/windows/registry/registry_test.go (about)

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