2222using System ;
2323using System . Collections . Generic ;
2424using System . Collections . ObjectModel ;
25+ using System . Diagnostics . CodeAnalysis ;
2526using System . IO ;
2627using System . Threading . Tasks ;
2728
29+ #nullable enable
30+
2831namespace OpenQA . Selenium . Chromium
2932{
3033 /// <summary>
@@ -108,9 +111,9 @@ public class ChromiumDriver : WebDriver, ISupportsLogs, IDevTools
108111 public static readonly string SetPermissionCommand = "setPermission" ;
109112
110113 private readonly string optionsCapabilityName ;
111- private DevToolsSession devToolsSession ;
114+ private DevToolsSession ? devToolsSession ;
112115
113- private static Dictionary < string , CommandInfo > chromiumCustomCommands = new Dictionary < string , CommandInfo > ( )
116+ private static readonly Dictionary < string , CommandInfo > chromiumCustomCommands = new Dictionary < string , CommandInfo > ( )
114117 {
115118 { GetNetworkConditionsCommand , new HttpCommandInfo ( HttpCommandInfo . GetCommand , "/session/{sessionId}/chromium/network_conditions" ) } ,
116119 { SetNetworkConditionsCommand , new HttpCommandInfo ( HttpCommandInfo . PostCommand , "/session/{sessionId}/chromium/network_conditions" ) } ,
@@ -127,19 +130,18 @@ public class ChromiumDriver : WebDriver, ISupportsLogs, IDevTools
127130 /// <param name="service">The <see cref="ChromiumDriverService"/> to use.</param>
128131 /// <param name="options">The <see cref="ChromiumOptions"/> to be used with the ChromiumDriver.</param>
129132 /// <param name="commandTimeout">The maximum amount of time to wait for each command.</param>
133+ /// <exception cref="ArgumentNullException">If <paramref name="service"/> or <paramref name="options"/> are <see langword="null"/>.</exception>
134+ /// <exception cref="ArgumentException">If the Chromium options capability name is <see langword="null"/>.</exception>
130135 protected ChromiumDriver ( ChromiumDriverService service , ChromiumOptions options , TimeSpan commandTimeout )
131136 : base ( GenerateDriverServiceCommandExecutor ( service , options , commandTimeout ) , ConvertOptionsToCapabilities ( options ) )
132137 {
133- this . optionsCapabilityName = options . CapabilityName ;
138+ this . optionsCapabilityName = options . CapabilityName ?? throw new ArgumentException ( "No chromium options capability name specified" , nameof ( options ) ) ;
134139 }
135140
136141 /// <summary>
137142 /// Gets the dictionary of custom Chromium commands registered with the driver.
138143 /// </summary>
139- protected static IReadOnlyDictionary < string , CommandInfo > ChromiumCustomCommands
140- {
141- get { return new ReadOnlyDictionary < string , CommandInfo > ( chromiumCustomCommands ) ; }
142- }
144+ protected static IReadOnlyDictionary < string , CommandInfo > ChromiumCustomCommands => new ReadOnlyDictionary < string , CommandInfo > ( chromiumCustomCommands ) ;
143145
144146 /// <summary>
145147 /// Uses DriverFinder to set Service attributes if necessary when creating the command executor
@@ -150,6 +152,16 @@ protected static IReadOnlyDictionary<string, CommandInfo> ChromiumCustomCommands
150152 /// <returns></returns>
151153 private static ICommandExecutor GenerateDriverServiceCommandExecutor ( DriverService service , DriverOptions options , TimeSpan commandTimeout )
152154 {
155+ if ( service is null )
156+ {
157+ throw new ArgumentNullException ( nameof ( service ) ) ;
158+ }
159+
160+ if ( options is null )
161+ {
162+ throw new ArgumentNullException ( nameof ( options ) ) ;
163+ }
164+
153165 if ( service . DriverServicePath == null )
154166 {
155167 DriverFinder finder = new DriverFinder ( options ) ;
@@ -177,27 +189,31 @@ private static ICommandExecutor GenerateDriverServiceCommandExecutor(DriverServi
177189 /// in conjunction with a standalone WebDriver server.</remarks>
178190 public override IFileDetector FileDetector
179191 {
180- get { return base . FileDetector ; }
192+ get => base . FileDetector ;
181193 set { }
182194 }
183195
184196 /// <summary>
185197 /// Gets a value indicating whether a DevTools session is active.
186198 /// </summary>
187- public bool HasActiveDevToolsSession
188- {
189- get { return this . devToolsSession != null ; }
190- }
199+ [ MemberNotNullWhen ( true , nameof ( devToolsSession ) ) ]
200+ public bool HasActiveDevToolsSession => this . devToolsSession != null ;
191201
192202 /// <summary>
193203 /// Gets or sets the network condition emulation for Chromium.
194204 /// </summary>
205+ /// <exception cref="ArgumentNullException">If the value is set to <see langword="null"/>.</exception>
195206 public ChromiumNetworkConditions NetworkConditions
196207 {
197208 get
198209 {
199210 Response response = this . Execute ( GetNetworkConditionsCommand , null ) ;
200- return ChromiumNetworkConditions . FromDictionary ( response . Value as Dictionary < string , object > ) ;
211+ if ( response . Value is not Dictionary < string , object ? > responseDictionary )
212+ {
213+ throw new WebDriverException ( $ "GetNetworkConditions command returned successfully, but data was not an object: { response . Value } ") ;
214+ }
215+
216+ return ChromiumNetworkConditions . FromDictionary ( responseDictionary ) ;
201217 }
202218
203219 set
@@ -209,6 +225,7 @@ public ChromiumNetworkConditions NetworkConditions
209225
210226 Dictionary < string , object > parameters = new Dictionary < string , object > ( ) ;
211227 parameters [ "network_conditions" ] = value ;
228+
212229 this . Execute ( SetNetworkConditionsCommand , parameters ) ;
213230 }
214231 }
@@ -217,6 +234,7 @@ public ChromiumNetworkConditions NetworkConditions
217234 /// Launches a Chromium based application.
218235 /// </summary>
219236 /// <param name="id">ID of the chromium app to launch.</param>
237+ /// <exception cref="ArgumentNullException">If <paramref name="id"/> is <see langword="null"/>.</exception>
220238 public void LaunchApp ( string id )
221239 {
222240 if ( id == null )
@@ -226,6 +244,7 @@ public void LaunchApp(string id)
226244
227245 Dictionary < string , object > parameters = new Dictionary < string , object > ( ) ;
228246 parameters [ "id" ] = id ;
247+
229248 this . Execute ( LaunchAppCommand , parameters ) ;
230249 }
231250
@@ -234,6 +253,7 @@ public void LaunchApp(string id)
234253 /// </summary>
235254 /// <param name="permissionName">Name of item to set the permission on.</param>
236255 /// <param name="permissionValue">Value to set the permission to.</param>
256+ /// <exception cref="ArgumentNullException">If <paramref name="permissionName"/> or <paramref name="permissionValue"/> are <see langword="null"/>.</exception>
237257 public void SetPermission ( string permissionName , string permissionValue )
238258 {
239259 if ( permissionName == null )
@@ -260,7 +280,8 @@ public void SetPermission(string permissionName, string permissionValue)
260280 /// <param name="commandName">Name of the command to execute.</param>
261281 /// <param name="commandParameters">Parameters of the command to execute.</param>
262282 /// <returns>An object representing the result of the command, if applicable.</returns>
263- public object ExecuteCdpCommand ( string commandName , Dictionary < string , object > commandParameters )
283+ /// <exception cref="ArgumentNullException">If <paramref name="commandName"/> is <see langword="null"/>.</exception>
284+ public object ? ExecuteCdpCommand ( string commandName , Dictionary < string , object > commandParameters )
264285 {
265286 if ( commandName == null )
266287 {
@@ -296,21 +317,20 @@ public DevToolsSession GetDevToolsSession(DevToolsOptions options)
296317 throw new WebDriverException ( "Cannot find " + this . optionsCapabilityName + " capability for driver" ) ;
297318 }
298319
299- Dictionary < string , object > optionsCapability = this . Capabilities . GetCapability ( this . optionsCapabilityName ) as Dictionary < string , object > ;
300- if ( optionsCapability == null )
320+ object ? optionsCapabilityObject = this . Capabilities . GetCapability ( this . optionsCapabilityName ) ;
321+ if ( optionsCapabilityObject is not Dictionary < string , object ? > optionsCapability )
301322 {
302- throw new WebDriverException ( "Found " + this . optionsCapabilityName + " capability, but is not an object") ;
323+ throw new WebDriverException ( $ "Found { this . optionsCapabilityName } capability, but is not an object: { optionsCapabilityObject } ") ;
303324 }
304325
305- if ( ! optionsCapability . ContainsKey ( "debuggerAddress" ) )
326+ if ( ! optionsCapability . TryGetValue ( "debuggerAddress" , out object ? debuggerAddress ) )
306327 {
307328 throw new WebDriverException ( "Did not find debuggerAddress capability in " + this . optionsCapabilityName ) ;
308329 }
309330
310- string debuggerAddress = optionsCapability [ "debuggerAddress" ] . ToString ( ) ;
311331 try
312332 {
313- DevToolsSession session = new DevToolsSession ( debuggerAddress , options ) ;
333+ DevToolsSession session = new DevToolsSession ( debuggerAddress ? . ToString ( ) , options ) ;
314334 Task . Run ( async ( ) => await session . StartSession ( ) ) . GetAwaiter ( ) . GetResult ( ) ;
315335 this . devToolsSession = session ;
316336 }
@@ -341,7 +361,7 @@ public void CloseDevToolsSession()
341361 {
342362 if ( this . devToolsSession != null )
343363 {
344- Task . Run ( async ( ) => await this . devToolsSession . StopSession ( true ) ) . GetAwaiter ( ) . GetResult ( ) ;
364+ Task . Run ( async ( ) => await this . devToolsSession . StopSession ( manualDetach : true ) ) . GetAwaiter ( ) . GetResult ( ) ;
345365 }
346366 }
347367
@@ -361,18 +381,16 @@ public List<Dictionary<string, string>> GetCastSinks()
361381 {
362382 List < Dictionary < string , string > > returnValue = new List < Dictionary < string , string > > ( ) ;
363383 Response response = this . Execute ( GetCastSinksCommand , null ) ;
364- object [ ] responseValue = response . Value as object [ ] ;
365- if ( responseValue != null )
384+ if ( response . Value is object ? [ ] responseValue )
366385 {
367- foreach ( object entry in responseValue )
386+ foreach ( object ? entry in responseValue )
368387 {
369- Dictionary < string , object > entryValue = entry as Dictionary < string , object > ;
370- if ( entryValue != null )
388+ if ( entry is Dictionary < string , object ? > entryValue )
371389 {
372390 Dictionary < string , string > sink = new Dictionary < string , string > ( ) ;
373- foreach ( KeyValuePair < string , object > pair in entryValue )
391+ foreach ( KeyValuePair < string , object ? > pair in entryValue )
374392 {
375- sink [ pair . Key ] = pair . Value . ToString ( ) ;
393+ sink [ pair . Key ] = pair . Value ! . ToString ( ) ! ;
376394 }
377395
378396 returnValue . Add ( sink ) ;
@@ -434,10 +452,10 @@ public void StartDesktopMirroring(string deviceName)
434452 /// Returns the error message if there is any issue in a Cast session.
435453 /// </summary>
436454 /// <returns>An error message.</returns>
437- public String GetCastIssueMessage ( )
455+ public string ? GetCastIssueMessage ( )
438456 {
439457 Response response = this . Execute ( GetCastIssueMessageCommand , null ) ;
440- return ( string ) response . Value ;
458+ return ( string ? ) response . Value ;
441459 }
442460
443461 /// <summary>
0 commit comments