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