@@ -13,8 +13,8 @@ Every descriptor should inherit from `DescriptorBase`, this hides object members
1313----
1414var notDescriptors = new[] { typeof(ClusterProcessOpenFileDescriptors).Name, "DescriptorForAttribute" };
1515var descriptors = from t in typeof(DescriptorBase<,>).Assembly().Types()
16- where t.IsClass()
17- && t.Name.Contains("Descriptor")
16+ where t.IsClass()
17+ && t.Name.Contains("Descriptor")
1818 && !notDescriptors.Contains(t.Name)
1919 && !t.GetInterfaces().Any(i => i == typeof(IDescriptor))
2020 select t.FullName;
@@ -59,3 +59,74 @@ var selectorMethods =
5959selectorMethods.Should().BeEmpty();
6060----
6161
62+ Descriptor methods that assign to a nullable bool property should accept
63+ a nullable bool with a default value
64+
65+ [source,csharp]
66+ ----
67+ var queries =
68+ from t in typeof(IQuery).Assembly().Types()
69+ where t.IsInterface() && typeof(IQuery).IsAssignableFrom(t)
70+ where t.GetProperties().Any(p => p.PropertyType == typeof(bool?))
71+ select t;
72+
73+ var descriptors =
74+ from t in typeof(DescriptorBase<,>).Assembly().Types()
75+ where t.IsClass() && typeof(IDescriptor).IsAssignableFrom(t)
76+ where t.GetInterfaces().Intersect(queries).Any()
77+ select t;
78+
79+ var breakingDescriptors = new List<string>();
80+
81+ var parameterlessMethods = new List<MethodInfo>
82+ {
83+ typeof(BoolQueryDescriptor<>).GetMethod(nameof(BoolQueryDescriptor<object>.DisableCoord))
84+ };
85+
86+ var nonDefaultValueMethods = new List<MethodInfo>
87+ {
88+ typeof(SpanNearQueryDescriptor<>).GetMethod(nameof(SpanNearQueryDescriptor<object>.CollectPayloads)),
89+ typeof(SpanNearQueryDescriptor<>).GetMethod(nameof(SpanNearQueryDescriptor<object>.InOrder)),
90+ };
91+ ----
92+
93+ [source,csharp]
94+ ----
95+ foreach (var query in queries)
96+ {
97+ var descriptor = descriptors.First(d => query.IsAssignableFrom(d));
98+ foreach (var boolProperty in query.GetProperties().Where(p => p.PropertyType == typeof(bool?)))
99+ {
100+ var descriptorMethod = descriptor.GetMethod(boolProperty.Name);
101+ if (descriptorMethod == null)
102+ throw new Exception($"No method for property {boolProperty.Name} on {descriptor.Name}");
103+
104+ var parameters = descriptorMethod.GetParameters();
105+
106+ if (!parameters.Any())
107+ {
108+ if (parameterlessMethods.Contains(descriptorMethod))
109+ continue;
110+
111+ throw new Exception($"No parameter for method {descriptorMethod.Name} on {descriptor.Name}");
112+ }
113+
114+ if (parameters.Length > 1)
115+ throw new Exception($"More than one parameter for method {descriptorMethod.Name} on {descriptor.Name}");
116+
117+ if (parameters[0].ParameterType != typeof(bool?))
118+ breakingDescriptors.Add($"{descriptor.FullName} method {descriptorMethod.Name} does not take nullable bool");
119+
120+ if (!parameters[0].HasDefaultValue)
121+ {
122+ if (nonDefaultValueMethods.Contains(descriptorMethod))
123+ continue;
124+
125+ breakingDescriptors.Add($"{descriptor.FullName} method {descriptorMethod.Name} does not have a default value");
126+ }
127+ }
128+ }
129+
130+ breakingDescriptors.Should().BeEmpty();
131+ ----
132+
0 commit comments