From 76b9cc4423b5bb3d8c873b184b86895a2b993d86 Mon Sep 17 00:00:00 2001
From: Michael Render <render.michael@gmail.com>
Date: Sat, 1 Feb 2025 00:12:42 -0500
Subject: [PATCH 1/2] [dotnet] Annotate nullability on firefox and chromium
 options

---
 dotnet/src/webdriver/Chrome/ChromeOptions.cs  |  14 +-
 dotnet/src/webdriver/Edge/EdgeOptions.cs      |  18 +--
 .../src/webdriver/Firefox/FirefoxOptions.cs   | 122 +++++++-----------
 3 files changed, 59 insertions(+), 95 deletions(-)

diff --git a/dotnet/src/webdriver/Chrome/ChromeOptions.cs b/dotnet/src/webdriver/Chrome/ChromeOptions.cs
index b45befaa7a8ab..ae8a39f9886ec 100644
--- a/dotnet/src/webdriver/Chrome/ChromeOptions.cs
+++ b/dotnet/src/webdriver/Chrome/ChromeOptions.cs
@@ -21,6 +21,8 @@
 using System;
 using System.Globalization;
 
+#nullable enable
+
 namespace OpenQA.Selenium.Chrome
 {
     /// <summary>
@@ -64,19 +66,13 @@ public ChromeOptions() : base()
         /// <summary>
         /// Gets the vendor prefix to apply to Chromium-specific capability names.
         /// </summary>
-        protected override string VendorPrefix
-        {
-            get { return "goog"; }
-        }
+        protected override string VendorPrefix => "goog";
 
         /// <summary>
         /// Gets the name of the capability used to store Chromium options in
         /// an <see cref="ICapabilities"/> object.
         /// </summary>
-        public override string CapabilityName
-        {
-            get { return string.Format(CultureInfo.InvariantCulture, "{0}:{1}", this.VendorPrefix, ChromeOptionsCapabilityName); }
-        }
+        public override string CapabilityName => string.Format(CultureInfo.InvariantCulture, "{0}:{1}", this.VendorPrefix, ChromeOptionsCapabilityName);
 
         /// <summary>
         /// Provides a means to add additional capabilities not yet added as type safe options
@@ -92,7 +88,7 @@ public override string CapabilityName
         /// where <paramref name="optionName"/> has already been added will overwrite the
         /// existing value with the new value in <paramref name="optionValue"/>.
         /// Calling this method adds capabilities to the Chrome-specific options object passed to
-        /// webdriver executable (property name 'goog:chromeOptions').</remarks>
+        /// WebDriver executable (property name 'goog:chromeOptions').</remarks>
         public void AddAdditionalChromeOption(string optionName, object optionValue)
         {
             this.AddAdditionalChromiumOption(optionName, optionValue);
diff --git a/dotnet/src/webdriver/Edge/EdgeOptions.cs b/dotnet/src/webdriver/Edge/EdgeOptions.cs
index f329f150d3245..655af3225dee7 100644
--- a/dotnet/src/webdriver/Edge/EdgeOptions.cs
+++ b/dotnet/src/webdriver/Edge/EdgeOptions.cs
@@ -21,6 +21,8 @@
 using System;
 using System.Globalization;
 
+#nullable enable
+
 namespace OpenQA.Selenium.Edge
 {
     /// <summary>
@@ -60,27 +62,21 @@ public EdgeOptions() : base()
         /// <summary>
         /// Gets the vendor prefix to apply to Chromium-specific capability names.
         /// </summary>
-        protected override string VendorPrefix
-        {
-            get { return "ms"; }
-        }
+        protected override string VendorPrefix => "ms";
 
         /// <summary>
         /// Gets the name of the capability used to store Chromium options in
         /// an <see cref="ICapabilities"/> object.
         /// </summary>
-        public override string CapabilityName
-        {
-            get { return string.Format(CultureInfo.InvariantCulture, "{0}:{1}", this.VendorPrefix, EdgeOptionsCapabilityName); }
-        }
+        public override string CapabilityName => string.Format(CultureInfo.InvariantCulture, "{0}:{1}", this.VendorPrefix, EdgeOptionsCapabilityName);
 
         /// <summary>
         /// Gets or sets whether to create a WebView session used for launching an Edge (Chromium) WebView-based app on desktop.
         /// </summary>
         public bool UseWebView
         {
-            get { return this.BrowserName == WebViewBrowserNameValue; }
-            set { this.BrowserName = value ? WebViewBrowserNameValue : DefaultBrowserNameValue; }
+            get => this.BrowserName == WebViewBrowserNameValue;
+            set => this.BrowserName = value ? WebViewBrowserNameValue : DefaultBrowserNameValue;
         }
 
         /// <summary>
@@ -97,7 +93,7 @@ public bool UseWebView
         /// where <paramref name="optionName"/> has already been added will overwrite the
         /// existing value with the new value in <paramref name="optionValue"/>.
         /// Calling this method adds capabilities to the Edge-specific options object passed to
-        /// webdriver executable (property name 'ms:edgeOptions').</remarks>
+        /// WebDriver executable (property name 'ms:edgeOptions').</remarks>
         public void AddAdditionalEdgeOption(string optionName, object optionValue)
         {
             this.AddAdditionalChromiumOption(optionName, optionValue);
diff --git a/dotnet/src/webdriver/Firefox/FirefoxOptions.cs b/dotnet/src/webdriver/Firefox/FirefoxOptions.cs
index 8e6f6d1785d06..5a47af73f5771 100644
--- a/dotnet/src/webdriver/Firefox/FirefoxOptions.cs
+++ b/dotnet/src/webdriver/Firefox/FirefoxOptions.cs
@@ -20,6 +20,8 @@
 using System;
 using System.Collections.Generic;
 
+#nullable enable
+
 namespace OpenQA.Selenium.Firefox
 {
     /// <summary>
@@ -60,16 +62,10 @@ public class FirefoxOptions : DriverOptions
         private const string FirefoxEnvCapability = "env";
         private const string FirefoxOptionsCapability = "moz:firefoxOptions";
         private const string FirefoxEnableDevToolsProtocolCapability = "moz:debuggerAddress";
-
-        private bool enableDevToolsProtocol;
-        private string binaryLocation;
-        private FirefoxDriverLogLevel logLevel = FirefoxDriverLogLevel.Default;
-        private FirefoxProfile profile;
-        private List<string> firefoxArguments = new List<string>();
-        private Dictionary<string, object> profilePreferences = new Dictionary<string, object>();
-        private Dictionary<string, object> additionalFirefoxOptions = new Dictionary<string, object>();
-        private Dictionary<string, object> environmentVariables = new Dictionary<string, object>();
-        private FirefoxAndroidOptions androidOptions;
+        private readonly List<string> firefoxArguments = new List<string>();
+        private readonly Dictionary<string, object> profilePreferences = new Dictionary<string, object>();
+        private readonly Dictionary<string, object> additionalFirefoxOptions = new Dictionary<string, object>();
+        private readonly Dictionary<string, object> environmentVariables = new Dictionary<string, object>();
 
         /// <summary>
         /// Initializes a new instance of the <see cref="FirefoxOptions"/> class.
@@ -97,63 +93,44 @@ public FirefoxOptions()
         /// <summary>
         /// Gets or sets the <see cref="FirefoxProfile"/> object to be used with this instance.
         /// </summary>
-        public FirefoxProfile Profile
-        {
-            get { return this.profile; }
-            set { this.profile = value; }
-        }
+        public FirefoxProfile? Profile { get; set; }
 
         /// <summary>
         /// Gets or sets the path and file name of the Firefox browser executable.
         /// </summary>
-        public override string BinaryLocation
-        {
-            get { return this.binaryLocation; }
-            set { this.binaryLocation = value; }
-        }
+        public override string? BinaryLocation { get; set; }
 
         /// <summary>
         /// Gets or sets the path and file name of the Firefox browser executable.
         /// </summary>
         [Obsolete("Use BinaryLocation property instead of BrowserExecutableLocation. This one will be removed soon.")]
-        public string BrowserExecutableLocation
+        public string? BrowserExecutableLocation
         {
-            get { return this.binaryLocation; }
-            set { this.binaryLocation = value; }
+            get => this.BinaryLocation;
+            set => this.BinaryLocation = value;
         }
 
         /// <summary>
         /// Gets or sets the logging level of the Firefox driver.
         /// </summary>
-        public FirefoxDriverLogLevel LogLevel
-        {
-            get { return this.logLevel; }
-            set { this.logLevel = value; }
-        }
+        public FirefoxDriverLogLevel LogLevel { get; set; } = FirefoxDriverLogLevel.Default;
 
         /// <summary>
         /// Gets or sets a value indicating whether to enable the DevTools protocol for the launched browser.
         /// </summary>
-        public bool EnableDevToolsProtocol
-        {
-            get { return this.enableDevToolsProtocol; }
-            set { this.enableDevToolsProtocol = value; }
-        }
+        public bool EnableDevToolsProtocol { get; set; }
 
         /// <summary>
         /// Gets or sets the options for automating Firefox on Android.
         /// </summary>
-        public FirefoxAndroidOptions AndroidOptions
-        {
-            get { return this.androidOptions; }
-            set { this.androidOptions = value; }
-        }
+        public FirefoxAndroidOptions? AndroidOptions { get; set; }
 
         /// <summary>
         /// Adds an argument to be used in launching the Firefox browser.
         /// </summary>
         /// <param name="argumentName">The argument to add.</param>
-        /// <remarks>Arguments must be preceeded by two dashes ("--").</remarks>
+        /// <remarks>Arguments must be preceded by two dashes ("--").</remarks>
+        /// <exception cref="ArgumentException">If <paramref name="argumentName"/> is <see langword="null"/> or <see cref="string.Empty"/>.</exception>
         public void AddArgument(string argumentName)
         {
             if (string.IsNullOrEmpty(argumentName))
@@ -168,16 +145,18 @@ public void AddArgument(string argumentName)
         /// Adds a list arguments to be used in launching the Firefox browser.
         /// </summary>
         /// <param name="argumentsToAdd">An array of arguments to add.</param>
-        /// <remarks>Each argument must be preceeded by two dashes ("--").</remarks>
+        /// <remarks>Each argument must be preceded by two dashes ("--").</remarks>
+        /// <exception cref="ArgumentNullException">If <paramref name="argumentsToAdd"/> is <see langword="null"/>.</exception>
         public void AddArguments(params string[] argumentsToAdd)
         {
-            this.AddArguments(new List<string>(argumentsToAdd));
+            this.AddArguments((IEnumerable<string>)argumentsToAdd);
         }
 
         /// <summary>
         /// Adds a list arguments to be used in launching the Firefox browser.
         /// </summary>
         /// <param name="argumentsToAdd">An array of arguments to add.</param>
+        /// <exception cref="ArgumentNullException">If <paramref name="argumentsToAdd"/> is <see langword="null"/>.</exception>
         public void AddArguments(IEnumerable<string> argumentsToAdd)
         {
             if (argumentsToAdd == null)
@@ -193,6 +172,7 @@ public void AddArguments(IEnumerable<string> argumentsToAdd)
         /// </summary>
         /// <param name="preferenceName">Name of the preference to set.</param>
         /// <param name="preferenceValue">Value of the preference to set.</param>
+        /// <exception cref="ArgumentException">If <paramref name="preferenceName"/> is <see langword="null"/> or <see cref="string.Empty"/>.</exception>
         public void SetPreference(string preferenceName, bool preferenceValue)
         {
             this.SetPreferenceValue(preferenceName, preferenceValue);
@@ -203,6 +183,7 @@ public void SetPreference(string preferenceName, bool preferenceValue)
         /// </summary>
         /// <param name="preferenceName">Name of the preference to set.</param>
         /// <param name="preferenceValue">Value of the preference to set.</param>
+        /// <exception cref="ArgumentException">If <paramref name="preferenceName"/> is <see langword="null"/> or <see cref="string.Empty"/>.</exception>
         public void SetPreference(string preferenceName, int preferenceValue)
         {
             this.SetPreferenceValue(preferenceName, preferenceValue);
@@ -213,6 +194,7 @@ public void SetPreference(string preferenceName, int preferenceValue)
         /// </summary>
         /// <param name="preferenceName">Name of the preference to set.</param>
         /// <param name="preferenceValue">Value of the preference to set.</param>
+        /// <exception cref="ArgumentException">If <paramref name="preferenceName"/> is <see langword="null"/> or <see cref="string.Empty"/>.</exception>
         public void SetPreference(string preferenceName, long preferenceValue)
         {
             this.SetPreferenceValue(preferenceName, preferenceValue);
@@ -223,6 +205,7 @@ public void SetPreference(string preferenceName, long preferenceValue)
         /// </summary>
         /// <param name="preferenceName">Name of the preference to set.</param>
         /// <param name="preferenceValue">Value of the preference to set.</param>
+        /// <exception cref="ArgumentException">If <paramref name="preferenceName"/> is <see langword="null"/> or <see cref="string.Empty"/>.</exception>
         public void SetPreference(string preferenceName, double preferenceValue)
         {
             this.SetPreferenceValue(preferenceName, preferenceValue);
@@ -233,29 +216,26 @@ public void SetPreference(string preferenceName, double preferenceValue)
         /// </summary>
         /// <param name="preferenceName">Name of the preference to set.</param>
         /// <param name="preferenceValue">Value of the preference to set.</param>
+        /// <exception cref="ArgumentException">If <paramref name="preferenceName"/> is <see langword="null"/> or <see cref="string.Empty"/>.</exception>
         public void SetPreference(string preferenceName, string preferenceValue)
         {
             this.SetPreferenceValue(preferenceName, preferenceValue);
         }
 
         /// <summary>
-        /// Sets an environment variable to be set in the operating system's environment under which the Firerox browser is launched.
+        /// Sets an environment variable to be set in the operating system's environment under which the Firefox browser is launched.
         /// </summary>
         /// <param name="variableName">The name of the environment variable.</param>
         /// <param name="variableValue">The value of the environment variable.</param>
-        public void SetEnvironmentVariable(string variableName, string variableValue)
+        /// <exception cref="ArgumentException">If <paramref name="variableName"/> is <see langword="null"/> or <see cref="string.Empty"/>.</exception>
+        public void SetEnvironmentVariable(string variableName, string? variableValue)
         {
             if (string.IsNullOrEmpty(variableName))
             {
                 throw new ArgumentException("Environment variable name cannot be null or an empty string");
             }
 
-            if (variableValue == null)
-            {
-                variableValue = string.Empty;
-            }
-
-            this.environmentVariables[variableName] = variableValue;
+            this.environmentVariables[variableName] = variableValue ?? string.Empty;
         }
 
         /// <summary>
@@ -290,7 +270,7 @@ public override ICapabilities ToCapabilities()
             IWritableCapabilities capabilities = GenerateDesiredCapabilities(true);
             Dictionary<string, object> firefoxOptions = this.GenerateFirefoxOptionsDictionary();
             capabilities.SetCapability(FirefoxOptionsCapability, firefoxOptions);
-            if (this.enableDevToolsProtocol)
+            if (this.EnableDevToolsProtocol)
             {
                 capabilities.SetCapability(FirefoxEnableDevToolsProtocolCapability, true);
             }
@@ -302,30 +282,26 @@ private Dictionary<string, object> GenerateFirefoxOptionsDictionary()
         {
             Dictionary<string, object> firefoxOptions = new Dictionary<string, object>();
 
-            if (this.profile != null)
+            if (this.Profile != null)
             {
-                firefoxOptions[FirefoxProfileCapability] = this.profile.ToBase64String();
+                firefoxOptions[FirefoxProfileCapability] = this.Profile.ToBase64String();
             }
 
-            if (!string.IsNullOrEmpty(this.binaryLocation))
+            if (!string.IsNullOrEmpty(this.BinaryLocation))
             {
-                firefoxOptions[FirefoxBinaryCapability] = this.binaryLocation;
+                firefoxOptions[FirefoxBinaryCapability] = this.BinaryLocation;
             }
 
-            if (this.logLevel != FirefoxDriverLogLevel.Default)
+            if (this.LogLevel != FirefoxDriverLogLevel.Default)
             {
                 Dictionary<string, object> logObject = new Dictionary<string, object>();
-                logObject["level"] = this.logLevel.ToString().ToLowerInvariant();
+                logObject["level"] = this.LogLevel.ToString().ToLowerInvariant();
                 firefoxOptions[FirefoxLogCapability] = logObject;
             }
 
             if (this.firefoxArguments.Count > 0)
             {
-                List<object> args = new List<object>();
-                foreach (string argument in this.firefoxArguments)
-                {
-                    args.Add(argument);
-                }
+                List<object> args = [.. this.firefoxArguments];
 
                 firefoxOptions[FirefoxArgumentsCapability] = args;
             }
@@ -340,9 +316,9 @@ private Dictionary<string, object> GenerateFirefoxOptionsDictionary()
                 firefoxOptions[FirefoxEnvCapability] = this.environmentVariables;
             }
 
-            if (this.androidOptions != null)
+            if (this.AndroidOptions != null)
             {
-                this.AddAndroidOptions(firefoxOptions);
+                AddAndroidOptions(this.AndroidOptions, firefoxOptions);
             }
 
             foreach (KeyValuePair<string, object> pair in this.additionalFirefoxOptions)
@@ -363,27 +339,23 @@ private void SetPreferenceValue(string preferenceName, object preferenceValue)
             this.profilePreferences[preferenceName] = preferenceValue;
         }
 
-        private void AddAndroidOptions(Dictionary<string, object> firefoxOptions)
+        private static void AddAndroidOptions(FirefoxAndroidOptions androidOptions, Dictionary<string, object> firefoxOptions)
         {
-            firefoxOptions["androidPackage"] = this.androidOptions.AndroidPackage;
+            firefoxOptions["androidPackage"] = androidOptions.AndroidPackage;
 
-            if (!string.IsNullOrEmpty(this.androidOptions.AndroidDeviceSerial))
+            if (!string.IsNullOrEmpty(androidOptions.AndroidDeviceSerial))
             {
-                firefoxOptions["androidDeviceSerial"] = this.androidOptions.AndroidDeviceSerial;
+                firefoxOptions["androidDeviceSerial"] = androidOptions.AndroidDeviceSerial;
             }
 
-            if (!string.IsNullOrEmpty(this.androidOptions.AndroidActivity))
+            if (!string.IsNullOrEmpty(androidOptions.AndroidActivity))
             {
-                firefoxOptions["androidActivity"] = this.androidOptions.AndroidActivity;
+                firefoxOptions["androidActivity"] = androidOptions.AndroidActivity;
             }
 
-            if (this.androidOptions.AndroidIntentArguments.Count > 0)
+            if (androidOptions.AndroidIntentArguments.Count > 0)
             {
-                List<object> args = new List<object>();
-                foreach (string argument in this.androidOptions.AndroidIntentArguments)
-                {
-                    args.Add(argument);
-                }
+                List<object> args = [.. androidOptions.AndroidIntentArguments];
 
                 firefoxOptions["androidIntentArguments"] = args;
             }

From a000d6187e3872b5d18331231635c801bf2044f0 Mon Sep 17 00:00:00 2001
From: Michael Render <render.michael@gmail.com>
Date: Sat, 1 Feb 2025 00:17:58 -0500
Subject: [PATCH 2/2] Annotate some easy wins in the firefox namespace

---
 dotnet/src/webdriver/Firefox/FirefoxAndroidOptions.cs | 11 ++++++-----
 dotnet/src/webdriver/Firefox/FirefoxCommandContext.cs |  2 ++
 dotnet/src/webdriver/Firefox/FirefoxDriverLogLevel.cs |  2 ++
 3 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/dotnet/src/webdriver/Firefox/FirefoxAndroidOptions.cs b/dotnet/src/webdriver/Firefox/FirefoxAndroidOptions.cs
index 46a7e8db51ba4..8b8153fd5cffd 100644
--- a/dotnet/src/webdriver/Firefox/FirefoxAndroidOptions.cs
+++ b/dotnet/src/webdriver/Firefox/FirefoxAndroidOptions.cs
@@ -18,9 +18,12 @@
 // </copyright>
 
 using OpenQA.Selenium.Internal;
+using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 
+#nullable enable
+
 namespace OpenQA.Selenium.Firefox
 {
     /// <summary>
@@ -28,7 +31,7 @@ namespace OpenQA.Selenium.Firefox
     /// </summary>
     public class FirefoxAndroidOptions : AndroidOptions
     {
-        private List<string> androidIntentArguments = new List<string>();
+        private readonly List<string> androidIntentArguments = new List<string>();
 
         /// <summary>
         /// Initializes a new instance of the <see cref="FirefoxAndroidOptions"/> class.
@@ -41,10 +44,7 @@ public FirefoxAndroidOptions(string androidPackage) : base(androidPackage)
         /// <summary>
         /// Gets a read-only list of the intent arguments set for this set of options.
         /// </summary>
-        public ReadOnlyCollection<string> AndroidIntentArguments
-        {
-            get { return this.androidIntentArguments.AsReadOnly(); }
-        }
+        public ReadOnlyCollection<string> AndroidIntentArguments => this.androidIntentArguments.AsReadOnly();
 
         /// <summary>
         /// Argument to launch the intent with. The given intent arguments are appended to the "am start" command.
@@ -59,6 +59,7 @@ public void AddIntentArgument(string argument)
         /// Arguments to launch the intent with. The given intent arguments are appended to the "am start" command.
         /// </summary>
         /// <param name="arguments">The arguments to add.</param>
+        /// <exception cref="ArgumentNullException">If <paramref name="arguments"/> is <see langword="null"/>.</exception>
         public void AddIntentArguments(params string[] arguments)
         {
             this.androidIntentArguments.AddRange(arguments);
diff --git a/dotnet/src/webdriver/Firefox/FirefoxCommandContext.cs b/dotnet/src/webdriver/Firefox/FirefoxCommandContext.cs
index 13cd9de0900dd..00a407236dd9f 100644
--- a/dotnet/src/webdriver/Firefox/FirefoxCommandContext.cs
+++ b/dotnet/src/webdriver/Firefox/FirefoxCommandContext.cs
@@ -17,6 +17,8 @@
 // under the License.
 // </copyright>
 
+#nullable enable
+
 namespace OpenQA.Selenium.Firefox
 {
     /// <summary>
diff --git a/dotnet/src/webdriver/Firefox/FirefoxDriverLogLevel.cs b/dotnet/src/webdriver/Firefox/FirefoxDriverLogLevel.cs
index 580958ba0605d..426bd52d51ac5 100644
--- a/dotnet/src/webdriver/Firefox/FirefoxDriverLogLevel.cs
+++ b/dotnet/src/webdriver/Firefox/FirefoxDriverLogLevel.cs
@@ -17,6 +17,8 @@
 // under the License.
 // </copyright>
 
+#nullable enable
+
 namespace OpenQA.Selenium.Firefox
 {
     /// <summary>