@@ -13,12 +13,27 @@ namespace Microsoft.Data.SqlClient.Tests;
1313
1414public sealed class UserAgentTests
1515{
16+ #region Constants
17+
18+ // All permitted characters that may appear as values in the User Agent.
19+ const string AllPermitted =
20+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
21+ "abcdefghijklmnopqrstuvwxyz" +
22+ "0123456789" +
23+ " .+_-" ;
24+
25+ #endregion
26+
1627 #region Test Setup
1728
18- // Setup to test by saving the xUnit output helper.
29+ /// <summary>
30+ /// Setup to test by saving the xUnit output helper.
31+ /// </summary>
32+ /// <param name="output">The xUnit output helper.</param>
1933 public UserAgentTests ( ITestOutputHelper output )
2034 {
21- // Use --logger option to see the output for successful test runs:
35+ // Use the dotnet CLI --logger option to see the output for successful
36+ // test runs:
2237 //
2338 // dotnet test --logger "console;verbosity=detailed"
2439 //
@@ -31,15 +46,16 @@ public UserAgentTests(ITestOutputHelper output)
3146
3247 #region Tests
3348
34- // Test the Value property when actual runtime information is used.
35- //
36- // This test assumes that values returned by the runtime used to construct
37- // the Value property will all fit within the max length (currently 256
38- // characters).
39- //
40- // If this test fails, then either the max length has changed or the runtime
41- // values have changed in a meaningful way.
42- //
49+ /// <summary>
50+ /// Test the Value property when actual runtime information is used.
51+ ///
52+ /// This test assumes that values returned by the runtime used to construct
53+ /// the Value property will all fit within the max length (currently 256
54+ /// characters).
55+ ///
56+ /// If this test fails, then either the max length has changed or the
57+ /// runtime values have changed in a meaningful way.
58+ /// </summary>
4359 [ Fact ]
4460 public void Value_Runtime_Parts ( )
4561 {
@@ -50,7 +66,7 @@ public void Value_Runtime_Parts()
5066 // Check the basic properties of the value.
5167 Assert . NotNull ( value ) ;
5268 Assert . True ( value . Length > 0 ) ;
53- Assert . True ( value . Length <= 128 ) ;
69+ Assert . True ( value . Length <= 256 ) ;
5470
5571 // Ensure we can split it into the expected parts.
5672 //
@@ -102,25 +118,42 @@ public void Value_Runtime_Parts()
102118 Assert . True ( parts [ 6 ] . Length <= 44 ) ;
103119 }
104120
105- // Test the Ucs2Bytes property when actual runtime information is used.
121+ /// <summary>
122+ /// Test the Ucs2Bytes property when actual runtime information is used.
123+ /// </summary>
106124 [ Fact ]
107125 public void Ucs2Bytes_Runtime_Parts ( )
108126 {
109127 var bytes = UserAgent . Ucs2Bytes ;
110128
111- _output . WriteLine (
112- $ "UserAgent.Ucs2Bytes: 0x{ Convert . ToHexString ( bytes . Span ) } ") ;
129+ #if NET
130+ var hex = Convert . ToHexString ( bytes . Span ) ;
131+ #else
132+ var hex = BitConverter . ToString ( bytes . ToArray ( ) ) . Replace ( "-" , string . Empty ) ;
133+ #endif
134+
135+ _output . WriteLine ( $ "UserAgent.Ucs2Bytes: 0x{ hex } ") ;
113136
114137 // Check the basic properties of the byte array.
115138 Assert . True ( bytes . Length > 0 ) ;
116- Assert . True ( bytes . Length <= 256 * 2 ) ; // USC2 uses 2 bytes per char.
139+ Assert . True ( bytes . Length <= 256 * 2 ) ; // UCS-2 uses 2 bytes per char.
117140
118141 // Ensure we can convert the bytes back to the original string.
119- string value = Encoding . Unicode . GetString ( bytes . Span ) ;
142+ string value =
143+ #if NET
144+ Encoding . Unicode . GetString ( bytes . Span ) ;
145+ #else
146+ Encoding . Unicode . GetString ( bytes . ToArray ( ) ) ;
147+ #endif
148+
120149 Assert. Equal ( UserAgent . Value , value ) ;
121150 }
122151
123- // Test the Build() function when it truncates the overall length.
152+ /// <summary>
153+ /// Test the Build() function when it truncates the overall length.
154+ /// </summary>
155+ /// <param name="maxLen">The expected max payload length.</param>
156+ /// <param name="expected">The expected payload string.</param>
124157 [ Theory ]
125158 [ InlineData ( 0 , "" ) ]
126159 [ InlineData ( 1 , "2" ) ]
@@ -153,7 +186,9 @@ public void Build_Truncate_Overall(ushort maxLen, string expected)
153186 runtimeInfo : "E" ) ) ;
154187 }
155188
156- // Test the Build() function when it truncates the payload version.
189+ /// <summary>
190+ /// Test the Build() function when it truncates the payload version.
191+ /// </summary>
157192 [ Fact ]
158193 public void Build_Truncate_Payload_Version ( )
159194 {
@@ -170,7 +205,9 @@ public void Build_Truncate_Payload_Version()
170205 128 , "1234" , "A" , "B" , "C" , Architecture . X64 , "D" , "E" ) ) ;
171206 }
172207
173- // Test the Build() function when it truncates the driver name.
208+ /// <summary>
209+ /// Test the Build() function when it truncates the driver name.
210+ /// </summary>
174211 [ Fact ]
175212 public void Build_Truncate_Driver_Name ( )
176213 {
@@ -188,7 +225,9 @@ public void Build_Truncate_Driver_Name()
188225 "D" , "E" ) ) ;
189226 }
190227
191- // Test the Build() function when it truncates the driver version.
228+ /// <summary>
229+ /// Test the Build() function when it truncates the driver version.
230+ /// </summary>
192231 [ Fact ]
193232 public void Build_Truncate_Driver_Version ( )
194233 {
@@ -207,7 +246,9 @@ public void Build_Truncate_Driver_Version()
207246 Architecture . X64 , "D" , "E" ) ) ;
208247 }
209248
210- // Test the Build() function when it truncates the OS Type.
249+ /// <summary>
250+ /// Test the Build() function when it truncates the OS Type.
251+ /// </summary>
211252 [ Fact ]
212253 public void Build_Truncate_OS_Type ( )
213254 {
@@ -225,7 +266,9 @@ public void Build_Truncate_OS_Type()
225266 "E" ) ) ;
226267 }
227268
228- // Test the Build() function when it truncates the Architecture.
269+ /// <summary>
270+ /// Test the Build() function when it truncates the Architecture.
271+ /// </summary>
229272 [ Fact ]
230273 public void Build_Truncate_Arch ( )
231274 {
@@ -247,7 +290,9 @@ public void Build_Truncate_Arch()
247290 #endif
248291 }
249292
250- // Test the Build() function when it truncates the OS Info.
293+ /// <summary>
294+ /// Test the Build() function when it truncates the OS Info.
295+ /// </summary>
251296 [ Fact ]
252297 public void Build_Truncate_OS_Info ( )
253298 {
@@ -266,7 +311,9 @@ public void Build_Truncate_OS_Info()
266311 "E" ) ) ;
267312 }
268313
269- // Test the Build() function when it truncates the Runtime Info.
314+ /// <summary>
315+ /// Test the Build() function when it truncates the Runtime Info.
316+ /// </summary>
270317 [ Fact ]
271318 public void Build_Truncate_Runtime_Info ( )
272319 {
@@ -285,8 +332,10 @@ public void Build_Truncate_Runtime_Info()
285332 "01234567890123456789012345678901234567890123456789" ) ) ;
286333 }
287334
288- // Test the Build() function when most of the fields are truncated, and
289- // the overall length is still within the max.
335+ /// <summary>
336+ /// Test the Build() function when most of the fields are truncated, and the
337+ /// overall length is still within the max.
338+ /// </summary>
290339 [ Fact ]
291340 public void Build_Truncate_Most ( )
292341 {
@@ -320,9 +369,13 @@ public void Build_Truncate_Most()
320369 name ) ;
321370 }
322371
372+ // Only .NET has an Architecture enum value long enough to test truncation
373+ // of that part.
323374 #if NET
324- // Test the Build() function when all the fields are truncated, and
325- // the overall length is still within the max.
375+ /// <summary>
376+ /// Test the Build() function when all the fields are truncated, and the
377+ /// overall length is still within the max.
378+ /// </summary>
326379 [ Fact ]
327380 public void Build_Truncate_All ( )
328381 {
@@ -354,46 +407,85 @@ public void Build_Truncate_All()
354407 "E0123456789012345678901234567890123456789012" ,
355408 name ) ;
356409 }
357- #endif // NET
410+ #endif
358411
359- // Test the Clean() function.
412+ /// <summary>
413+ /// Test the Clean() function for null input.
414+ /// </summary>
360415 [ Fact ]
361- public void Clean ( )
416+ public void Clean_Null ( )
362417 {
363418 // Null becomes "Unknown".
364419 Assert . Equal ( "Unknown" , UserAgent . Clean ( null ) ) ;
420+ }
365421
422+ /// <summary>
423+ /// Test the Clean() function for empty input.
424+ /// </summary>
425+ [ Fact ]
426+ public void Clean_Empty ( )
427+ {
366428 // Empty string becomes "Unknown".
367429 Assert . Equal ( "Unknown" , UserAgent . Clean ( string . Empty ) ) ;
430+ }
368431
432+ /// <summary>
433+ /// Test the Clean() function for whitespace input.
434+ /// </summary>
435+ [ Fact ]
436+ public void Clean_Whitespace ( )
437+ {
369438 // Whitespace string becomes "Unknown".
370439 Assert . Equal ( "Unknown" , UserAgent . Clean ( " " ) ) ;
371440 Assert . Equal ( "Unknown" , UserAgent . Clean ( "\t " ) ) ;
372441 Assert . Equal ( "Unknown" , UserAgent . Clean ( "\r " ) ) ;
373442 Assert . Equal ( "Unknown" , UserAgent . Clean ( "\n " ) ) ;
374443 Assert . Equal ( "Unknown" , UserAgent . Clean ( " \t \r \n " ) ) ;
444+ }
375445
446+ /// <summary>
447+ /// Test the Clean() function with leading and trailing whitespace.
448+ /// </summary>
449+ [ Fact ]
450+ public void Clean_Leading_Trailing_Whitespace ( )
451+ {
376452 // Leading and trailing whitespace are removed.
377453 Assert . Equal ( "A" , UserAgent . Clean ( " A" ) ) ;
378454 Assert . Equal ( "A" , UserAgent . Clean ( "A\t " ) ) ;
379455 Assert . Equal ( "A" , UserAgent . Clean ( "\r A\n " ) ) ;
456+ }
380457
458+ /// <summary>
459+ /// Test the Clean() function with permitted characters.
460+ /// </summary>
461+ [ Fact ]
462+ public void Clean_Permitted_Disallowed_Characters ( )
463+ {
381464 // All permitted characters are preserved.
382- const string AllPermitted =
383- "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
384- "abcdefghijklmnopqrstuvwxyz" +
385- "0123456789" +
386- " .+_-" ;
387465 Assert . Equal ( AllPermitted , UserAgent . Clean ( AllPermitted ) ) ;
466+ }
388467
468+ /// <summary>
469+ /// Test the Clean() function with various disallowed characters.
470+ /// </summary>
471+ [ Fact ]
472+ public void Clean_Disallowed_Characters ( )
473+ {
389474 // Each disallowed character is replaced with underscore.
390475 Assert . Equal (
391476 "A_B_C_D_E_F_G_H_I_J_K_L_M_N_O_P" ,
392477 UserAgent . Clean ( "A|B,C;D:E'F\" G[H{I]J}K\\ L/M<N>O?P" ) ) ;
393478 Assert . Equal (
394479 "Q_R_S_T_U_V_W_X+Y-Z_a.b_c_d_e_f_g_h_i_j_k_l_m_n_o" ,
395480 UserAgent . Clean ( "Q^R_S`T~U(V)W*X+Y-Z_a.b,c/d:e<f>g'h\" i[j]k{l}m|n\\ o" ) ) ;
481+ }
396482
483+ /// <summary>
484+ /// Test the Clean() function with all Unicode characters.
485+ /// </summary>
486+ [ Fact ]
487+ public void Clean_All_Unicode_Characters ( )
488+ {
397489 // All disallowed characters are replaced with underscore.
398490 for ( char c = ( char ) 0u ; /* see condition below */ ; ++ c )
399491 {
@@ -405,12 +497,12 @@ public void Clean()
405497 Assert . Equal ( "Unknown" , clean ) ;
406498 }
407499 else if (
408- #if NET
500+ #if NET
409501 AllPermitted . Contains ( c )
410- #else
502+ #else
411503 AllPermitted . Contains ( c . ToString ( ) )
412- #endif
413- )
504+ #endif
505+ )
414506 {
415507 Assert . Equal ( c . ToString ( ) , clean ) ;
416508 }
@@ -433,7 +525,9 @@ public void Clean()
433525 }
434526 }
435527
436- // Test the Trunc() function.
528+ /// <summary>
529+ /// Test the Trunc() function.
530+ /// </summary>
437531 [ Fact ]
438532 public void Trunc ( )
439533 {
0 commit comments