1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Collections;
6 using System.Linq;
7 
8 using Xunit;
9 
10 namespace System.Data.SqlClient.Tests
11 {
12     public partial class SqlConnectionTest
13     {
14         private static readonly string[] s_retrieveStatisticsKeys =
15         {
16             "BuffersReceived",
17             "BuffersSent",
18             "BytesReceived",
19             "BytesSent",
20             "CursorOpens",
21             "IduCount",
22             "IduRows",
23             "PreparedExecs",
24             "Prepares",
25             "SelectCount",
26             "SelectRows",
27             "ServerRoundtrips",
28             "SumResultSets",
29             "Transactions",
30             "UnpreparedExecs",
31             "ConnectionTime",
32             "ExecutionTime",
33             "NetworkServerTime"
34         };
35 
36         [Fact]
RetrieveStatistics_Success()37         public void RetrieveStatistics_Success()
38         {
39             var connection = new SqlConnection();
40             IDictionary d = connection.RetrieveStatistics();
41             Assert.NotNull(d);
42             Assert.NotSame(d, connection.RetrieveStatistics());
43         }
44 
45         [Fact]
RetrieveStatistics_ExpectedKeysInDictionary_Success()46         public void RetrieveStatistics_ExpectedKeysInDictionary_Success()
47         {
48             IDictionary d = new SqlConnection().RetrieveStatistics();
49 
50             Assert.NotEmpty(d);
51             Assert.Equal(s_retrieveStatisticsKeys.Length, d.Count);
52 
53             Assert.NotEmpty(d.Keys);
54             Assert.Equal(s_retrieveStatisticsKeys.Length, d.Keys.Count);
55 
56             Assert.NotEmpty(d.Values);
57             Assert.Equal(s_retrieveStatisticsKeys.Length, d.Values.Count);
58 
59             foreach (string key in s_retrieveStatisticsKeys)
60             {
61                 Assert.True(d.Contains(key));
62 
63                 object value = d[key];
64                 Assert.NotNull(value);
65                 Assert.IsType<long>(value);
66                 Assert.Equal(0L, value);
67             }
68         }
69 
70         [Fact]
RetrieveStatistics_UnexpectedKeysNotInDictionary_Success()71         public void RetrieveStatistics_UnexpectedKeysNotInDictionary_Success()
72         {
73             IDictionary d = new SqlConnection().RetrieveStatistics();
74             Assert.False(d.Contains("Foo"));
75             Assert.Null(d["Foo"]);
76         }
77 
78         [Fact]
RetrieveStatistics_IsSynchronized_Success()79         public void RetrieveStatistics_IsSynchronized_Success()
80         {
81             IDictionary d = new SqlConnection().RetrieveStatistics();
82             Assert.False(d.IsSynchronized);
83         }
84 
85         [Fact]
RetrieveStatistics_SyncRoot_Success()86         public void RetrieveStatistics_SyncRoot_Success()
87         {
88             IDictionary d = new SqlConnection().RetrieveStatistics();
89             Assert.NotNull(d.SyncRoot);
90             Assert.Same(d.SyncRoot, d.SyncRoot);
91         }
92 
93         [Fact]
RetrieveStatistics_IsFixedSize_Success()94         public void RetrieveStatistics_IsFixedSize_Success()
95         {
96             IDictionary d = new SqlConnection().RetrieveStatistics();
97             Assert.False(d.IsFixedSize);
98         }
99 
100         [Fact]
RetrieveStatistics_IsReadOnly_Success()101         public void RetrieveStatistics_IsReadOnly_Success()
102         {
103             IDictionary d = new SqlConnection().RetrieveStatistics();
104             Assert.False(d.IsReadOnly);
105         }
106 
107         public static readonly object[][] RetrieveStatisticsKeyValueData =
108         {
109             new object[] { "Foo", 100L },
110             new object[] { "Foo", null },
111             new object[] { "Blah", "Blah" },
112             new object[] { 100, "Value" }
113         };
114 
115         [Theory]
116         [MemberData(nameof(RetrieveStatisticsKeyValueData))]
RetrieveStatistics_Add_Success(object key, object value)117         public void RetrieveStatistics_Add_Success(object key, object value)
118         {
119             IDictionary d = new SqlConnection().RetrieveStatistics();
120 
121             d.Add(key, value);
122 
123             Assert.True(d.Contains(key));
124 
125             object v = d[key];
126             Assert.Same(value, v);
127         }
128 
129         [Fact]
RetrieveStatistics_Add_ExistingKey_Throws()130         public void RetrieveStatistics_Add_ExistingKey_Throws()
131         {
132             IDictionary d = new SqlConnection().RetrieveStatistics();
133             string key = s_retrieveStatisticsKeys[0];
134             AssertExtensions.Throws<ArgumentException>(null, () => d.Add(key, 100L));
135         }
136 
137         [Fact]
RetrieveStatistics_Add_NullKey_Throws()138         public void RetrieveStatistics_Add_NullKey_Throws()
139         {
140             IDictionary d = new SqlConnection().RetrieveStatistics();
141             AssertExtensions.Throws<ArgumentNullException>("key", () => d.Add(null, 100L));
142         }
143 
144         [Theory]
145         [MemberData(nameof(RetrieveStatisticsKeyValueData))]
RetrieveStatistics_Setter_Success(object key, object value)146         public void RetrieveStatistics_Setter_Success(object key, object value)
147         {
148             IDictionary d = new SqlConnection().RetrieveStatistics();
149 
150             d[key] = value;
151 
152             Assert.True(d.Contains(key));
153 
154             object v = d[key];
155             Assert.Same(value, v);
156         }
157 
158         [Fact]
RetrieveStatistics_Setter_ExistingKey_Success()159         public void RetrieveStatistics_Setter_ExistingKey_Success()
160         {
161             IDictionary d = new SqlConnection().RetrieveStatistics();
162             string key = s_retrieveStatisticsKeys[0];
163 
164             d[key] = 100L;
165             Assert.Equal(100L, d[key]);
166         }
167 
168         [Fact]
RetrieveStatistics_Setter_NullKey_Throws()169         public void RetrieveStatistics_Setter_NullKey_Throws()
170         {
171             IDictionary d = new SqlConnection().RetrieveStatistics();
172             AssertExtensions.Throws<ArgumentNullException>("key", () => d[null] = 100L);
173         }
174 
175         [Fact]
RetrieveStatistics_Clear_Success()176         public void RetrieveStatistics_Clear_Success()
177         {
178             IDictionary d = new SqlConnection().RetrieveStatistics();
179 
180             d.Clear();
181 
182             Assert.Empty(d);
183             Assert.Equal(0, d.Count);
184 
185             Assert.Empty(d.Keys);
186             Assert.Equal(0, d.Keys.Count);
187 
188             Assert.Empty(d.Values);
189             Assert.Equal(0, d.Values.Count);
190         }
191 
192         [Fact]
RetrieveStatistics_Remove_ExistingKey_Success()193         public void RetrieveStatistics_Remove_ExistingKey_Success()
194         {
195             IDictionary d = new SqlConnection().RetrieveStatistics();
196 
197             string key = s_retrieveStatisticsKeys[0];
198 
199             Assert.Equal(s_retrieveStatisticsKeys.Length, d.Count);
200             Assert.Equal(s_retrieveStatisticsKeys.Length, d.Keys.Count);
201             Assert.Equal(s_retrieveStatisticsKeys.Length, d.Values.Count);
202             Assert.True(d.Contains(key));
203             Assert.NotNull(d[key]);
204 
205             d.Remove(key);
206 
207             Assert.Equal(s_retrieveStatisticsKeys.Length - 1, d.Count);
208             Assert.Equal(s_retrieveStatisticsKeys.Length - 1, d.Keys.Count);
209             Assert.Equal(s_retrieveStatisticsKeys.Length - 1, d.Values.Count);
210             Assert.False(d.Contains(key));
211             Assert.Null(d[key]);
212         }
213 
214         [Fact]
RetrieveStatistics_Remove_NonExistentKey_Success()215         public void RetrieveStatistics_Remove_NonExistentKey_Success()
216         {
217             IDictionary d = new SqlConnection().RetrieveStatistics();
218 
219             const string key = "Foo";
220 
221             Assert.Equal(s_retrieveStatisticsKeys.Length, d.Count);
222             Assert.Equal(s_retrieveStatisticsKeys.Length, d.Keys.Count);
223             Assert.Equal(s_retrieveStatisticsKeys.Length, d.Values.Count);
224             Assert.False(d.Contains(key));
225             Assert.Null(d[key]);
226 
227             d.Remove(key);
228 
229             Assert.Equal(s_retrieveStatisticsKeys.Length, d.Count);
230             Assert.Equal(s_retrieveStatisticsKeys.Length, d.Keys.Count);
231             Assert.Equal(s_retrieveStatisticsKeys.Length, d.Values.Count);
232             Assert.False(d.Contains(key));
233             Assert.Null(d[key]);
234         }
235 
236         [Fact]
RetrieveStatistics_Remove_NullKey_Throws()237         public void RetrieveStatistics_Remove_NullKey_Throws()
238         {
239             IDictionary d = new SqlConnection().RetrieveStatistics();
240             AssertExtensions.Throws<ArgumentNullException>("key", () => d.Remove(null));
241         }
242 
243         [Fact]
RetrieveStatistics_Contains_NullKey_Throws()244         public void RetrieveStatistics_Contains_NullKey_Throws()
245         {
246             IDictionary d = new SqlConnection().RetrieveStatistics();
247             AssertExtensions.Throws<ArgumentNullException>("key", () => d.Contains(null));
248         }
249 
250         [Fact]
RetrieveStatistics_CopyTo_Success()251         public void RetrieveStatistics_CopyTo_Success()
252         {
253             IDictionary d = new SqlConnection().RetrieveStatistics();
254             DictionaryEntry[] destination = new DictionaryEntry[d.Count];
255 
256             d.CopyTo(destination, 0);
257 
258             int i = 0;
259             foreach (DictionaryEntry entry in d)
260             {
261                 Assert.Equal(entry, destination[i]);
262                 i++;
263             }
264         }
265 
266         [Fact]
RetrieveStatistics_CopyTo_Throws()267         public void RetrieveStatistics_CopyTo_Throws()
268         {
269             IDictionary d = new SqlConnection().RetrieveStatistics();
270 
271             AssertExtensions.Throws<ArgumentNullException>("array", () => d.CopyTo(null, 0));
272             AssertExtensions.Throws<ArgumentNullException>("array", () => d.CopyTo(null, -1));
273             AssertExtensions.Throws<ArgumentOutOfRangeException>("arrayIndex", () => d.CopyTo(new DictionaryEntry[20], -1));
274             AssertExtensions.Throws<ArgumentException>(null, () => d.CopyTo(new DictionaryEntry[20], 18));
275             AssertExtensions.Throws<ArgumentException>(null, () => d.CopyTo(new DictionaryEntry[20], 1000));
276             AssertExtensions.Throws<ArgumentException>(null, () => d.CopyTo(new DictionaryEntry[4, 3], 0));
277             Assert.Throws<InvalidCastException>(() => d.CopyTo(new string[20], 0));
278         }
279 
280         [Fact]
RetrieveStatistics_IDictionary_GetEnumerator_Success()281         public void RetrieveStatistics_IDictionary_GetEnumerator_Success()
282         {
283             IDictionary d = new SqlConnection().RetrieveStatistics();
284 
285             IDictionaryEnumerator e = d.GetEnumerator();
286 
287             Assert.NotNull(e);
288             Assert.NotSame(e, d.GetEnumerator());
289 
290             for (int i = 0; i < 2; i++)
291             {
292                 Assert.Throws<InvalidOperationException>(() => e.Current);
293 
294                 foreach (string ignored in s_retrieveStatisticsKeys)
295                 {
296                     Assert.True(e.MoveNext());
297 
298                     Assert.NotNull(e.Current);
299                     Assert.IsType<DictionaryEntry>(e.Current);
300 
301                     Assert.NotNull(e.Entry.Key);
302                     Assert.IsType<string>(e.Entry.Key);
303                     Assert.NotNull(e.Entry.Value);
304                     Assert.IsType<long>(e.Entry.Value);
305 
306                     Assert.Equal(e.Current, e.Entry);
307                     Assert.Same(e.Key, e.Entry.Key);
308                     Assert.Same(e.Value, e.Entry.Value);
309 
310                     Assert.True(s_retrieveStatisticsKeys.Contains(e.Entry.Key));
311                 }
312 
313                 Assert.False(e.MoveNext());
314                 Assert.False(e.MoveNext());
315                 Assert.False(e.MoveNext());
316 
317                 Assert.Throws<InvalidOperationException>(() => e.Current);
318 
319                 e.Reset();
320             }
321         }
322 
323         [Fact]
RetrieveStatistics_IEnumerable_GetEnumerator_Success()324         public void RetrieveStatistics_IEnumerable_GetEnumerator_Success()
325         {
326             // Treat the result as IEnumerable instead of IDictionary.
327             IEnumerable d = new SqlConnection().RetrieveStatistics();
328 
329             IEnumerator e = d.GetEnumerator();
330 
331             Assert.NotNull(e);
332             Assert.NotSame(e, d.GetEnumerator());
333 
334             for (int i = 0; i < 2; i++)
335             {
336                 Assert.Throws<InvalidOperationException>(() => e.Current);
337 
338                 foreach (string ignored in s_retrieveStatisticsKeys)
339                 {
340                     Assert.True(e.MoveNext());
341 
342                     Assert.NotNull(e.Current);
343 
344                     // Verify the IEnumerable.GetEnumerator enumerator is yielding DictionaryEntry entries,
345                     // not KeyValuePair entries.
346                     Assert.IsType<DictionaryEntry>(e.Current);
347 
348                     DictionaryEntry entry = (DictionaryEntry)e.Current;
349 
350                     Assert.NotNull(entry.Key);
351                     Assert.IsType<string>(entry.Key);
352                     Assert.NotNull(entry.Value);
353                     Assert.IsType<long>(entry.Value);
354 
355                     Assert.True(s_retrieveStatisticsKeys.Contains(entry.Key));
356                 }
357 
358                 Assert.False(e.MoveNext());
359                 Assert.False(e.MoveNext());
360                 Assert.False(e.MoveNext());
361 
362                 Assert.Throws<InvalidOperationException>(() => e.Current);
363 
364                 e.Reset();
365             }
366         }
367 
368         [Fact]
RetrieveStatistics_GetEnumerator_ModifyCollection_Throws()369         public void RetrieveStatistics_GetEnumerator_ModifyCollection_Throws()
370         {
371             IDictionary d = new SqlConnection().RetrieveStatistics();
372 
373             IDictionaryEnumerator e = d.GetEnumerator();
374 
375             d.Add("Foo", 0L);
376 
377             Assert.Throws<InvalidOperationException>(() => e.MoveNext());
378             Assert.Throws<InvalidOperationException>(() => e.Reset());
379         }
380 
381         [Fact]
RetrieveStatistics_Keys_Success()382         public void RetrieveStatistics_Keys_Success()
383         {
384             IDictionary d = new SqlConnection().RetrieveStatistics();
385             Assert.NotNull(d.Keys);
386             Assert.Same(d.Keys, d.Keys);
387         }
388 
389         [Fact]
RetrieveStatistics_Keys_IsSynchronized_Success()390         public void RetrieveStatistics_Keys_IsSynchronized_Success()
391         {
392             IDictionary d = new SqlConnection().RetrieveStatistics();
393             ICollection c = d.Keys;
394             Assert.False(c.IsSynchronized);
395         }
396 
397         [Fact]
RetrieveStatistics_Keys_SyncRoot_Success()398         public void RetrieveStatistics_Keys_SyncRoot_Success()
399         {
400             IDictionary d = new SqlConnection().RetrieveStatistics();
401             ICollection c = d.Keys;
402             Assert.NotNull(c.SyncRoot);
403             Assert.Same(c.SyncRoot, c.SyncRoot);
404         }
405 
406         [Fact]
RetrieveStatistics_Keys_CopyTo_ObjectArray_Success()407         public void RetrieveStatistics_Keys_CopyTo_ObjectArray_Success()
408         {
409             IDictionary d = new SqlConnection().RetrieveStatistics();
410             ICollection c = d.Keys;
411             object[] destination = new object[c.Count];
412 
413             c.CopyTo(destination, 0);
414 
415             Assert.Equal(c.Cast<object>().ToArray(), destination);
416         }
417 
418         [Fact]
RetrieveStatistics_Keys_CopyTo_StringArray_Success()419         public void RetrieveStatistics_Keys_CopyTo_StringArray_Success()
420         {
421             IDictionary d = new SqlConnection().RetrieveStatistics();
422             ICollection c = d.Keys;
423             string[] destination = new string[c.Count];
424 
425             c.CopyTo(destination, 0);
426 
427             Assert.Equal(c.Cast<string>().ToArray(), destination);
428         }
429 
430         [Fact]
RetrieveStatistics_Keys_CopyTo_Throws()431         public void RetrieveStatistics_Keys_CopyTo_Throws()
432         {
433             IDictionary d = new SqlConnection().RetrieveStatistics();
434             ICollection c = d.Keys;
435 
436             AssertExtensions.Throws<ArgumentNullException>("array", () => c.CopyTo(null, 0));
437             AssertExtensions.Throws<ArgumentNullException>("array", () => c.CopyTo(null, -1));
438             AssertExtensions.Throws<ArgumentOutOfRangeException>("arrayIndex", () => c.CopyTo(new string[20], -1));
439             AssertExtensions.Throws<ArgumentException>(null, () => c.CopyTo(new string[20], 18));
440             AssertExtensions.Throws<ArgumentException>(null, () => c.CopyTo(new string[20], 1000));
441             AssertExtensions.Throws<ArgumentException>(null, () => c.CopyTo(new string[4, 3], 0));
442             Assert.Throws<InvalidCastException>(() => c.CopyTo(new Version[20], 0));
443         }
444 
445         [Fact]
RetrieveStatistics_Keys_GetEnumerator_Success()446         public void RetrieveStatistics_Keys_GetEnumerator_Success()
447         {
448             IDictionary d = new SqlConnection().RetrieveStatistics();
449             ICollection c = d.Keys;
450 
451             IEnumerator e = c.GetEnumerator();
452 
453             Assert.NotNull(e);
454             Assert.NotSame(e, c.GetEnumerator());
455 
456             for (int i = 0; i < 2; i++)
457             {
458                 Assert.Throws<InvalidOperationException>(() => e.Current);
459 
460                 foreach (string ignored in s_retrieveStatisticsKeys)
461                 {
462                     Assert.True(e.MoveNext());
463                     Assert.NotNull(e.Current);
464                     Assert.True(s_retrieveStatisticsKeys.Contains(e.Current));
465                 }
466 
467                 Assert.False(e.MoveNext());
468                 Assert.False(e.MoveNext());
469                 Assert.False(e.MoveNext());
470 
471                 Assert.Throws<InvalidOperationException>(() => e.Current);
472 
473                 e.Reset();
474             }
475         }
476 
477         [Fact]
RetrieveStatistics_Keys_GetEnumerator_ModifyCollection_Throws()478         public void RetrieveStatistics_Keys_GetEnumerator_ModifyCollection_Throws()
479         {
480             IDictionary d = new SqlConnection().RetrieveStatistics();
481             ICollection c = d.Keys;
482 
483             IEnumerator e = c.GetEnumerator();
484 
485             d.Add("Foo", 0L);
486 
487             Assert.Throws<InvalidOperationException>(() => e.MoveNext());
488             Assert.Throws<InvalidOperationException>(() => e.Reset());
489         }
490 
491         [Fact]
RetrieveStatistics_Values_Success()492         public void RetrieveStatistics_Values_Success()
493         {
494             IDictionary d = new SqlConnection().RetrieveStatistics();
495             Assert.NotNull(d.Values);
496             Assert.Same(d.Values, d.Values);
497         }
498 
499         [Fact]
RetrieveStatistics_Values_IsSynchronized_Success()500         public void RetrieveStatistics_Values_IsSynchronized_Success()
501         {
502             IDictionary d = new SqlConnection().RetrieveStatistics();
503             ICollection c = d.Values;
504             Assert.False(c.IsSynchronized);
505         }
506 
507         [Fact]
RetrieveStatistics_Values_SyncRoot_Success()508         public void RetrieveStatistics_Values_SyncRoot_Success()
509         {
510             IDictionary d = new SqlConnection().RetrieveStatistics();
511             ICollection c = d.Values;
512             Assert.NotNull(c.SyncRoot);
513             Assert.Same(c.SyncRoot, c.SyncRoot);
514         }
515 
516         [Fact]
RetrieveStatistics_Values_CopyTo_ObjectArray_Success()517         public void RetrieveStatistics_Values_CopyTo_ObjectArray_Success()
518         {
519             IDictionary d = new SqlConnection().RetrieveStatistics();
520             ICollection c = d.Values;
521             object[] destination = new object[c.Count];
522 
523             c.CopyTo(destination, 0);
524 
525             Assert.Equal(c.Cast<object>().ToArray(), destination);
526         }
527 
528         [Fact]
RetrieveStatistics_Values_CopyTo_Int64Array_Success()529         public void RetrieveStatistics_Values_CopyTo_Int64Array_Success()
530         {
531             IDictionary d = new SqlConnection().RetrieveStatistics();
532             ICollection c = d.Values;
533             long[] destination = new long[c.Count];
534 
535             c.CopyTo(destination, 0);
536 
537             Assert.Equal(c.Cast<long>().ToArray(), destination);
538         }
539 
540         [Fact]
RetrieveStatistics_Values_CopyTo_Throws()541         public void RetrieveStatistics_Values_CopyTo_Throws()
542         {
543             IDictionary d = new SqlConnection().RetrieveStatistics();
544             ICollection c = d.Values;
545 
546             AssertExtensions.Throws<ArgumentNullException>("array", () => c.CopyTo(null, 0));
547             AssertExtensions.Throws<ArgumentNullException>("array", () => c.CopyTo(null, -1));
548             AssertExtensions.Throws<ArgumentOutOfRangeException>("arrayIndex", () => c.CopyTo(new long[20], -1));
549             AssertExtensions.Throws<ArgumentException>(null, () => c.CopyTo(new long[20], 18));
550             AssertExtensions.Throws<ArgumentException>(null, () => c.CopyTo(new long[20], 1000));
551             AssertExtensions.Throws<ArgumentException>(null, () => c.CopyTo(new long[4, 3], 0));
552             Assert.Throws<InvalidCastException>(() => c.CopyTo(new Version[20], 0));
553         }
554 
555         [Fact]
RetrieveStatistics_Values_GetEnumerator_Success()556         public void RetrieveStatistics_Values_GetEnumerator_Success()
557         {
558             IDictionary d = new SqlConnection().RetrieveStatistics();
559             ICollection c = d.Values;
560 
561             IEnumerator e = c.GetEnumerator();
562 
563             Assert.NotNull(e);
564             Assert.NotSame(e, c.GetEnumerator());
565 
566             for (int i = 0; i < 2; i++)
567             {
568                 Assert.Throws<InvalidOperationException>(() => e.Current);
569 
570                 foreach (string ignored in s_retrieveStatisticsKeys)
571                 {
572                     Assert.True(e.MoveNext());
573                     Assert.NotNull(e.Current);
574                     Assert.Equal(0L, e.Current);
575                 }
576 
577                 Assert.False(e.MoveNext());
578                 Assert.False(e.MoveNext());
579                 Assert.False(e.MoveNext());
580 
581                 Assert.Throws<InvalidOperationException>(() => e.Current);
582 
583                 e.Reset();
584             }
585         }
586 
587         [Fact]
RetrieveStatistics_Values_GetEnumerator_ModifyCollection_Throws()588         public void RetrieveStatistics_Values_GetEnumerator_ModifyCollection_Throws()
589         {
590             IDictionary d = new SqlConnection().RetrieveStatistics();
591             ICollection c = d.Values;
592 
593             IEnumerator e = c.GetEnumerator();
594 
595             d.Add("Foo", 0L);
596 
597             Assert.Throws<InvalidOperationException>(() => e.MoveNext());
598             Assert.Throws<InvalidOperationException>(() => e.Reset());
599         }
600     }
601 }
602