-
-
Notifications
You must be signed in to change notification settings - Fork 233
Expand file tree
/
Copy pathBindableTests.cs
More file actions
126 lines (112 loc) · 5.05 KB
/
BindableTests.cs
File metadata and controls
126 lines (112 loc) · 5.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#if !NETFRAMEWORK
using Microsoft.Extensions.Configuration;
using Sentry.Internal.DiagnosticSource;
namespace Sentry.Testing;
public abstract class BindableTests<TOptions>(params string[] skipProperties)
{
public class TextFixture
{
public IEnumerable<string> ExpectedPropertyNames { get; }
public List<KeyValuePair<PropertyInfo, object>> ExpectedPropertyValues { get; }
public IConfigurationRoot Config { get; }
public TextFixture(params string[] skipProperties)
{
ExpectedPropertyNames = GetBindableProperties(skipProperties).Select(x => x.Name);
ExpectedPropertyValues = GetBindableProperties(skipProperties).Select(GetDummyBindableValue).ToList();
Config = new ConfigurationBuilder()
.AddInMemoryCollection(ExpectedPropertyValues.SelectMany(ToConfigValues))
.Build();
}
}
protected TextFixture Fixture { get; } = new(skipProperties);
private static IEnumerable<PropertyInfo> GetBindableProperties(IEnumerable<string> skipProperties)
{
return typeof(TOptions).GetProperties()
.Where(p =>
!p.PropertyType.IsSubclassOf(typeof(Delegate)) // Exclude delegate properties
&& !p.PropertyType.IsInterface // Exclude interface properties
&& !skipProperties.Contains(p.Name) // Exclude any properties explicitly excluded by derived classes
// Exclude the Mobile sub-properties
#if ANDROID
&& !(p.PropertyType == typeof(SentryOptions.AndroidOptions))
&& !(p.PropertyType == typeof(SentryOptions.NativeOptions))
#elif __IOS__
&& !(p.PropertyType == typeof(SentryOptions.NativeOptions))
#endif
);
}
protected IEnumerable<string> GetPropertyNames<T>() => typeof(T).GetProperties().Select(x => x.Name).ToList();
private static KeyValuePair<PropertyInfo, object> GetDummyBindableValue(PropertyInfo propertyInfo)
{
var propertyType = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
var value = propertyType switch
{
not null when propertyType == typeof(bool) => true,
not null when propertyType == typeof(string) => $"fake {propertyInfo.Name}",
not null when propertyType == typeof(int) => 7,
not null when propertyType == typeof(short) => 7,
not null when propertyType == typeof(long) => 7,
not null when propertyType == typeof(float) => 0.3f,
not null when propertyType == typeof(double) => 0.6,
not null when propertyType == typeof(TimeSpan) => TimeSpan.FromSeconds(3),
not null when propertyType.IsEnum => GetNonDefaultEnumValue(propertyType),
not null when propertyType == typeof(Dictionary<string, string>) =>
new Dictionary<string, string>
{
{$"key1", $"{propertyInfo.Name}value1"},
{$"key2", $"{propertyInfo.Name}value2"}
},
_ => throw new NotSupportedException($"Unsupported property type on property {propertyInfo.Name}")
};
return new KeyValuePair<PropertyInfo, object>(propertyInfo, value);
}
private static IEnumerable<KeyValuePair<string, string>> ToConfigValues(KeyValuePair<PropertyInfo, object> item)
{
var (prop, value) = item;
var propertyType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
if (propertyType == typeof(Dictionary<string, string>))
{
foreach (var kvp in (Dictionary<string, string>)value)
{
yield return new KeyValuePair<string, string>($"{prop.Name}:{kvp.Key}", kvp.Value);
}
}
else
{
yield return new KeyValuePair<string, string>(prop.Name, Convert.ToString(value, CultureInfo.InvariantCulture));
}
}
private static object GetNonDefaultEnumValue(Type enumType)
{
var enumValues = Enum.GetValues(enumType);
if (enumValues.Length > 1)
{
return enumValues.GetValue(1); // return second value
}
throw new InvalidOperationException("Enum has no non-default values");
}
protected void AssertContainsAllOptionsProperties(IEnumerable<string> actual)
{
var missing = Fixture.ExpectedPropertyNames.Where(x => !actual.Contains(x));
missing.Should().BeEmpty();
}
protected void AssertContainsExpectedPropertyValues(TOptions actual)
{
using (new AssertionScope())
{
foreach (var (prop, expectedValue) in Fixture.ExpectedPropertyValues)
{
var actualValue = actual.GetProperty(prop.Name);
if (prop.PropertyType == typeof(Dictionary<string, string>))
{
actualValue.Should().BeEquivalentTo(expectedValue);
}
else
{
actualValue.Should().Be(expectedValue);
}
}
}
}
}
#endif