4
4
using ProtoBuf . Grpc . Reflection ;
5
5
using System ;
6
6
using System . Collections . Generic ;
7
+ using System . IO ;
8
+ using System . Linq ;
7
9
using System . Runtime . Serialization ;
8
- using System . ServiceModel ;
9
10
using System . Threading . Tasks ;
11
+ using Google . Protobuf . Reflection ;
12
+ using Grpc . Core ;
10
13
using Xunit ;
11
14
using Xunit . Abstractions ;
12
15
@@ -124,7 +127,63 @@ public interface INotAService
124
127
ValueTask NotAServiceAsyncEmpty ( ) ;
125
128
void NotAServiceSyncEmpty ( ) ;
126
129
}
130
+
131
+ [ Theory ]
132
+ [ InlineData ( typeof ( IMyService ) ) ]
133
+ [ InlineData ( typeof ( IMyInheritedService ) ) ]
134
+ [ InlineData ( typeof ( IMyAnotherLevelOfInheritedService ) ) ]
135
+ public void CompareRouteTable ( Type type )
136
+ {
137
+ // 1: use the existing binder logic to build the routes, using the server logic
138
+ var binder = new TestBinder ( ) ;
139
+ binder . Bind ( type , type , BinderConfiguration . Default ) ;
140
+ var viaBinder = binder . Collect ( ) ;
141
+ foreach ( var method in viaBinder ) Log ( method ) ;
142
+ Log ( "" ) ;
143
+
144
+
145
+ // 2: create a schema and parse it for equivalece
146
+ var generator = new SchemaGenerator ( ) ;
147
+ var schema = generator . GetSchema ( type ) ;
148
+ Log ( schema ) ;
149
+ var fds = new FileDescriptorSet ( ) ;
150
+ fds . Add ( "my.proto" , source : new StringReader ( schema ) ) ;
151
+ fds . Process ( ) ;
152
+ Assert . Empty ( fds . GetErrors ( ) ) ;
153
+ var viaSchema = new List < string > ( viaBinder . Length ) ;
154
+ var file = fds . Files . Single ( static x => x . IncludeInOutput ) ;
155
+ foreach ( var service in file . Services )
156
+ {
157
+ var svcName = string . IsNullOrEmpty ( file . Package ) ? service . Name : $ "{ file . Package } .{ service . Name } ";
158
+ foreach ( var method in service . Methods )
159
+ {
160
+ viaSchema . Add ( $ "/{ svcName } /{ method . Name } ") ;
161
+ }
162
+ }
163
+ viaSchema . Sort ( ) ;
164
+
165
+ Assert . Equal ( string . Join ( Environment . NewLine , viaBinder ) , string . Join ( Environment . NewLine , viaSchema ) ) ;
166
+
167
+ }
127
168
169
+ class TestBinder : ServerBinder
170
+ {
171
+ private readonly List < string > _methods = new List < string > ( ) ;
172
+ protected override bool TryBind < TService , TRequest , TResponse > ( ServiceBindContext bindContext , Method < TRequest , TResponse > method , MethodStub < TService > stub )
173
+ {
174
+ _methods . Add ( method . FullName ) ;
175
+ return true ;
176
+ }
177
+
178
+ public string [ ] Collect ( )
179
+ {
180
+ _methods . Sort ( ) ;
181
+ var arr = _methods . ToArray ( ) ;
182
+ _methods . Clear ( ) ; // reset
183
+ return arr ;
184
+ }
185
+ }
186
+
128
187
[ Service ]
129
188
public interface ISomeGenericService < in TGenericRequest , TGenericResult >
130
189
{
@@ -143,6 +202,13 @@ public interface IMyInheritedService : IMyService, ISomeGenericService<MyRequest
143
202
void InheritedSyncEmpty ( ) ;
144
203
}
145
204
205
+
206
+ [ Service ]
207
+ public interface IMyAnotherLevelOfInheritedService : IMyInheritedService
208
+ {
209
+ ValueTask < MyResponse > AnotherMethod ( MyRequest request , CallContext callContext = default ) ;
210
+ }
211
+
146
212
[ DataContract ]
147
213
public class MyRequest
148
214
{
0 commit comments