From becfbde3a0606b2bde06d57064cfbdde3cc31b60 Mon Sep 17 00:00:00 2001 From: Michael Render Date: Sun, 26 Jan 2025 21:22:31 -0500 Subject: [PATCH] [dotnet] Annotate nullability on `DriverOptions` --- dotnet/src/webdriver/DriverOptions.cs | 194 ++++++++++---------------- 1 file changed, 74 insertions(+), 120 deletions(-) diff --git a/dotnet/src/webdriver/DriverOptions.cs b/dotnet/src/webdriver/DriverOptions.cs index 2c34844ffcbd1..93150dd91013f 100644 --- a/dotnet/src/webdriver/DriverOptions.cs +++ b/dotnet/src/webdriver/DriverOptions.cs @@ -21,8 +21,11 @@ using OpenQA.Selenium.Remote; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Globalization; +#nullable enable + namespace OpenQA.Selenium { /// @@ -112,22 +115,9 @@ public Dictionary ToCapabilities() /// public abstract class DriverOptions { - private string browserName; - private string browserVersion; - private string platformName; - private Proxy proxy; - private bool? acceptInsecureCertificates; - private bool? useWebSocketUrl; - private bool useStrictFileInteractability; - private bool? enableDownloads; - private TimeSpan? scriptTimeout; - private TimeSpan? pageLoadTimeout; - private TimeSpan? implicitWaitTimeout; - private UnhandledPromptBehavior unhandledPromptBehavior = UnhandledPromptBehavior.Default; - private PageLoadStrategy pageLoadStrategy = PageLoadStrategy.Default; - private Dictionary additionalCapabilities = new Dictionary(); - private Dictionary loggingPreferences = new Dictionary(); - private Dictionary knownCapabilityNames = new Dictionary(); + private readonly Dictionary additionalCapabilities = new Dictionary(); + private readonly Dictionary loggingPreferences = new Dictionary(); + private readonly Dictionary knownCapabilityNames = new Dictionary(); /// /// Initializes a new instance of the class. @@ -148,97 +138,57 @@ protected DriverOptions() /// /// Gets or sets the name of the browser. /// - public string BrowserName - { - get { return this.browserName; } - protected set { this.browserName = value; } - } + public string? BrowserName { get; protected set; } /// /// Gets or sets the version of the browser. /// - public string BrowserVersion - { - get { return this.browserVersion; } - set { this.browserVersion = value; } - } + public string? BrowserVersion { get; set; } /// /// Gets or sets the name of the platform on which the browser is running. /// - public string PlatformName - { - get { return this.platformName; } - set { this.platformName = value; } - } + public string? PlatformName { get; set; } /// /// Gets or sets a value indicating whether the browser should accept self-signed /// SSL certificates. /// - public bool? AcceptInsecureCertificates - { - get { return this.acceptInsecureCertificates; } - set { this.acceptInsecureCertificates = value; } - } + public bool? AcceptInsecureCertificates { get; set; } /// /// Gets or sets a value indicating whether the driver should request a URL to /// a WebSocket to be used for bidirectional communication. /// - public bool? UseWebSocketUrl - { - get { return this.useWebSocketUrl; } - set { this.useWebSocketUrl = value; } - } + public bool? UseWebSocketUrl { get; set; } /// /// Gets or sets the value for describing how unexpected alerts are to be handled in the browser. /// Defaults to . /// - public UnhandledPromptBehavior UnhandledPromptBehavior - { - get { return this.unhandledPromptBehavior; } - set { this.unhandledPromptBehavior = value; } - } + public UnhandledPromptBehavior UnhandledPromptBehavior { get; set; } = UnhandledPromptBehavior.Default; /// /// Gets or sets the value for describing how the browser is to wait for pages to load in the browser. /// Defaults to . /// - public PageLoadStrategy PageLoadStrategy - { - get { return this.pageLoadStrategy; } - set { this.pageLoadStrategy = value; } - } + public PageLoadStrategy PageLoadStrategy { get; set; } = PageLoadStrategy.Default; /// /// Gets or sets the to be used with this browser. /// - public Proxy Proxy - { - get { return this.proxy; } - set { this.proxy = value; } - } + public Proxy? Proxy { get; set; } /// /// Gets or sets a value indicating whether <input type='file'/> elements /// must be visible to allow uploading of files. /// - public bool UseStrictFileInteractability - { - get { return this.useStrictFileInteractability; } - set { this.useStrictFileInteractability = value; } - } + public bool UseStrictFileInteractability { get; set; } /// /// Gets or sets a value indicating whether files may be downloaded from remote node. /// - public bool? EnableDownloads - { - get { return this.enableDownloads; } - set { this.enableDownloads = value; } - } + public bool? EnableDownloads { get; set; } /// /// Gets or sets the asynchronous script timeout, which is the amount @@ -246,22 +196,14 @@ public bool? EnableDownloads /// This timeout only affects the /// method. /// - public TimeSpan? ScriptTimeout - { - get { return this.scriptTimeout; } - set { this.scriptTimeout = value; } - } + public TimeSpan? ScriptTimeout { get; set; } /// /// Gets or sets the page load timeout, which is the amount of time the driver /// should wait for a page to load when setting the /// property. /// - public TimeSpan? PageLoadTimeout - { - get { return this.pageLoadTimeout; } - set { this.pageLoadTimeout = value; } - } + public TimeSpan? PageLoadTimeout { get; set; } /// /// Gets or sets the implicit wait timeout, which is the amount of time the @@ -280,20 +222,16 @@ public TimeSpan? PageLoadTimeout /// slower location strategies like XPath. /// /// - public TimeSpan? ImplicitWaitTimeout - { - get { return this.implicitWaitTimeout; } - set { this.implicitWaitTimeout = value; } - } + public TimeSpan? ImplicitWaitTimeout { get; set; } /// /// Set or Get the location of the browser /// Override in subclass /// - public virtual string BinaryLocation + public virtual string? BinaryLocation { - get { return null; } - set { throw new NotImplementedException(); } + get => null; + set => throw new NotImplementedException(); } /// @@ -330,45 +268,51 @@ public virtual void AddAdditionalOption(string optionName, object optionValue) /// /// The object to compare with. /// A object containing the status of the attempted merge. + /// If is . public virtual DriverOptionsMergeResult GetMergeResult(DriverOptions other) { + if (other is null) + { + throw new ArgumentNullException(nameof(other)); + } + DriverOptionsMergeResult result = new DriverOptionsMergeResult(); - if (this.browserName != null && other.BrowserName != null) + if (this.BrowserName != null && other.BrowserName != null) { result.IsMergeConflict = true; result.MergeConflictOptionName = "BrowserName"; return result; } - if (this.browserVersion != null && other.BrowserVersion != null) + if (this.BrowserVersion != null && other.BrowserVersion != null) { result.IsMergeConflict = true; result.MergeConflictOptionName = "BrowserVersion"; return result; } - if (this.platformName != null && other.PlatformName != null) + if (this.PlatformName != null && other.PlatformName != null) { result.IsMergeConflict = true; result.MergeConflictOptionName = "PlatformName"; return result; } - if (this.proxy != null && other.Proxy != null) + if (this.Proxy != null && other.Proxy != null) { result.IsMergeConflict = true; result.MergeConflictOptionName = "Proxy"; return result; } - if (this.unhandledPromptBehavior != UnhandledPromptBehavior.Default && other.UnhandledPromptBehavior != UnhandledPromptBehavior.Default) + if (this.UnhandledPromptBehavior != UnhandledPromptBehavior.Default && other.UnhandledPromptBehavior != UnhandledPromptBehavior.Default) { result.IsMergeConflict = true; result.MergeConflictOptionName = "UnhandledPromptBehavior"; return result; } - if (this.pageLoadStrategy != PageLoadStrategy.Default && other.PageLoadStrategy != PageLoadStrategy.Default) + if (this.PageLoadStrategy != PageLoadStrategy.Default && other.PageLoadStrategy != PageLoadStrategy.Default) { result.IsMergeConflict = true; result.MergeConflictOptionName = "PageLoadStrategy"; @@ -393,10 +337,10 @@ public void SetLoggingPreference(string logType, LogLevel logLevel) /// Returns the current options as a . /// /// The current options as a . - internal IDictionary ToDictionary() + internal IDictionary? ToDictionary() { - IHasCapabilitiesDictionary desired = this.ToCapabilities() as IHasCapabilitiesDictionary; - if (desired == null) + ICapabilities? capabilities = this.ToCapabilities(); + if (capabilities is not IHasCapabilitiesDictionary desired) { return null; } @@ -413,16 +357,15 @@ internal IDictionary ToDictionary() /// thrown when attempting to add a capability for which there is already a type safe option, or /// when is or the empty string. /// - protected void ValidateCapabilityName(string capabilityName) + protected void ValidateCapabilityName([NotNull] string? capabilityName) { - if (string.IsNullOrEmpty(capabilityName)) + if (capabilityName is null || string.IsNullOrEmpty(capabilityName)) { throw new ArgumentException("Capability name may not be null an empty string.", nameof(capabilityName)); } - if (this.IsKnownCapabilityName(capabilityName)) + if (this.TryGetKnownCapability(capabilityName!, out string? typeSafeOptionName)) { - string typeSafeOptionName = this.GetTypeSafeOptionName(capabilityName); string message = string.Format(CultureInfo.InvariantCulture, "There is already an option for the {0} capability. Please use the {1} instead.", capabilityName, typeSafeOptionName); throw new ArgumentException(message, nameof(capabilityName)); } @@ -443,9 +386,9 @@ protected void AddKnownCapabilityName(string capabilityName, string typeSafeOpti /// Remove a capability from the list of known capabilities /// /// The name of the capability to be removed. - protected void RemoveKnownCapabilityName(string capabilityName) + protected void RemoveKnownCapabilityName(string? capabilityName) { - if (!string.IsNullOrEmpty(capabilityName) && this.knownCapabilityNames.ContainsKey(capabilityName)) + if (capabilityName is not null) { this.knownCapabilityNames.Remove(capabilityName); } @@ -461,6 +404,17 @@ protected bool IsKnownCapabilityName(string capabilityName) return this.knownCapabilityNames.ContainsKey(capabilityName); } + /// + /// Gets a value indicating whether the specified capability name is a known capability name which has a type-safe option. + /// + /// The name of the capability to check. + /// The name of the type-safe option for the given capability name, or if not found. + /// if the capability name is known; otherwise . + protected bool TryGetKnownCapability(string capabilityName, [NotNullWhen(true)] out string? typeSafeOptionName) + { + return this.knownCapabilityNames.TryGetValue(capabilityName, out typeSafeOptionName); + } + /// /// Gets the name of the type-safe option for a given capability name. /// @@ -480,7 +434,7 @@ protected string GetTypeSafeOptionName(string capabilityName) /// Generates the logging preferences dictionary for transmission as a desired capability. /// /// The dictionary containing the logging preferences. - protected Dictionary GenerateLoggingPreferencesDictionary() + protected Dictionary? GenerateLoggingPreferencesDictionary() { if (this.loggingPreferences.Count == 0) { @@ -504,45 +458,45 @@ protected Dictionary GenerateLoggingPreferencesDictionary() protected IWritableCapabilities GenerateDesiredCapabilities(bool isSpecificationCompliant) { DesiredCapabilities capabilities = new DesiredCapabilities(); - if (!string.IsNullOrEmpty(this.browserName)) + if (!string.IsNullOrEmpty(this.BrowserName)) { - capabilities.SetCapability(CapabilityType.BrowserName, this.browserName); + capabilities.SetCapability(CapabilityType.BrowserName, this.BrowserName!); } - if (!string.IsNullOrEmpty(this.browserVersion)) + if (!string.IsNullOrEmpty(this.BrowserVersion)) { - capabilities.SetCapability(CapabilityType.BrowserVersion, this.browserVersion); + capabilities.SetCapability(CapabilityType.BrowserVersion, this.BrowserVersion!); } - if (!string.IsNullOrEmpty(this.platformName)) + if (!string.IsNullOrEmpty(this.PlatformName)) { - capabilities.SetCapability(CapabilityType.PlatformName, this.platformName); + capabilities.SetCapability(CapabilityType.PlatformName, this.PlatformName!); } - if (this.acceptInsecureCertificates.HasValue) + if (this.AcceptInsecureCertificates.HasValue) { - capabilities.SetCapability(CapabilityType.AcceptInsecureCertificates, this.acceptInsecureCertificates); + capabilities.SetCapability(CapabilityType.AcceptInsecureCertificates, this.AcceptInsecureCertificates); } - if (this.useWebSocketUrl.HasValue) + if (this.UseWebSocketUrl.HasValue) { - capabilities.SetCapability(CapabilityType.WebSocketUrl, this.useWebSocketUrl); + capabilities.SetCapability(CapabilityType.WebSocketUrl, this.UseWebSocketUrl); } - if (this.enableDownloads.HasValue) + if (this.EnableDownloads.HasValue) { - capabilities.SetCapability(CapabilityType.EnableDownloads, this.enableDownloads); + capabilities.SetCapability(CapabilityType.EnableDownloads, this.EnableDownloads); } - if (this.useStrictFileInteractability) + if (this.UseStrictFileInteractability) { capabilities.SetCapability(CapabilityType.UseStrictFileInteractability, true); } - if (this.pageLoadStrategy != PageLoadStrategy.Default) + if (this.PageLoadStrategy != PageLoadStrategy.Default) { string pageLoadStrategySetting = "normal"; - switch (this.pageLoadStrategy) + switch (this.PageLoadStrategy) { case PageLoadStrategy.Eager: pageLoadStrategySetting = "eager"; @@ -583,7 +537,7 @@ protected IWritableCapabilities GenerateDesiredCapabilities(bool isSpecification if (this.Proxy != null) { - Dictionary proxyCapability = this.Proxy.ToCapability(); + Dictionary? proxyCapability = this.Proxy.ToCapability(); if (!isSpecificationCompliant) { proxyCapability = this.Proxy.ToLegacyCapability(); @@ -595,13 +549,13 @@ protected IWritableCapabilities GenerateDesiredCapabilities(bool isSpecification } } - if (this.scriptTimeout.HasValue || this.pageLoadTimeout.HasValue || this.implicitWaitTimeout.HasValue) + if (this.ScriptTimeout.HasValue || this.PageLoadTimeout.HasValue || this.ImplicitWaitTimeout.HasValue) { var timeouts = new Timeout { - Script = this.scriptTimeout, - PageLoad = this.pageLoadTimeout, - ImplicitWait = this.implicitWaitTimeout + Script = this.ScriptTimeout, + PageLoad = this.PageLoadTimeout, + ImplicitWait = this.ImplicitWaitTimeout }; capabilities.SetCapability(CapabilityType.Timeouts, timeouts.ToCapabilities());