Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
ccc536d
[dotnet] [bidi] Simplify usage of `LocalValue`
RenderMichael Mar 17, 2025
0722af5
Update exception
RenderMichael Mar 17, 2025
cd55951
Use new methods better in tests
RenderMichael Mar 17, 2025
47891c5
`String(null)` returns `NullLocalValue`
RenderMichael Mar 17, 2025
d367a66
Merge branch 'trunk' into local-value
RenderMichael Mar 17, 2025
c7cbaf7
Add regex overload that takes a string pattern
RenderMichael Mar 17, 2025
0c4f8bf
Remote static factory methods for now
RenderMichael Mar 21, 2025
6ae7a94
remove unnecessary change
RenderMichael Mar 21, 2025
c7ac3b9
Avoid BigInt until we need it
RenderMichael Mar 21, 2025
c73fd33
Account for BigInt in ConvertFrom(object)
RenderMichael Mar 21, 2025
a762425
Avoid implicit casts in tests that aren't there to test it
RenderMichael Mar 21, 2025
02ace40
Merge branch 'trunk' into local-value
RenderMichael Mar 21, 2025
2ae4fad
Remote `LocalValue.ConvertFrom(JsonNode)`, expand `ConvertFrom(object)`
RenderMichael Mar 25, 2025
49f1347
Merge branch 'trunk' into local-value
RenderMichael Mar 25, 2025
e875b05
Add ConvertFrom support for `DateTime` and `long`
RenderMichael Mar 25, 2025
4e6db49
Add unit tests to LocalValue operators
RenderMichael Mar 25, 2025
e1ce7ed
Merge branch 'trunk' into local-value
RenderMichael Mar 25, 2025
efd0058
Use var
RenderMichael Mar 25, 2025
64c5eb0
Use in-line literals for `LocalValue` conversions, use a separate fix…
RenderMichael Mar 26, 2025
e647628
Merge branch 'trunk' into local-value
RenderMichael Mar 26, 2025
d0da6e2
Use int literal
RenderMichael Mar 26, 2025
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
87 changes: 80 additions & 7 deletions dotnet/src/webdriver/BiDi/Modules/Script/LocalValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,14 @@
// under the License.
// </copyright>

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;

namespace OpenQA.Selenium.BiDi.Modules.Script;

Expand All @@ -38,22 +44,40 @@ namespace OpenQA.Selenium.BiDi.Modules.Script;
[JsonDerivedType(typeof(SetLocalValue), "set")]
public abstract record LocalValue
{
public static implicit operator LocalValue(int value) { return new NumberLocalValue(value); }
public static implicit operator LocalValue(bool? value) { return value is bool b ? new BooleanLocalValue(b) : new NullLocalValue(); }
public static implicit operator LocalValue(int? value) { return value is int i ? new NumberLocalValue(i) : new NullLocalValue(); }
public static implicit operator LocalValue(double? value) { return value is double d ? new NumberLocalValue(d) : new NullLocalValue(); }
public static implicit operator LocalValue(string? value) { return value is null ? new NullLocalValue() : new StringLocalValue(value); }

// TODO: Extend converting from types
public static LocalValue ConvertFrom(object? value)
{
switch (value)
{
case LocalValue:
return (LocalValue)value;
case LocalValue localValue:
return localValue;

case null:
return new NullLocalValue();
case int:
return (int)value;
case string:
return (string)value;

case bool b:
return new BooleanLocalValue(b);

case int i:
return new NumberLocalValue(i);

case double d:
return new NumberLocalValue(d);

case BigInteger bigInt:
return new BigIntLocalValue(bigInt.ToString());

case string str:
return new StringLocalValue(str);

case IEnumerable<object?> list:
return new ArrayLocalValue(list.Select(ConvertFrom).ToList());

case object:
{
var type = value.GetType();
Expand All @@ -71,6 +95,55 @@ public static LocalValue ConvertFrom(object? value)
}
}
}

public static LocalValue ConvertFrom(JsonNode? node)
{
if (node is null)
{
return new NullLocalValue();
}

switch (node.GetValueKind())
{
case System.Text.Json.JsonValueKind.Null:
return new NullLocalValue();

case System.Text.Json.JsonValueKind.True:
return new BooleanLocalValue(true);

case System.Text.Json.JsonValueKind.False:
return new BooleanLocalValue(false);

case System.Text.Json.JsonValueKind.String:
return new StringLocalValue(node.ToString());

case System.Text.Json.JsonValueKind.Number:
{
var numberString = node.ToString();

var numberAsDouble = double.Parse(numberString);

if (double.IsInfinity(numberAsDouble))
{
// Numbers outside of Int64's range will successfully parse, but become +- Infinity
// We can retain the value using a BigInt
return new BigIntLocalValue(numberString);
}

return new NumberLocalValue(numberAsDouble);
}

case System.Text.Json.JsonValueKind.Array:
return new ArrayLocalValue(node.AsArray().Select(ConvertFrom));

case System.Text.Json.JsonValueKind.Object:
var convertedToListForm = node.AsObject().Select(property => new LocalValue[] { new StringLocalValue(property.Key), ConvertFrom(property.Value) }).ToList();
return new ObjectLocalValue(convertedToListForm);

default:
throw new InvalidOperationException("Invalid JSON node");
}
}
}

