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