7
7
using System . ClientModel . Primitives ;
8
8
using System . Collections . Generic ;
9
9
using System . Reflection ;
10
+ using System . Runtime . InteropServices ;
10
11
using System . Threading . Tasks ;
11
12
12
13
namespace System . ClientModel . Tests . Pipeline ;
@@ -181,11 +182,13 @@ public void GenerateUserAgentString_ProducesValidUserAgent()
181
182
Assembly assembly = Assembly . GetExecutingAssembly ( ) ;
182
183
183
184
// Test without application ID
184
- string userAgent = UserAgentPolicy . GenerateUserAgentString ( assembly ) ;
185
- Assert . IsNotNull ( userAgent ) ;
186
- Assert . IsNotEmpty ( userAgent ) ;
185
+ var policy = new UserAgentPolicy ( assembly ) ;
186
+ Assert . IsNotNull ( policy ) ;
187
+ Assert . IsNull ( policy . ApplicationId ) ;
188
+ Assert . AreEqual ( assembly , policy . Assembly ) ;
187
189
188
190
// Should contain assembly name and version
191
+ var userAgent = policy . UserAgentValue ;
189
192
string assemblyName = assembly . GetName ( ) . Name ! ;
190
193
Assert . That ( userAgent , Does . Contain ( assemblyName ) ) ;
191
194
@@ -200,9 +203,11 @@ public void GenerateUserAgentString_WithApplicationId_ProducesValidUserAgent()
200
203
Assembly assembly = Assembly . GetExecutingAssembly ( ) ;
201
204
string applicationId = "TestApp/1.0" ;
202
205
203
- string userAgent = UserAgentPolicy . GenerateUserAgentString ( assembly , applicationId ) ;
204
- Assert . IsNotNull ( userAgent ) ;
205
- Assert . IsNotEmpty ( userAgent ) ;
206
+ var policy = new UserAgentPolicy ( assembly , applicationId ) ;
207
+ Assert . IsNotNull ( policy ) ;
208
+ Assert . AreEqual ( applicationId , policy . ApplicationId ) ;
209
+ Assert . AreEqual ( assembly , policy . Assembly ) ;
210
+ var userAgent = policy . UserAgentValue ;
206
211
207
212
// Should start with application ID
208
213
Assert . That ( userAgent , Does . StartWith ( applicationId ) ) ;
@@ -211,4 +216,150 @@ public void GenerateUserAgentString_WithApplicationId_ProducesValidUserAgent()
211
216
string assemblyName = assembly . GetName ( ) . Name ! ;
212
217
Assert . That ( userAgent , Does . Contain ( assemblyName ) ) ;
213
218
}
214
- }
219
+
220
+ [ Test ]
221
+ [ TestCase ( "ValidParens (2023-)" , "ValidParens (2023-)" ) ]
222
+ [ TestCase ( "(ValidParens (2023-))" , "(ValidParens (2023-))" ) ]
223
+ [ TestCase ( "ProperlyEscapedParens \\ (2023-\\ )" , "ProperlyEscapedParens \\ (2023-\\ )" ) ]
224
+ [ TestCase ( "UnescapedOnlyParens (2023-)" , "UnescapedOnlyParens (2023-)" ) ]
225
+ [ TestCase ( "UnmatchedOpenParen (2023-" , "UnmatchedOpenParen \\ (2023-" ) ]
226
+ [ TestCase ( "UnEscapedParenWithValidParens (()" , "UnEscapedParenWithValidParens \\ (\\ (\\ )" ) ]
227
+ [ TestCase ( "UnEscapedInvalidParen (" , "UnEscapedInvalidParen \\ (" ) ]
228
+ [ TestCase ( "UnEscapedParenWithValidParens2 ())" , "UnEscapedParenWithValidParens2 \\ (\\ )\\ )" ) ]
229
+ [ TestCase ( "InvalidParen )" , "InvalidParen \\ )" ) ]
230
+ [ TestCase ( "(InvalidParen " , "\\ (InvalidParen " ) ]
231
+ [ TestCase ( "UnescapedParenInText MyO)SDescription " , "UnescapedParenInText MyO\\ )SDescription " ) ]
232
+ [ TestCase ( "UnescapedParenInText MyO(SDescription " , "UnescapedParenInText MyO\\ (SDescription " ) ]
233
+ public void ValidatesProperParenthesisMatching ( string input , string output )
234
+ {
235
+ var mockRuntimeInformation = new MockRuntimeInformation
236
+ {
237
+ OSDescriptionMock = input ,
238
+ FrameworkDescriptionMock = RuntimeInformation . FrameworkDescription
239
+ } ;
240
+ var assembly = Assembly . GetExecutingAssembly ( ) ;
241
+ AssemblyInformationalVersionAttribute ? versionAttribute = assembly . GetCustomAttribute < AssemblyInformationalVersionAttribute > ( ) ;
242
+ string version = versionAttribute ! . InformationalVersion ;
243
+ int hashSeparator = version . IndexOf ( '+' ) ;
244
+ if ( hashSeparator != - 1 )
245
+ {
246
+ version = version . Substring ( 0 , hashSeparator ) ;
247
+ }
248
+
249
+ string userAgent = UserAgentPolicy . GenerateUserAgentString ( assembly , null , mockRuntimeInformation ) ;
250
+ string assemblyName = assembly . GetName ( ) . Name ! ;
251
+
252
+ Assert . AreEqual (
253
+ $ "{ assemblyName } /{ version } ({ mockRuntimeInformation . FrameworkDescription } ; { output } )",
254
+ userAgent ) ;
255
+ }
256
+
257
+ [ Test ]
258
+ [ TestCase ( "Win64; x64" , "Win64; x64" ) ]
259
+ [ TestCase ( "Intel Mac OS X 10_15_7" , "Intel Mac OS X 10_15_7" ) ]
260
+ [ TestCase ( "Android 10; SM-G973F" , "Android 10; SM-G973F" ) ]
261
+ [ TestCase ( "Win64; x64; Xbox; Xbox One" , "Win64; x64; Xbox; Xbox One" ) ]
262
+ public void AsciiDoesNotEncode ( string input , string output )
263
+ {
264
+ var mockRuntimeInformation = new MockRuntimeInformation
265
+ {
266
+ OSDescriptionMock = input ,
267
+ FrameworkDescriptionMock = RuntimeInformation . FrameworkDescription
268
+ } ;
269
+ var assembly = Assembly . GetExecutingAssembly ( ) ;
270
+ AssemblyInformationalVersionAttribute ? versionAttribute = assembly . GetCustomAttribute < AssemblyInformationalVersionAttribute > ( ) ;
271
+ string version = versionAttribute ! . InformationalVersion ;
272
+ int hashSeparator = version . IndexOf ( '+' ) ;
273
+ if ( hashSeparator != - 1 )
274
+ {
275
+ version = version . Substring ( 0 , hashSeparator ) ;
276
+ }
277
+
278
+ string userAgent = UserAgentPolicy . GenerateUserAgentString ( assembly , null , mockRuntimeInformation ) ;
279
+ string assemblyName = assembly . GetName ( ) . Name ! ;
280
+
281
+ Assert . AreEqual (
282
+ $ "{ assemblyName } /{ version } ({ mockRuntimeInformation . FrameworkDescription } ; { output } )",
283
+ userAgent ) ;
284
+ }
285
+
286
+ [ Test ]
287
+ [ TestCase ( "»-Browser¢sample" , "%C2%BB-Browser%C2%A2sample" ) ]
288
+ [ TestCase ( "NixOS 24.11 (Vicuña)" , "NixOS+24.11+(Vicu%C3%B1a)" ) ]
289
+ public void NonAsciiCharactersAreUrlEncoded ( string input , string output )
290
+ {
291
+ var mockRuntimeInformation = new MockRuntimeInformation
292
+ {
293
+ OSDescriptionMock = input ,
294
+ FrameworkDescriptionMock = RuntimeInformation . FrameworkDescription
295
+ } ;
296
+ var assembly = Assembly . GetExecutingAssembly ( ) ;
297
+ AssemblyInformationalVersionAttribute ? versionAttribute = assembly . GetCustomAttribute < AssemblyInformationalVersionAttribute > ( ) ;
298
+ string version = versionAttribute ! . InformationalVersion ;
299
+ int hashSeparator = version . IndexOf ( '+' ) ;
300
+ if ( hashSeparator != - 1 )
301
+ {
302
+ version = version . Substring ( 0 , hashSeparator ) ;
303
+ }
304
+
305
+ string userAgent = UserAgentPolicy . GenerateUserAgentString ( assembly , null , mockRuntimeInformation ) ;
306
+ string assemblyName = assembly . GetName ( ) . Name ! ;
307
+
308
+ Assert . AreEqual (
309
+ $ "{ assemblyName } /{ version } ({ mockRuntimeInformation . FrameworkDescription } ; { output } )",
310
+ userAgent ) ;
311
+ }
312
+
313
+ [ Test ]
314
+ public void GenerateUserAgentString_WithCustomRuntimeInfo_ProducesValidUserAgent ( )
315
+ {
316
+ var assembly = Assembly . GetExecutingAssembly ( ) ;
317
+ var mockRuntimeInfo = new MockRuntimeInformation
318
+ {
319
+ OSDescriptionMock = "Test OS" ,
320
+ FrameworkDescriptionMock = "Test Framework"
321
+ } ;
322
+
323
+ string userAgent = UserAgentPolicy . GenerateUserAgentString ( assembly , null , mockRuntimeInfo ) ;
324
+
325
+ // Get expected values
326
+ string assemblyName = assembly . GetName ( ) . Name ! ;
327
+ AssemblyInformationalVersionAttribute ? versionAttribute = assembly . GetCustomAttribute < AssemblyInformationalVersionAttribute > ( ) ;
328
+ string version = versionAttribute ! . InformationalVersion ;
329
+ int hashSeparator = version . IndexOf ( '+' ) ;
330
+ if ( hashSeparator != - 1 )
331
+ {
332
+ version = version . Substring ( 0 , hashSeparator ) ;
333
+ }
334
+
335
+ string expectedUserAgent = $ "{ assemblyName } /{ version } ({ mockRuntimeInfo . FrameworkDescriptionMock } ; { mockRuntimeInfo . OSDescriptionMock } )";
336
+ Assert . AreEqual ( expectedUserAgent , userAgent ) ;
337
+ }
338
+
339
+ [ Test ]
340
+ public void GenerateUserAgentString_WithCustomRuntimeInfoAndApplicationId_ProducesValidUserAgent ( )
341
+ {
342
+ var assembly = Assembly . GetExecutingAssembly ( ) ;
343
+ string applicationId = "TestApp/1.0" ;
344
+ var mockRuntimeInfo = new MockRuntimeInformation
345
+ {
346
+ OSDescriptionMock = "Test OS" ,
347
+ FrameworkDescriptionMock = "Test Framework"
348
+ } ;
349
+
350
+ string userAgent = UserAgentPolicy . GenerateUserAgentString ( assembly , applicationId , mockRuntimeInfo ) ;
351
+
352
+ // Get expected values
353
+ string assemblyName = assembly . GetName ( ) . Name ! ;
354
+ AssemblyInformationalVersionAttribute ? versionAttribute = assembly . GetCustomAttribute < AssemblyInformationalVersionAttribute > ( ) ;
355
+ string version = versionAttribute ! . InformationalVersion ;
356
+ int hashSeparator = version . IndexOf ( '+' ) ;
357
+ if ( hashSeparator != - 1 )
358
+ {
359
+ version = version . Substring ( 0 , hashSeparator ) ;
360
+ }
361
+
362
+ string expectedUserAgent = $ "{ applicationId } { assemblyName } /{ version } ({ mockRuntimeInfo . FrameworkDescriptionMock } ; { mockRuntimeInfo . OSDescriptionMock } )";
363
+ Assert . AreEqual ( expectedUserAgent , userAgent ) ;
364
+ }
365
+ }
0 commit comments