public abstract record PrimitiveProtocolLocalValue : LocalValue;
Expand Down
26 changes: 21 additions & 5 deletions dotnet/test/common/BiDi/Script/CallFunctionLocalValueTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ await context.Script.CallFunctionAsync($$"""
}

[Test]
public void CanCallFunctionWithArgumentBoolean()
public void CanCallFunctionWithArgumentTrue()
{
var arg = new BooleanLocalValue(true);
Assert.That(async () =>
Expand All @@ -72,6 +72,22 @@ await context.Script.CallFunctionAsync($$"""
}, Throws.Nothing);
}

[Test]
public void CanCallFunctionWithArgumentFalse()
{
var arg = new BooleanLocalValue(false);
Assert.That(async () =>
{
await context.Script.CallFunctionAsync($$"""
(arg) => {
if (arg !== false) {
throw new Error("Assert failed: " + arg);
}
}
""", false, new() { Arguments = [arg] });
}, Throws.Nothing);
}

[Test]
public void CanCallFunctionWithArgumentBigInt()
{
Expand Down Expand Up @@ -298,7 +314,7 @@ await context.Script.CallFunctionAsync($$"""
[Test]
public void CanCallFunctionWithArgumentArray()
{
var arg = new ArrayLocalValue([new StringLocalValue("hi")]);
var arg = new ArrayLocalValue(["hi"]);

Assert.That(async () =>
{
Expand All @@ -315,7 +331,7 @@ await context.Script.CallFunctionAsync($$"""
[Test]
public void CanCallFunctionWithArgumentObject()
{
var arg = new ObjectLocalValue([[new StringLocalValue("objKey"), new StringLocalValue("objValue")]]);
var arg = new ObjectLocalValue([["objKey", "objValue"]]);

Assert.That(async () =>
{
Expand All @@ -332,7 +348,7 @@ await context.Script.CallFunctionAsync($$"""
[Test]
public void CanCallFunctionWithArgumentMap()
{
var arg = new MapLocalValue([[new StringLocalValue("mapKey"), new StringLocalValue("mapValue")]]);
var arg = new MapLocalValue([["mapKey", "mapValue"]]);

Assert.That(async () =>
{
Expand All @@ -349,7 +365,7 @@ await context.Script.CallFunctionAsync($$"""
[Test]
public void CanCallFunctionWithArgumentSet()
{
var arg = new SetLocalValue([new StringLocalValue("setKey")]);
var arg = new SetLocalValue(["setKey"]);

Assert.That(async () =>
{
Expand Down