Skip to content

Commit 37d2ec1

Browse files
[dotnet] [bidi] Simplify conversion to LocalValue (#15441)
1 parent 8f09638 commit 37d2ec1

File tree

4 files changed

+199
-13
lines changed

4 files changed

+199
-13
lines changed

dotnet/src/webdriver/BiDi/BiDiException.cs

+3
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,7 @@ public class BiDiException : Exception
2626
public BiDiException(string message) : base(message)
2727
{
2828
}
29+
public BiDiException(string? message, Exception? innerException) : base(message, innerException)
30+
{
31+
}
2932
}

dotnet/src/webdriver/BiDi/Modules/Script/LocalValue.cs

+80-12
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@
1717
// under the License.
1818
// </copyright>
1919

20+
using System;
2021
using System.Collections.Generic;
22+
using System.Linq;
23+
using System.Numerics;
2124
using System.Text.Json.Serialization;
2225

2326
namespace OpenQA.Selenium.BiDi.Modules.Script;
@@ -38,33 +41,98 @@ namespace OpenQA.Selenium.BiDi.Modules.Script;
3841
[JsonDerivedType(typeof(SetLocalValue), "set")]
3942
public abstract record LocalValue
4043
{
41-
public static implicit operator LocalValue(int value) { return new NumberLocalValue(value); }
44+
public static implicit operator LocalValue(bool? value) { return value is bool b ? new BooleanLocalValue(b) : new NullLocalValue(); }
45+
public static implicit operator LocalValue(int? value) { return value is int i ? new NumberLocalValue(i) : new NullLocalValue(); }
46+
public static implicit operator LocalValue(double? value) { return value is double d ? new NumberLocalValue(d) : new NullLocalValue(); }
4247
public static implicit operator LocalValue(string? value) { return value is null ? new NullLocalValue() : new StringLocalValue(value); }
4348

4449
// TODO: Extend converting from types
4550
public static LocalValue ConvertFrom(object? value)
4651
{
4752
switch (value)
4853
{
49-
case LocalValue:
50-
return (LocalValue)value;
54+
case LocalValue localValue:
55+
return localValue;
56+
5157
case null:
5258
return new NullLocalValue();
53-
case int:
54-
return (int)value;
55-
case string:
56-
return (string)value;
57-
case object:
59+
60+
case bool b:
61+
return new BooleanLocalValue(b);
62+
63+
case int i:
64+
return new NumberLocalValue(i);
65+
66+
case double d:
67+
return new NumberLocalValue(d);
68+
69+
case long l:
70+
return new NumberLocalValue(l);
71+
72+
case DateTime dt:
73+
return new DateLocalValue(dt.ToString("o"));
74+
75+
case BigInteger bigInt:
76+
return new BigIntLocalValue(bigInt.ToString());
77+
78+
case string str:
79+
return new StringLocalValue(str);
80+
81+
case IDictionary<string, string?> dictionary:
5882
{
59-
var type = value.GetType();
83+
var bidiObject = new List<List<LocalValue>>(dictionary.Count);
84+
foreach (var item in dictionary)
85+
{
86+
bidiObject.Add([new StringLocalValue(item.Key), ConvertFrom(item.Value)]);
87+
}
6088

61-
var properties = type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
89+
return new ObjectLocalValue(bidiObject);
90+
}
91+
92+
case IDictionary<string, object?> dictionary:
93+
{
94+
var bidiObject = new List<List<LocalValue>>(dictionary.Count);
95+
foreach (var item in dictionary)
96+
{
97+
bidiObject.Add([new StringLocalValue(item.Key), ConvertFrom(item.Value)]);
98+
}
99+
100+
return new ObjectLocalValue(bidiObject);
101+
}
102+
103+
case IDictionary<int, object?> dictionary:
104+
{
105+
var bidiObject = new List<List<LocalValue>>(dictionary.Count);
106+
foreach (var item in dictionary)
107+
{
108+
bidiObject.Add([ConvertFrom(item.Key), ConvertFrom(item.Value)]);
109+
}
110+
111+
return new MapLocalValue(bidiObject);
112+
}
113+
114+
case IEnumerable<object?> list:
115+
return new ArrayLocalValue(list.Select(ConvertFrom).ToList());
116+
117+
case object:
118+
{
119+
const System.Reflection.BindingFlags Flags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance;
62120

63-
List<List<LocalValue>> values = [];
121+
var properties = value.GetType().GetProperties(Flags);
64122

123+
var values = new List<List<LocalValue>>(properties.Length);
65124
foreach (var property in properties)
66125
{
67-
values.Add([property.Name, ConvertFrom(property.GetValue(value))]);
126+
object? propertyValue;
127+
try
128+
{
129+
propertyValue = property.GetValue(value);
130+
}
131+
catch (Exception ex)
132+
{
133+
throw new BiDiException($"Could not retrieve property {property.Name} from {property.DeclaringType}", ex);
134+
}
135+
values.Add([property.Name, ConvertFrom(propertyValue)]);
68136
}
69137

70138
return new ObjectLocalValue(values);

dotnet/test/common/BiDi/Script/CallFunctionLocalValueTest.cs

+17-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ await context.Script.CallFunctionAsync($$"""
5757
}
5858

5959
[Test]
60-
public void CanCallFunctionWithArgumentBoolean()
60+
public void CanCallFunctionWithArgumentTrue()
6161
{
6262
var arg = new BooleanLocalValue(true);
6363
Assert.That(async () =>
@@ -72,6 +72,22 @@ await context.Script.CallFunctionAsync($$"""
7272
}, Throws.Nothing);
7373
}
7474

75+
[Test]
76+
public void CanCallFunctionWithArgumentFalse()
77+
{
78+
var arg = new BooleanLocalValue(false);
79+
Assert.That(async () =>
80+
{
81+
await context.Script.CallFunctionAsync($$"""
82+
(arg) => {
83+
if (arg !== false) {
84+
throw new Error("Assert failed: " + arg);
85+
}
86+
}
87+
""", false, new() { Arguments = [arg] });
88+
}, Throws.Nothing);
89+
}
90+
7591
[Test]
7692
public void CanCallFunctionWithArgumentBigInt()
7793
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// <copyright file="LocalValueConversionTests.cs" company="Selenium Committers">
2+
// Licensed to the Software Freedom Conservancy (SFC) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The SFC licenses this file
6+
// to you under the Apache License, Version 2.0 (the
7+
// "License"); you may not use this file except in compliance
8+
// with the License. You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing,
13+
// software distributed under the License is distributed on an
14+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
// KIND, either express or implied. See the License for the
16+
// specific language governing permissions and limitations
17+
// under the License.
18+
// </copyright>
19+
20+
using NUnit.Framework;
21+
using OpenQA.Selenium.BiDi.Modules.Script;
22+
23+
namespace OpenQA.Selenium.BiDi.Script;
24+
25+
class LocalValueConversionTests
26+
{
27+
[Test]
28+
public void CanConvertNullBoolToLocalValue()
29+
{
30+
bool? arg = null;
31+
LocalValue result = arg;
32+
Assert.That(result, Is.TypeOf<NullLocalValue>());
33+
}
34+
35+
[Test]
36+
public void CanConvertTrueToLocalValue()
37+
{
38+
LocalValue result = true;
39+
Assert.That(result, Is.TypeOf<BooleanLocalValue>());
40+
Assert.That((result as BooleanLocalValue).Value, Is.True);
41+
}
42+
43+
[Test]
44+
public void CanConvertFalseToLocalValue()
45+
{
46+
LocalValue result = false;
47+
Assert.That(result, Is.TypeOf<BooleanLocalValue>());
48+
Assert.That((result as BooleanLocalValue).Value, Is.False);
49+
}
50+
51+
[Test]
52+
public void CanConvertNullIntToLocalValue()
53+
{
54+
int? arg = null;
55+
LocalValue result = arg;
56+
Assert.That(result, Is.TypeOf<NullLocalValue>());
57+
}
58+
59+
[Test]
60+
public void CanConvertZeroIntToLocalValue()
61+
{
62+
LocalValue result = 0;
63+
Assert.That(result, Is.TypeOf<NumberLocalValue>());
64+
Assert.That((result as NumberLocalValue).Value, Is.Zero);
65+
}
66+
67+
[Test]
68+
public void CanConvertNullDoubleToLocalValue()
69+
{
70+
double? arg = null;
71+
LocalValue result = arg;
72+
Assert.That(result, Is.TypeOf<NullLocalValue>());
73+
}
74+
75+
[Test]
76+
public void CanConvertZeroDoubleToLocalValue()
77+
{
78+
double arg = 0;
79+
LocalValue result = arg;
80+
Assert.That(result, Is.TypeOf<NumberLocalValue>());
81+
Assert.That((result as NumberLocalValue).Value, Is.Zero);
82+
}
83+
84+
[Test]
85+
public void CanConvertNullStringToLocalValue()
86+
{
87+
string arg = null;
88+
LocalValue result = arg;
89+
Assert.That(result, Is.TypeOf<NullLocalValue>());
90+
}
91+
92+
[Test]
93+
public void CanConvertStringToLocalValue()
94+
{
95+
LocalValue result = "value";
96+
Assert.That(result, Is.TypeOf<StringLocalValue>());
97+
Assert.That((result as StringLocalValue).Value, Is.EqualTo("value"));
98+
}
99+
}

0 commit comments

Comments
 (0)