Skip to content

Commit 7b45115

Browse files
[dotnet] Annotate nullability on Firefox profile (#15207)
1 parent bd2e454 commit 7b45115

File tree

3 files changed

+59
-76
lines changed

3 files changed

+59
-76
lines changed

dotnet/src/webdriver/Firefox/FirefoxProfile.cs

Lines changed: 40 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@
2020
using OpenQA.Selenium.Internal;
2121
using System;
2222
using System.Collections.Generic;
23+
using System.Diagnostics.CodeAnalysis;
2324
using System.IO;
2425
using System.IO.Compression;
2526
using System.Text.Json;
2627

28+
#nullable enable
29+
2730
namespace OpenQA.Selenium.Firefox
2831
{
2932
/// <summary>
@@ -32,13 +35,10 @@ namespace OpenQA.Selenium.Firefox
3235
public class FirefoxProfile
3336
{
3437
private const string UserPreferencesFileName = "user.js";
35-
36-
private string profileDir;
37-
private string sourceProfileDir;
38-
private bool deleteSource;
39-
private bool deleteOnClean = true;
40-
private Preferences profilePreferences;
41-
private Dictionary<string, FirefoxExtension> extensions = new Dictionary<string, FirefoxExtension>();
38+
private readonly string? sourceProfileDir;
39+
private readonly bool deleteSource;
40+
private readonly Preferences profilePreferences;
41+
private readonly Dictionary<string, FirefoxExtension> extensions = new Dictionary<string, FirefoxExtension>();
4242

4343
/// <summary>
4444
/// Initializes a new instance of the <see cref="FirefoxProfile"/> class.
@@ -53,7 +53,7 @@ public FirefoxProfile()
5353
/// specific profile directory.
5454
/// </summary>
5555
/// <param name="profileDirectory">The directory containing the profile.</param>
56-
public FirefoxProfile(string profileDirectory)
56+
public FirefoxProfile(string? profileDirectory)
5757
: this(profileDirectory, false)
5858
{
5959
}
@@ -64,31 +64,24 @@ public FirefoxProfile(string profileDirectory)
6464
/// </summary>
6565
/// <param name="profileDirectory">The directory containing the profile.</param>
6666
/// <param name="deleteSourceOnClean">Delete the source directory of the profile upon cleaning.</param>
67-
public FirefoxProfile(string profileDirectory, bool deleteSourceOnClean)
67+
public FirefoxProfile(string? profileDirectory, bool deleteSourceOnClean)
6868
{
6969
this.sourceProfileDir = profileDirectory;
7070
this.deleteSource = deleteSourceOnClean;
71-
this.ReadDefaultPreferences();
71+
this.profilePreferences = this.ReadDefaultPreferences();
7272
this.profilePreferences.AppendPreferences(this.ReadExistingPreferences());
7373
}
7474

7575
/// <summary>
7676
/// Gets the directory containing the profile.
7777
/// </summary>
78-
public string ProfileDirectory
79-
{
80-
get { return this.profileDir; }
81-
}
78+
public string? ProfileDirectory { get; private set; }
8279

8380
/// <summary>
8481
/// Gets or sets a value indicating whether to delete this profile after use with
8582
/// the <see cref="FirefoxDriver"/>.
8683
/// </summary>
87-
public bool DeleteAfterUse
88-
{
89-
get { return this.deleteOnClean; }
90-
set { this.deleteOnClean = value; }
91-
}
84+
public bool DeleteAfterUse { get; set; } = true;
9285

9386
/// <summary>
9487
/// Converts a base64-encoded string into a <see cref="FirefoxProfile"/>.
@@ -130,6 +123,7 @@ public void AddExtension(string extensionToInstall)
130123
/// </summary>
131124
/// <param name="name">The name of the preference to add.</param>
132125
/// <param name="value">A <see cref="string"/> value to add to the profile.</param>
126+
/// <exception cref="ArgumentNullException">If <paramref name="name"/> or <paramref name="value"/> are <see langword="null"/>.</exception>
133127
public void SetPreference(string name, string value)
134128
{
135129
this.profilePreferences.SetPreference(name, value);
@@ -140,6 +134,7 @@ public void SetPreference(string name, string value)
140134
/// </summary>
141135
/// <param name="name">The name of the preference to add.</param>
142136
/// <param name="value">A <see cref="int"/> value to add to the profile.</param>
137+
/// <exception cref="ArgumentNullException">If <paramref name="name"/> is <see langword="null"/>.</exception>
143138
public void SetPreference(string name, int value)
144139
{
145140
this.profilePreferences.SetPreference(name, value);
@@ -150,6 +145,7 @@ public void SetPreference(string name, int value)
150145
/// </summary>
151146
/// <param name="name">The name of the preference to add.</param>
152147
/// <param name="value">A <see cref="bool"/> value to add to the profile.</param>
148+
/// <exception cref="ArgumentNullException">If <paramref name="name"/> is <see langword="null"/>.</exception>
153149
public void SetPreference(string name, bool value)
154150
{
155151
this.profilePreferences.SetPreference(name, value);
@@ -158,22 +154,23 @@ public void SetPreference(string name, bool value)
158154
/// <summary>
159155
/// Writes this in-memory representation of a profile to disk.
160156
/// </summary>
157+
[MemberNotNull(nameof(ProfileDirectory))]
161158
public void WriteToDisk()
162159
{
163-
this.profileDir = GenerateProfileDirectoryName();
160+
this.ProfileDirectory = GenerateProfileDirectoryName();
164161
if (!string.IsNullOrEmpty(this.sourceProfileDir))
165162
{
166-
FileUtilities.CopyDirectory(this.sourceProfileDir, this.profileDir);
163+
FileUtilities.CopyDirectory(this.sourceProfileDir, this.ProfileDirectory);
167164
}
168165
else
169166
{
170-
Directory.CreateDirectory(this.profileDir);
167+
Directory.CreateDirectory(this.ProfileDirectory);
171168
}
172169

173-
this.InstallExtensions();
174-
this.DeleteLockFiles();
175-
this.DeleteExtensionsCache();
176-
this.UpdateUserPreferences();
170+
this.InstallExtensions(this.ProfileDirectory);
171+
this.DeleteLockFiles(this.ProfileDirectory);
172+
this.DeleteExtensionsCache(this.ProfileDirectory);
173+
this.UpdateUserPreferences(this.ProfileDirectory);
177174
}
178175

179176
/// <summary>
@@ -185,9 +182,9 @@ public void WriteToDisk()
185182
/// is deleted.</remarks>
186183
public void Clean()
187184
{
188-
if (this.deleteOnClean && !string.IsNullOrEmpty(this.profileDir) && Directory.Exists(this.profileDir))
185+
if (this.DeleteAfterUse && !string.IsNullOrEmpty(this.ProfileDirectory) && Directory.Exists(this.ProfileDirectory))
189186
{
190-
FileUtilities.DeleteDirectory(this.profileDir);
187+
FileUtilities.DeleteDirectory(this.ProfileDirectory);
191188
}
192189

193190
if (this.deleteSource && !string.IsNullOrEmpty(this.sourceProfileDir) && Directory.Exists(this.sourceProfileDir))
@@ -202,17 +199,17 @@ public void Clean()
202199
/// <returns>A base64-encoded string containing the contents of the profile.</returns>
203200
public string ToBase64String()
204201
{
205-
string base64zip = string.Empty;
202+
string base64zip;
206203
this.WriteToDisk();
207204

208205
using (MemoryStream profileMemoryStream = new MemoryStream())
209206
{
210207
using (ZipArchive profileZipArchive = new ZipArchive(profileMemoryStream, ZipArchiveMode.Create, true))
211208
{
212-
string[] files = Directory.GetFiles(this.profileDir, "*.*", SearchOption.AllDirectories);
209+
string[] files = Directory.GetFiles(this.ProfileDirectory, "*.*", SearchOption.AllDirectories);
213210
foreach (string file in files)
214211
{
215-
string fileNameInZip = file.Substring(this.profileDir.Length + 1).Replace(Path.DirectorySeparatorChar, '/');
212+
string fileNameInZip = file.Substring(this.ProfileDirectory.Length + 1).Replace(Path.DirectorySeparatorChar, '/');
216213
profileZipArchive.CreateEntryFromFile(file, fileNameInZip);
217214
}
218215
}
@@ -236,20 +233,20 @@ private static string GenerateProfileDirectoryName()
236233
/// <summary>
237234
/// Deletes the lock files for a profile.
238235
/// </summary>
239-
private void DeleteLockFiles()
236+
private void DeleteLockFiles(string profileDirectory)
240237
{
241-
File.Delete(Path.Combine(this.profileDir, ".parentlock"));
242-
File.Delete(Path.Combine(this.profileDir, "parent.lock"));
238+
File.Delete(Path.Combine(profileDirectory, ".parentlock"));
239+
File.Delete(Path.Combine(profileDirectory, "parent.lock"));
243240
}
244241

245242
/// <summary>
246243
/// Installs all extensions in the profile in the directory on disk.
247244
/// </summary>
248-
private void InstallExtensions()
245+
private void InstallExtensions(string profileDirectory)
249246
{
250247
foreach (string extensionKey in this.extensions.Keys)
251248
{
252-
this.extensions[extensionKey].Install(this.profileDir);
249+
this.extensions[extensionKey].Install(profileDirectory);
253250
}
254251
}
255252

@@ -259,10 +256,10 @@ private void InstallExtensions()
259256
/// <remarks>If the extensions cache does not exist for this profile, the
260257
/// <see cref="DeleteExtensionsCache"/> method performs no operations, but
261258
/// succeeds.</remarks>
262-
private void DeleteExtensionsCache()
259+
private void DeleteExtensionsCache(string profileDirectory)
263260
{
264-
DirectoryInfo ex = new DirectoryInfo(Path.Combine(this.profileDir, "extensions"));
265-
string cacheFile = Path.Combine(ex.Parent.FullName, "extensions.cache");
261+
DirectoryInfo ex = new DirectoryInfo(Path.Combine(profileDirectory, "extensions"));
262+
string cacheFile = Path.Combine(ex.Parent!.FullName, "extensions.cache");
266263
if (File.Exists(cacheFile))
267264
{
268265
File.Delete(cacheFile);
@@ -272,9 +269,9 @@ private void DeleteExtensionsCache()
272269
/// <summary>
273270
/// Writes the user preferences to the profile.
274271
/// </summary>
275-
private void UpdateUserPreferences()
272+
private void UpdateUserPreferences(string profileDirectory)
276273
{
277-
string userPrefs = Path.Combine(this.profileDir, UserPreferencesFileName);
274+
string userPrefs = Path.Combine(profileDirectory, UserPreferencesFileName);
278275
if (File.Exists(userPrefs))
279276
{
280277
try
@@ -300,7 +297,7 @@ private void UpdateUserPreferences()
300297
this.profilePreferences.WriteToFile(userPrefs);
301298
}
302299

303-
private void ReadDefaultPreferences()
300+
private Preferences ReadDefaultPreferences()
304301
{
305302
using (Stream defaultPrefsStream = ResourceUtilities.GetResourceStream("webdriver_prefs.json", "webdriver_prefs.json"))
306303
{
@@ -309,7 +306,7 @@ private void ReadDefaultPreferences()
309306
JsonElement immutableDefaultPreferences = defaultPreferences.RootElement.GetProperty("frozen");
310307
JsonElement editableDefaultPreferences = defaultPreferences.RootElement.GetProperty("mutable");
311308

312-
this.profilePreferences = new Preferences(immutableDefaultPreferences, editableDefaultPreferences);
309+
return new Preferences(immutableDefaultPreferences, editableDefaultPreferences);
313310
}
314311
}
315312

dotnet/src/webdriver/Firefox/FirefoxProfileManager.cs

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
using System.Collections.ObjectModel;
2424
using System.IO;
2525

26+
#nullable enable
27+
2628
namespace OpenQA.Selenium.Firefox
2729
{
2830
/// <summary>
@@ -45,52 +47,32 @@ public FirefoxProfileManager()
4547
/// Gets a <see cref="ReadOnlyCollection{T}"/> containing <see cref="FirefoxProfile">FirefoxProfiles</see>
4648
/// representing the existing named profiles for Firefox.
4749
/// </summary>
48-
public ReadOnlyCollection<string> ExistingProfiles
49-
{
50-
get
51-
{
52-
List<string> profileList = new List<string>(this.profiles.Keys);
53-
return profileList.AsReadOnly();
54-
}
55-
}
50+
public ReadOnlyCollection<string> ExistingProfiles => new List<string>(this.profiles.Keys).AsReadOnly();
5651

5752
/// <summary>
5853
/// Gets a <see cref="FirefoxProfile"/> with a given name.
5954
/// </summary>
6055
/// <param name="profileName">The name of the profile to get.</param>
6156
/// <returns>A <see cref="FirefoxProfile"/> with a given name.
6257
/// Returns <see langword="null"/> if no profile with the given name exists.</returns>
63-
public FirefoxProfile GetProfile(string profileName)
58+
public FirefoxProfile? GetProfile(string? profileName)
6459
{
65-
FirefoxProfile profile = null;
66-
if (!string.IsNullOrEmpty(profileName))
60+
if (profileName is not null && this.profiles.TryGetValue(profileName, out string? profile))
6761
{
68-
if (this.profiles.ContainsKey(profileName))
69-
{
70-
profile = new FirefoxProfile(this.profiles[profileName]);
71-
}
62+
return new FirefoxProfile(profile);
7263
}
7364

74-
return profile;
65+
return null;
7566
}
7667

7768
private static string GetApplicationDataDirectory()
7869
{
79-
string appDataDirectory = string.Empty;
80-
switch (Environment.OSVersion.Platform)
70+
string appDataDirectory = Environment.OSVersion.Platform switch
8171
{
82-
case PlatformID.Unix:
83-
appDataDirectory = Path.Combine(".mozilla", "firefox");
84-
break;
85-
86-
case PlatformID.MacOSX:
87-
appDataDirectory = Path.Combine("Library", Path.Combine("Application Support", "Firefox"));
88-
break;
89-
90-
default:
91-
appDataDirectory = Path.Combine("Mozilla", "Firefox");
92-
break;
93-
}
72+
PlatformID.Unix => Path.Combine(".mozilla", "firefox"),
73+
PlatformID.MacOSX => Path.Combine("Library", Path.Combine("Application Support", "Firefox")),
74+
_ => Path.Combine("Mozilla", "Firefox"),
75+
};
9476

9577
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), appDataDirectory);
9678
}
@@ -109,7 +91,7 @@ private void ReadProfiles(string appDataDirectory)
10991
string name = reader.GetValue(sectionName, "name");
11092
bool isRelative = reader.GetValue(sectionName, "isrelative") == "1";
11193
string profilePath = reader.GetValue(sectionName, "path");
112-
string fullPath = string.Empty;
94+
string fullPath;
11395
if (isRelative)
11496
{
11597
fullPath = Path.Combine(appDataDirectory, profilePath);

dotnet/src/webdriver/Internal/FileUtilities.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public static bool CopyDirectory(string sourceDirectory, string destinationDirec
7676
/// </summary>
7777
/// <param name="directoryToDelete">The directory to delete.</param>
7878
/// <remarks>This method does not throw an exception if the delete fails.</remarks>
79-
public static void DeleteDirectory(string directoryToDelete)
79+
public static void DeleteDirectory(string? directoryToDelete)
8080
{
8181
int numberOfRetries = 0;
8282
while (Directory.Exists(directoryToDelete) && numberOfRetries < 10)
@@ -210,7 +210,11 @@ public static string GetCurrentDirectory()
210210
/// <param name="directoryPattern">The pattern to use in creating the directory name, following standard
211211
/// .NET string replacement tokens.</param>
212212
/// <returns>The full path to the random directory name in the temporary directory.</returns>
213-
public static string GenerateRandomTempDirectoryName(string directoryPattern)
213+
public static string GenerateRandomTempDirectoryName(
214+
#if NET8_0_OR_GREATER
215+
[System.Diagnostics.CodeAnalysis.StringSyntax(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.CompositeFormat)]
216+
#endif
217+
string directoryPattern)
214218
{
215219
string directoryName = string.Format(CultureInfo.InvariantCulture, directoryPattern, Guid.NewGuid().ToString("N"));
216220
return Path.Combine(Path.GetTempPath(), directoryName);

0 commit comments

Comments
 (0)