Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
248 changes: 186 additions & 62 deletions dotnet/src/webdriver/BiDi/Modules/Script/LocalValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ namespace OpenQA.Selenium.BiDi.Modules.Script;
[JsonDerivedType(typeof(SetLocalValue), "set")]
public abstract record LocalValue
{
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); }
public static implicit operator LocalValue(bool? value) { return ConvertFrom(value); }
public static implicit operator LocalValue(int? value) { return ConvertFrom(value); }
public static implicit operator LocalValue(double? value) { return ConvertFrom(value); }
public static implicit operator LocalValue(string? value) { return ConvertFrom(value); }

// TODO: Extend converting from types
public static LocalValue ConvertFrom(object? value)
Expand All @@ -58,86 +58,210 @@ public static LocalValue ConvertFrom(object? value)
return new NullLocalValue();

case bool b:
return new BooleanLocalValue(b);
return ConvertFrom(b);

case int i:
return new NumberLocalValue(i);
return ConvertFrom(i);

case double d:
return new NumberLocalValue(d);
return ConvertFrom(d);

case long l:
return new NumberLocalValue(l);
return ConvertFrom(l);

case DateTime dt:
return new DateLocalValue(dt.ToString("o"));
return ConvertFrom(dt);

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

case string str:
return new StringLocalValue(str);
return ConvertFrom(str);

case IDictionary<string, string?> dictionary:
{
var bidiObject = new List<List<LocalValue>>(dictionary.Count);
foreach (var item in dictionary)
{
bidiObject.Add([new StringLocalValue(item.Key), ConvertFrom(item.Value)]);
}

return new ObjectLocalValue(bidiObject);
}
return ConvertFrom(dictionary);

case IDictionary<string, object?> dictionary:
{
var bidiObject = new List<List<LocalValue>>(dictionary.Count);
foreach (var item in dictionary)
{
bidiObject.Add([new StringLocalValue(item.Key), ConvertFrom(item.Value)]);
}

return new ObjectLocalValue(bidiObject);
}
return ConvertFrom(dictionary);

case IDictionary<int, object?> dictionary:
{
var bidiObject = new List<List<LocalValue>>(dictionary.Count);
foreach (var item in dictionary)
{
bidiObject.Add([ConvertFrom(item.Key), ConvertFrom(item.Value)]);
}
return ConvertFrom(dictionary);

case ISet<object?> set:
return ConvertFrom(set);

return new MapLocalValue(bidiObject);
}
case IList<object?> set:
return ConvertFrom(set);

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

case object:
{
const System.Reflection.BindingFlags Flags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance;

var properties = value.GetType().GetProperties(Flags);

var values = new List<List<LocalValue>>(properties.Length);
foreach (var property in properties)
{
object? propertyValue;
try
{
propertyValue = property.GetValue(value);
}
catch (Exception ex)
{
throw new BiDiException($"Could not retrieve property {property.Name} from {property.DeclaringType}", ex);
}
values.Add([property.Name, ConvertFrom(propertyValue)]);
}

return new ObjectLocalValue(values);
}
return ConvertFrom(list);

default:
return ReflectionBasedConvertFrom(value);
}
}

public static LocalValue ConvertFrom(bool? value)
{
if (value is bool b)
{
return new BooleanLocalValue(b);
}

return new NullLocalValue();
}

public static LocalValue ConvertFrom(int? value)
{
if (value is int b)
{
return new NumberLocalValue(b);
}

return new NullLocalValue();
}

public static LocalValue ConvertFrom(double? value)
{
if (value is double b)
{
return new NumberLocalValue(b);
}

return new NullLocalValue();
}

public static LocalValue ConvertFrom(long? value)
{
if (value is long b)
{
return new NumberLocalValue(b);
}

return new NullLocalValue();
}

public static LocalValue ConvertFrom(string? value)
{
if (value is not null)
{
return new StringLocalValue(value);
}

return new NullLocalValue();
}

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

return new DateLocalValue(value.Value.ToString("o"));
}

public static LocalValue ConvertFrom(BigInteger? value)
{
if (value is not null)
{
return new BigIntLocalValue(value.Value.ToString());
}

return new NullLocalValue();
}

public static LocalValue ConvertFrom(IEnumerable<object?>? value)
{
if (value is null)
{
return new NullLocalValue();
}

LocalValue[] convertedList = [.. value.Select(ConvertFrom)];
return new ArrayLocalValue(convertedList);
}

public static LocalValue ConvertFrom<T>(IList<T?>? value)
{
if (value is null)
{
return new NullLocalValue();
}

List<LocalValue> convertedList = [.. value.Select(element => ConvertFrom(element))];
return new ArrayLocalValue(convertedList);
}

public static LocalValue ConvertFrom<TValue>(IDictionary<string, TValue?>? value)
{
return ConvertFrom<string, TValue>(value);
}

public static LocalValue ConvertFrom<TKey, TValue>(IDictionary<TKey, TValue?>? value)
{
if (value is null)
{
return new NullLocalValue();
}

var bidiObject = new List<List<LocalValue>>(value.Count);

foreach (KeyValuePair<TKey, TValue?> item in value)
{
bidiObject.Add([ConvertFrom(item.Key), ConvertFrom(item.Value)]);
}

if (typeof(TKey) == typeof(string))
{
return new ObjectLocalValue(bidiObject);
}

return new MapLocalValue(bidiObject);
}

public static LocalValue ConvertFrom<T>(ISet<T?>? value)
{
if (value is null)
{
return new NullLocalValue();
}

LocalValue[] convertedValues = [.. value.Select(x => ConvertFrom(x))];

return new SetLocalValue(convertedValues);
}

private static LocalValue ReflectionBasedConvertFrom(object? value)
{
if (value is null)
{
return new NullLocalValue();
}

const System.Reflection.BindingFlags Flags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance;

System.Reflection.PropertyInfo[] properties = value.GetType().GetProperties(Flags);

var values = new List<List<LocalValue>>(properties.Length);

foreach (System.Reflection.PropertyInfo? property in properties)
{
object? propertyValue;

try
{
propertyValue = property.GetValue(value);
}
catch (Exception ex)
{
throw new BiDiException($"Could not retrieve property {property.Name} from {property.DeclaringType}", ex);
}

values.Add([property.Name, ConvertFrom(propertyValue)]);
}

return new ObjectLocalValue(values);
}
}

Expand Down
Loading