1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using Xunit; 7 8 namespace Microsoft.Win32.RegistryTests 9 { 10 public abstract class RegistryTestsBase : IDisposable 11 { 12 protected string TestRegistryKeyName { get; private set; } 13 protected RegistryKey TestRegistryKey { get; private set; } 14 RegistryTestsBase()15 protected RegistryTestsBase() 16 { 17 // Create a unique name for this test class 18 TestRegistryKeyName = CreateUniqueKeyName(); 19 20 // Cleanup the key in case a previous run of this test crashed and left 21 // the key behind. The key name is specific enough to corefx that we don't 22 // need to worry about it being a real key on the user's system used 23 // for another purpose. 24 RemoveKeyIfExists(TestRegistryKeyName); 25 26 // Then create the key. 27 TestRegistryKey = Registry.CurrentUser.CreateSubKey(TestRegistryKeyName, true); 28 Assert.NotNull(TestRegistryKey); 29 } 30 Dispose()31 public void Dispose() 32 { 33 TestRegistryKey.Dispose(); 34 RemoveKeyIfExists(TestRegistryKeyName); 35 } 36 RemoveKeyIfExists(string keyName)37 private static void RemoveKeyIfExists(string keyName) 38 { 39 RegistryKey rk = Registry.CurrentUser; 40 if (rk.OpenSubKey(keyName) != null) 41 { 42 rk.DeleteSubKeyTree(keyName); 43 Assert.Null(rk.OpenSubKey(keyName)); 44 } 45 } 46 CreateUniqueKeyName()47 private string CreateUniqueKeyName() 48 { 49 // Create a name to use for this class of tests. The name includes: 50 // - A "corefxtest" prefix to help make it clear to anyone looking at the registry 51 // that these keys are test-only and can be deleted, in case the tests crash and 52 // we end up leaving some keys behind. 53 // - The name of this test class, so as to avoid problems with tests on different test 54 // classes running concurrently 55 return "corefxtest_" + GetType().Name; 56 } 57 58 public static readonly object[][] TestRegistrySubKeyNames = 59 { 60 new object[] { @"Foo", @"Foo" }, 61 new object[] { @"Foo\Bar", @"Foo\Bar" }, 62 63 // Multiple/trailing slashes should be removed. 64 new object[] { @"Foo", @"Foo\" }, 65 new object[] { @"Foo", @"Foo\\" }, 66 new object[] { @"Foo", @"Foo\\\" }, 67 new object[] { @"Foo", @"Foo\\\\" }, 68 new object[] { @"Foo\Bar", @"Foo\\Bar" }, 69 new object[] { @"Foo\Bar", @"Foo\\\Bar" }, 70 new object[] { @"Foo\Bar", @"Foo\\\\Bar" }, 71 new object[] { @"Foo\Bar", @"Foo\Bar\" }, 72 new object[] { @"Foo\Bar", @"Foo\Bar\\" }, 73 new object[] { @"Foo\Bar", @"Foo\Bar\\\" }, 74 new object[] { @"Foo\Bar", @"Foo\\Bar\" }, 75 new object[] { @"Foo\Bar", @"Foo\\Bar\\" }, 76 new object[] { @"Foo\Bar", @"Foo\\Bar\\\" }, 77 new object[] { @"Foo\Bar", @"Foo\\\Bar\\\" }, 78 new object[] { @"Foo\Bar", @"Foo\\\\Bar\\\\" }, 79 80 // The name fix-up implementation uses a mark-and-sweep approach. 81 // If there are multiple slashes, any extra slash chars will be 82 // replaced with a marker char ('\uffff'), and then all '\uffff' 83 // chars will be removed, including any pre-existing '\uffff' chars. 84 InsertMarkerChar(@"Foo", @"{0}Foo\\"), 85 InsertMarkerChar(@"Foo", @"Foo{0}\\"), 86 InsertMarkerChar(@"Foo", @"Foo\\{0}"), 87 InsertMarkerChar(@"Foo", @"Fo{0}o\\"), 88 InsertMarkerChar(@"Foo", @"{0}Fo{0}o{0}\\{0}"), 89 InsertMarkerChar(@"Foo", @"{0}Foo\\\"), 90 InsertMarkerChar(@"Foo", @"Foo{0}\\\"), 91 InsertMarkerChar(@"Foo", @"Foo\\\{0}"), 92 InsertMarkerChar(@"Foo", @"Fo{0}o\\\"), 93 InsertMarkerChar(@"Foo", @"{0}Fo{0}o{0}\\\{0}"), 94 InsertMarkerChar(@"Foo\Bar", @"{0}Foo\\Bar"), 95 InsertMarkerChar(@"Foo\Bar", @"Foo{0}\\Bar"), 96 InsertMarkerChar(@"Foo\Bar", @"Foo\\{0}Bar"), 97 InsertMarkerChar(@"Foo\Bar", @"Foo\\Bar{0}"), 98 InsertMarkerChar(@"Foo\Bar", @"Fo{0}o\\Bar"), 99 InsertMarkerChar(@"Foo\Bar", @"Foo\\B{0}ar"), 100 InsertMarkerChar(@"Foo\Bar", @"Fo{0}o\\B{0}ar"), 101 InsertMarkerChar(@"Foo\Bar", @"{0}Fo{0}o{0}\\{0}B{0}ar{0}"), 102 InsertMarkerChar(@"Foo\Bar", @"{0}Foo\\\Bar"), 103 InsertMarkerChar(@"Foo\Bar", @"Foo{0}\\\Bar"), 104 InsertMarkerChar(@"Foo\Bar", @"Foo\\\{0}Bar"), 105 InsertMarkerChar(@"Foo\Bar", @"Foo\\\Bar{0}"), 106 InsertMarkerChar(@"Foo\Bar", @"Fo{0}o\\\Bar"), 107 InsertMarkerChar(@"Foo\Bar", @"Foo\\\B{0}ar"), 108 InsertMarkerChar(@"Foo\Bar", @"Fo{0}o\\\B{0}ar"), 109 InsertMarkerChar(@"Foo\Bar", @"{0}Fo{0}o{0}\\\{0}B{0}ar{0}"), 110 InsertMarkerChar(@"Foo\Bar", @"{0}Foo\Bar\\"), 111 InsertMarkerChar(@"Foo\Bar", @"Foo{0}\Bar\\"), 112 InsertMarkerChar(@"Foo\Bar", @"Foo\{0}Bar\\"), 113 InsertMarkerChar(@"Foo\Bar", @"Foo\Bar{0}\\"), 114 InsertMarkerChar(@"Foo\Bar", @"Foo\Bar\\{0}"), 115 InsertMarkerChar(@"Foo\Bar", @"Fo{0}o\B{0}ar\\"), 116 InsertMarkerChar(@"Foo\Bar", @"{0}Fo{0}o{0}\{0}B{0}ar{0}\\{0}"), 117 118 // If there aren't multiple slashes, any '\uffff' chars should remain. 119 InsertMarkerChar(@"{0}Foo"), 120 InsertMarkerChar(@"Foo{0}"), 121 InsertMarkerChar(@"Fo{0}o"), 122 InsertMarkerChar(@"{0}Fo{0}o{0}"), 123 InsertMarkerChar(@"{0}Foo\"), 124 InsertMarkerChar(@"Foo{0}\"), 125 InsertMarkerChar(@"Fo{0}o\"), 126 InsertMarkerChar(@"{0}Fo{0}o{0}\"), 127 InsertMarkerChar(@"{0}Foo\Bar"), 128 InsertMarkerChar(@"Foo{0}\Bar"), 129 InsertMarkerChar(@"Foo\{0}Bar"), 130 InsertMarkerChar(@"Foo\Bar{0}"), 131 InsertMarkerChar(@"Fo{0}o\Bar"), 132 InsertMarkerChar(@"Foo\B{0}ar"), 133 InsertMarkerChar(@"Fo{0}o\B{0}ar"), 134 InsertMarkerChar(@"{0}Fo{0}o{0}\{0}B{0}ar{0}"), 135 InsertMarkerChar(@"{0}Foo\Bar\"), 136 InsertMarkerChar(@"Foo{0}\Bar\"), 137 InsertMarkerChar(@"Foo\{0}Bar\"), 138 InsertMarkerChar(@"Foo\Bar{0}\"), 139 InsertMarkerChar(@"Fo{0}o\Bar\"), 140 InsertMarkerChar(@"Foo\B{0}ar\"), 141 InsertMarkerChar(@"Fo{0}o\B{0}ar\"), 142 InsertMarkerChar(@"{0}Fo{0}o{0}\{0}B{0}ar{0}\"), 143 }; 144 145 private const char MarkerChar = '\uffff'; 146 InsertMarkerChar(string expected, string format)147 private static object[] InsertMarkerChar(string expected, string format) 148 { 149 string result = string.Format(format, MarkerChar); 150 return new object[] { expected, result }; 151 } 152 InsertMarkerChar(string format)153 private static object[] InsertMarkerChar(string format) 154 { 155 string result = string.Format(format, MarkerChar); 156 string expected = result.TrimEnd('\\'); 157 return new object[] { expected, result }; 158 } 159 CreateTestRegistrySubKey(string expected)160 protected void CreateTestRegistrySubKey(string expected) 161 { 162 Assert.Equal(0, TestRegistryKey.SubKeyCount); 163 164 using (RegistryKey key = TestRegistryKey.CreateSubKey(expected)) 165 { 166 Assert.NotNull(key); 167 Assert.Equal(1, TestRegistryKey.SubKeyCount); 168 Assert.Equal(TestRegistryKey.Name + @"\" + expected, key.Name); 169 } 170 } 171 } 172 } 173