Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[dotnet] Annotate nullable reference types on input devices #14804

Merged
merged 13 commits into from
Jan 24, 2025
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions dotnet/src/webdriver/Interactions/InputDevice.cs
Original file line number Diff line number Diff line change
@@ -21,36 +21,34 @@
using System.Collections.Generic;
using System.Globalization;

#nullable enable

namespace OpenQA.Selenium.Interactions
{
/// <summary>
/// Base class for all input devices for actions.
/// </summary>
public abstract class InputDevice
{
private string deviceName;

/// <summary>
/// Initializes a new instance of the <see cref="InputDevice"/> class.
/// </summary>
/// <param name="deviceName">The unique name of the input device represented by this class.</param>
/// <exception cref="ArgumentException">If <paramref name="deviceName"/> is <see langword="null"/> or <see cref="string.Empty"/>.</exception>
protected InputDevice(string deviceName)
{
if (string.IsNullOrEmpty(deviceName))
{
throw new ArgumentException("Device name must not be null or empty", nameof(deviceName));
}

this.deviceName = deviceName;
this.DeviceName = deviceName;
}

/// <summary>
/// Gets the unique name of this input device.
/// </summary>
public string DeviceName
{
get { return this.deviceName; }
}
public string DeviceName { get; }

/// <summary>
/// Gets the kind of device for this input device.
@@ -90,7 +88,7 @@ public Interaction CreatePause(TimeSpan duration)
/// <returns>A hash code for the current <see cref="InputDevice"/>.</returns>
public override int GetHashCode()
{
return this.deviceName.GetHashCode();
return this.DeviceName.GetHashCode();
}

/// <summary>
@@ -99,7 +97,7 @@ public override int GetHashCode()
/// <returns>A string that represents the current <see cref="InputDevice"/>.</returns>
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "{0} input device [name: {1}]", this.DeviceKind, this.deviceName);
return string.Format(CultureInfo.InvariantCulture, "{0} input device [name: {1}]", this.DeviceKind, this.DeviceName);
}
}
}
20 changes: 8 additions & 12 deletions dotnet/src/webdriver/Interactions/KeyInputDevice.cs
Original file line number Diff line number Diff line change
@@ -21,6 +21,8 @@
using System.Collections.Generic;
using System.Globalization;

#nullable enable

namespace OpenQA.Selenium.Interactions
{
/// <summary>
@@ -40,6 +42,7 @@ public KeyInputDevice()
/// Initializes a new instance of the <see cref="KeyInputDevice"/> class, given the device's name.
/// </summary>
/// <param name="deviceName">The unique name of this input device.</param>
/// <exception cref="ArgumentException">If <paramref name="deviceName"/> is <see langword="null"/> or <see cref="string.Empty"/>.</exception>
public KeyInputDevice(string deviceName)
: base(deviceName)
{
@@ -48,10 +51,7 @@ public KeyInputDevice(string deviceName)
/// <summary>
/// Gets the type of device for this input device.
/// </summary>
public override InputDeviceKind DeviceKind
{
get { return InputDeviceKind.Key; }
}
public override InputDeviceKind DeviceKind => InputDeviceKind.Key;

/// <summary>
/// Converts this input device into an object suitable for serializing across the wire.
@@ -115,27 +115,23 @@ public override string ToString()

private class TypingInteraction : Interaction
{
private string type;
private string value;
private readonly string type;

public TypingInteraction(InputDevice sourceDevice, string type, char codePoint)
: base(sourceDevice)
{
this.type = type;
this.value = codePoint.ToString();
this.Value = codePoint.ToString();
}

protected string Value
{
get { return this.value; }
}
protected string Value { get; }

public override Dictionary<string, object> ToDictionary()
{
Dictionary<string, object> toReturn = new Dictionary<string, object>();

toReturn["type"] = this.type;
toReturn["value"] = this.value;
toReturn["value"] = this.Value;

return toReturn;
}
174 changes: 60 additions & 114 deletions dotnet/src/webdriver/Interactions/PointerInputDevice.cs
Original file line number Diff line number Diff line change
@@ -17,10 +17,12 @@
// under the License.
// </copyright>

using OpenQA.Selenium.Internal;
using System;
using System.Collections.Generic;
using System.Globalization;
using OpenQA.Selenium.Internal;

#nullable enable

namespace OpenQA.Selenium.Interactions
{
@@ -107,7 +109,7 @@ public enum MouseButton
/// </summary>
public class PointerInputDevice : InputDevice
{
private PointerKind pointerKind;
private readonly PointerKind pointerKind;

/// <summary>
/// Initializes a new instance of the <see cref="PointerInputDevice"/> class.
@@ -131,6 +133,7 @@ public PointerInputDevice(PointerKind pointerKind)
/// </summary>
/// <param name="pointerKind">The kind of pointer represented by this input device.</param>
/// <param name="deviceName">The unique name for this input device.</param>
/// <exception cref="ArgumentException">If <paramref name="deviceName"/> is <see langword="null"/> or <see cref="string.Empty"/>.</exception>
public PointerInputDevice(PointerKind pointerKind, string deviceName)
: base(deviceName)
{
@@ -140,10 +143,7 @@ public PointerInputDevice(PointerKind pointerKind, string deviceName)
/// <summary>
/// Gets the type of device for this input device.
/// </summary>
public override InputDeviceKind DeviceKind
{
get { return InputDeviceKind.Pointer; }
}
public override InputDeviceKind DeviceKind => InputDeviceKind.Pointer;

/// <summary>
/// Returns a value for this input device that can be transmitted across the wire to a remote end.
@@ -265,7 +265,7 @@ public Interaction CreatePointerMove(CoordinateOrigin origin, int xOffset, int y
/// <param name="properties">The object containing additional proprties for this pointer move operation.</param>
/// <returns>The action representing the pointer move gesture.</returns>
/// <exception cref="ArgumentException">Thrown when passing CoordinateOrigin.Element into origin.
/// Users should us the other CreatePointerMove overload to move to a specific element.</exception>
/// Users should use the other CreatePointerMove overload to move to a specific element.</exception>
public Interaction CreatePointerMove(CoordinateOrigin origin, int xOffset, int yOffset, TimeSpan duration, PointerEventProperties properties)
{
if (origin == CoordinateOrigin.Element)
@@ -290,103 +290,68 @@ public Interaction CreatePointerCancel()
/// </summary>
public class PointerEventProperties
{
private double? width;
private double? height;
private double? pressure;
private double? tangentialPressure;
private int? tiltX;
private int? tiltY;
private int? twist;
private double? altitudeAngle;
private double? azimuthAngle;

/// <summary>
/// Gets or sets the width (magnitude on x-axis) in pixels of the contact geometry of the pointer.
/// </summary>
public double? Width
{
get { return this.width; }
set { this.width = value; }
}
public double? Width { get; set; }

/// <summary>
/// Gets or sets the height (magnitude on y-axis) in pixels of the contact geometry of the pointer.
/// </summary>
public double? Height
{
get { return this.height; }
set { this.height = value; }
}
public double? Height { get; set; }

/// <summary>
/// Gets or sets the normalized pressure of the pointer input.
/// </summary>
/// <remarks>
/// 0 and 1 represent the minimum and maximum pressure the hardware is capable of detecting, respectively.
/// </remarks>
public double? Pressure
{
get { return this.pressure; }
set { this.pressure = value; }
}
public double? Pressure { get; set; }

/// <summary>
/// Gets or sets the normalized tangential pressure (also known as barrel pressure) of the pointer input.
/// </summary>
/// <remarks>
/// Valid values are between -1 and 1 with 0 being the neutral position of the control.
/// Some hardware may only support positive values between 0 and 1.
/// </remarks>
public double? TangentialPressure
{
get { return this.tangentialPressure; }
set { this.tangentialPressure = value; }
}
public double? TangentialPressure { get; set; }

/// <summary>
/// Gets or sets the plane angle in degrees between the Y-Z plane and the plane containing
/// both the transducer (e.g. pen stylus) axis and the Y axis..
/// </summary>
/// <remarks>
/// Valid values are between -90 and 90. A positive value is to the right.
/// </remarks>
public int? TiltX
{
get { return this.tiltX; }
set { this.tiltX = value; }
}
public int? TiltX { get; set; }

/// <summary>
/// Gets or sets the plane angle in degrees between the X-Z plane and the plane containing
/// both the transducer (e.g. pen stylus) axis and the X axis..
/// </summary>
/// <remarks>
/// Valid values are between -90 and 90. A positive value is toward the user.
/// </remarks>
public int? TiltY
{
get { return this.tiltY; }
set { this.tiltY = value; }
}
public int? TiltY { get; set; }

/// <summary>
/// Gets or sets the clockwise rotation in degrees of a transducer (e.g. stylus) around its own major axis
/// </summary>
/// <remarks>
/// Valid values are between 0 and 359.
/// </remarks>
public int? Twist
{
get { return this.twist; }
set { this.twist = value; }
}
public int? Twist { get; set; }

/// <summary>
/// Gets or sets the altitude in radians of the transducer (e.g. pen/stylus)
/// </summary>
/// <remarks>
/// Valid values are between 0 and π/2, where 0 is parallel to the surface (X-Y plane),
/// and π/2 is perpendicular to the surface.
/// </remarks>
public double? AltitudeAngle
{
get { return this.altitudeAngle; }
set { this.altitudeAngle = value; }
}
public double? AltitudeAngle { get; set; }

/// <summary>
/// Gets or sets the azimuth angle (in radians) of the transducer (e.g. pen/stylus)
/// </summary>
@@ -395,11 +360,7 @@ public double? AltitudeAngle
/// where 0 represents a transducer whose cap is pointing in the direction of increasing X values,
/// and the values progressively increase when going clockwise.
/// </remarks>
public double? AzimuthAngle
{
get { return this.azimuthAngle; }
set { this.azimuthAngle = value; }
}
public double? AzimuthAngle { get; set; }

/// <summary>
/// Serializes the properties of this input device as a dictionary.
@@ -414,44 +375,44 @@ public Dictionary<string, object> ToDictionary()
toReturn["width"] = this.Width.Value;
}

if (this.height.HasValue)
if (this.Height.HasValue)
{
toReturn["height"] = this.height.Value;
toReturn["height"] = this.Height.Value;
}

if (this.pressure.HasValue)
if (this.Pressure.HasValue)
{
toReturn["pressure"] = this.pressure.Value;
toReturn["pressure"] = this.Pressure.Value;
}

if (this.tangentialPressure.HasValue)
if (this.TangentialPressure.HasValue)
{
toReturn["tangentialPressure"] = this.tangentialPressure.Value;
toReturn["tangentialPressure"] = this.TangentialPressure.Value;
}

if (this.tiltX.HasValue)
if (this.TiltX.HasValue)
{
toReturn["tiltX"] = this.tiltX.Value;
toReturn["tiltX"] = this.TiltX.Value;
}

if (this.tiltY.HasValue)
if (this.TiltY.HasValue)
{
toReturn["tiltY"] = this.tiltY.Value;
toReturn["tiltY"] = this.TiltY.Value;
}

if (this.twist.HasValue)
if (this.Twist.HasValue)
{
toReturn["twist"] = this.twist.Value;
toReturn["twist"] = this.Twist.Value;
}

if (this.altitudeAngle.HasValue)
if (this.AltitudeAngle.HasValue)
{
toReturn["altitudeAngle"] = this.altitudeAngle.Value;
toReturn["altitudeAngle"] = this.AltitudeAngle.Value;
}

if (this.azimuthAngle.HasValue)
if (this.AzimuthAngle.HasValue)
{
toReturn["azimuthAngle"] = this.azimuthAngle.Value;
toReturn["azimuthAngle"] = this.AzimuthAngle.Value;
}

return toReturn;
@@ -460,8 +421,8 @@ public Dictionary<string, object> ToDictionary()

private class PointerDownInteraction : Interaction
{
private MouseButton button;
private PointerEventProperties eventProperties;
private readonly MouseButton button;
private readonly PointerEventProperties eventProperties;

public PointerDownInteraction(InputDevice sourceDevice, MouseButton button, PointerEventProperties properties)
: base(sourceDevice)
@@ -473,7 +434,7 @@ public PointerDownInteraction(InputDevice sourceDevice, MouseButton button, Poin
public override Dictionary<string, object> ToDictionary()
{
Dictionary<string, object> toReturn;
if (eventProperties == null)
if (eventProperties is null)
{
toReturn = new Dictionary<string, object>();
}
@@ -487,16 +448,13 @@ public override Dictionary<string, object> ToDictionary()
return toReturn;
}

public override string ToString()
{
return "Pointer down";
}
public override string ToString() => "Pointer down";
}

private class PointerUpInteraction : Interaction
{
private MouseButton button;
private PointerEventProperties eventProperties;
private readonly MouseButton button;
private readonly PointerEventProperties eventProperties;

public PointerUpInteraction(InputDevice sourceDevice, MouseButton button, PointerEventProperties properties)
: base(sourceDevice)
@@ -508,7 +466,7 @@ public PointerUpInteraction(InputDevice sourceDevice, MouseButton button, Pointe
public override Dictionary<string, object> ToDictionary()
{
Dictionary<string, object> toReturn;
if (eventProperties == null)
if (eventProperties is null)
{
toReturn = new Dictionary<string, object>();
}
@@ -523,10 +481,7 @@ public override Dictionary<string, object> ToDictionary()
return toReturn;
}

public override string ToString()
{
return "Pointer up";
}
public override string ToString() => "Pointer up";
}

private class PointerCancelInteraction : Interaction
@@ -543,22 +498,19 @@ public override Dictionary<string, object> ToDictionary()
return toReturn;
}

public override string ToString()
{
return "Pointer cancel";
}
public override string ToString() => "Pointer cancel";
}

private class PointerMoveInteraction : Interaction
{
private IWebElement target;
private int x = 0;
private int y = 0;
private readonly IWebElement? target;
private readonly int x = 0;
private readonly int y = 0;
private TimeSpan duration = TimeSpan.MinValue;
private CoordinateOrigin origin = CoordinateOrigin.Pointer;
private PointerEventProperties eventProperties;
private readonly CoordinateOrigin origin = CoordinateOrigin.Pointer;
private readonly PointerEventProperties eventProperties;

public PointerMoveInteraction(InputDevice sourceDevice, IWebElement target, CoordinateOrigin origin, int x, int y, TimeSpan duration, PointerEventProperties properties)
public PointerMoveInteraction(InputDevice sourceDevice, IWebElement? target, CoordinateOrigin origin, int x, int y, TimeSpan duration, PointerEventProperties properties)
: base(sourceDevice)
{
if (target != null)
@@ -622,31 +574,25 @@ public override string ToString()
string originDescription = this.origin.ToString();
if (this.origin == CoordinateOrigin.Element)
{
originDescription = this.target.ToString();
originDescription = this.target!.ToString()!;
}

return string.Format(CultureInfo.InvariantCulture, "Pointer move [origin: {0}, x offset: {1}, y offset: {2}, duration: {3}ms]", originDescription, this.x, this.y, this.duration.TotalMilliseconds);
}

private Dictionary<string, object> ConvertElement()
{
IWebDriverObjectReference elementReference = this.target as IWebDriverObjectReference;
if (elementReference == null)
if (this.target is IWebDriverObjectReference element)
{
IWrapsElement elementWrapper = this.target as IWrapsElement;
if (elementWrapper != null)
{
elementReference = elementWrapper.WrappedElement as IWebDriverObjectReference;
}
return element.ToDictionary();
}

if (elementReference == null)
if (this.target is IWrapsElement { WrappedElement: IWebDriverObjectReference wrappedElement })
{
throw new ArgumentException("Target element cannot be converted to IWebElementReference");
return wrappedElement.ToDictionary();
}

Dictionary<string, object> elementDictionary = elementReference.ToDictionary();
return elementDictionary;
throw new ArgumentException("Target element cannot be converted to IWebElementReference");
}
}
}
73 changes: 23 additions & 50 deletions dotnet/src/webdriver/Interactions/WheelInputDevice.cs
Original file line number Diff line number Diff line change
@@ -17,9 +17,11 @@
// under the License.
// </copyright>

using OpenQA.Selenium.Internal;
using System;
using System.Collections.Generic;
using OpenQA.Selenium.Internal;

#nullable enable

namespace OpenQA.Selenium.Interactions
{
@@ -40,6 +42,7 @@ public WheelInputDevice()
/// Initializes a new instance of the <see cref="WheelInputDevice"/> class, given the device's name.
/// </summary>
/// <param name="deviceName">The unique name of this input device.</param>
/// <exception cref="ArgumentException">If <paramref name="deviceName"/> is <see langword="null"/> or <see cref="string.Empty"/>.</exception>
public WheelInputDevice(string deviceName)
: base(deviceName)
{
@@ -48,10 +51,7 @@ public WheelInputDevice(string deviceName)
/// <summary>
/// Gets the type of device for this input device.
/// </summary>
public override InputDeviceKind DeviceKind
{
get { return InputDeviceKind.Wheel; }
}
public override InputDeviceKind DeviceKind => InputDeviceKind.Wheel;

/// <summary>
/// Returns a value for this input device that can be transmitted across the wire to a remote end.
@@ -114,60 +114,39 @@ public Interaction CreateWheelScroll(CoordinateOrigin origin, int xOffset, int y
/// </summary>
public class ScrollOrigin
{
private IWebElement element;
private bool viewport;
private int xOffset = 0;
private int yOffset = 0;

/// <summary>
/// Gets or sets the element for the scroll origin.
/// </summary>
public IWebElement Element
{
get { return this.element; }
set { this.element = value; }
}
public IWebElement? Element { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the viewport should be used as the origin.
/// </summary>
public bool Viewport
{
get { return this.viewport; }
set { this.viewport = value; }
}
public bool Viewport { get; set; }

/// <summary>
/// Gets or sets the horizontal offset of the scroll origin.
/// </summary>
public int XOffset
{
get { return this.xOffset; }
set { this.xOffset = value; }
}
public int XOffset { get; set; } = 0;

/// <summary>
/// Gets or sets the vertical offset of the scroll origin.
/// </summary>
public int YOffset
{
get { return this.yOffset; }
set { this.yOffset = value; }
}
public int YOffset { get; set; } = 0;

}

private class WheelScrollInteraction : Interaction
{
private IWebElement target;
private int x = 0;
private int y = 0;
private int deltaX = 0;
private int deltaY = 0;
private TimeSpan duration = TimeSpan.MinValue;
private CoordinateOrigin origin = CoordinateOrigin.Viewport;

public WheelScrollInteraction(InputDevice sourceDevice, IWebElement target, CoordinateOrigin origin, int x, int y, int deltaX, int deltaY, TimeSpan duration)
private readonly IWebElement? target;
private readonly int x = 0;
private readonly int y = 0;
private readonly int deltaX = 0;
private readonly int deltaY = 0;
private readonly TimeSpan duration = TimeSpan.MinValue;
private readonly CoordinateOrigin origin = CoordinateOrigin.Viewport;

public WheelScrollInteraction(InputDevice sourceDevice, IWebElement? target, CoordinateOrigin origin, int x, int y, int deltaX, int deltaY, TimeSpan duration)
: base(sourceDevice)
{
if (target != null)
@@ -224,23 +203,17 @@ public override Dictionary<string, object> ToDictionary()

private Dictionary<string, object> ConvertElement()
{
IWebDriverObjectReference elementReference = this.target as IWebDriverObjectReference;
if (elementReference == null)
if (this.target is IWebDriverObjectReference element)
{
IWrapsElement elementWrapper = this.target as IWrapsElement;
if (elementWrapper != null)
{
elementReference = elementWrapper.WrappedElement as IWebDriverObjectReference;
}
return element.ToDictionary();
}

if (elementReference == null)
if (this.target is IWrapsElement { WrappedElement: IWebDriverObjectReference wrappedElement })
{
throw new ArgumentException("Target element cannot be converted to IWebElementReference");
return wrappedElement.ToDictionary();
}

Dictionary<string, object> elementDictionary = elementReference.ToDictionary();
return elementDictionary;
throw new ArgumentException("Target element cannot be converted to IWebElementReference");
}
}
}