PageRenderTime 52ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Compilers/Core/CodeAnalysisTest/CachingLookupTests.cs

https://gitlab.com/sharadag/Roslyn
C# | 287 lines | 241 code | 41 blank | 5 comment | 4 complexity | c6a59fc937bddec652b82f7010be65c1 MD5 | raw file
  1. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Collections.Immutable;
  5. using System.Linq;
  6. using Microsoft.CodeAnalysis.Collections;
  7. using Microsoft.CodeAnalysis.Text;
  8. using Xunit;
  9. namespace Microsoft.CodeAnalysis.UnitTests
  10. {
  11. /// <summary>
  12. /// Tests for CachingLookup.
  13. /// </summary>
  14. public class CachingLookupTests
  15. {
  16. private readonly Random _randomCaseGenerator = new Random(17);
  17. private int[] RandomNumbers(int length, int seed)
  18. {
  19. Random rand = new Random(seed);
  20. int[] result = new int[length];
  21. for (int i = 0; i < length; ++i)
  22. {
  23. result[i] = rand.Next(100, ((length / 10) + 4) * 100);
  24. }
  25. return result;
  26. }
  27. private HashSet<string> Keys(int[] numbers, bool randomCase, IEqualityComparer<string> comparer)
  28. {
  29. var keys = new HashSet<string>(comparer);
  30. foreach (var n in numbers)
  31. {
  32. keys.Add(GetKey(n, randomCase));
  33. }
  34. return keys;
  35. }
  36. private string GetKey(int number, bool randomCase)
  37. {
  38. if (randomCase)
  39. {
  40. bool upper = _randomCaseGenerator.Next(2) == 0;
  41. return (upper ? "AA" : "aa") + Right2Chars(number.ToString());
  42. }
  43. else
  44. {
  45. return "AA" + Right2Chars(number.ToString());
  46. }
  47. }
  48. private ImmutableArray<int> Values(string key, int[] numbers, bool ignoreCase)
  49. {
  50. return (from n in numbers
  51. where string.Equals(GetKey(n, ignoreCase), key, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)
  52. select n).ToArray().AsImmutableOrNull();
  53. }
  54. private ILookup<string, int> CreateLookup(int[] numbers, bool randomCase)
  55. {
  56. if (randomCase)
  57. {
  58. return numbers.ToLookup(n => GetKey(n, randomCase), StringComparer.OrdinalIgnoreCase);
  59. }
  60. else
  61. {
  62. return numbers.ToLookup(n => GetKey(n, randomCase), StringComparer.Ordinal);
  63. }
  64. }
  65. private string Right2Chars(string s)
  66. {
  67. return s.Substring(s.Length - 2);
  68. }
  69. private void CheckEqualEnumerable<T>(IEnumerable<T> e1, IEnumerable<T> e2)
  70. {
  71. List<T> l1 = e1.ToList();
  72. List<T> l2 = e2.ToList();
  73. Assert.Equal(l1.Count, l2.Count);
  74. foreach (T item in l1)
  75. {
  76. Assert.Contains(item, l2);
  77. }
  78. foreach (T item in l2)
  79. {
  80. Assert.Contains(item, l1);
  81. }
  82. }
  83. private void CompareLookups1(ILookup<string, int> look1, CachingDictionary<string, int> look2, HashSet<string> keys)
  84. {
  85. foreach (string k in keys)
  86. {
  87. Assert.Equal(look1.Contains(k), look2.Contains(k));
  88. CheckEqualEnumerable(look1[k], look2[k]);
  89. }
  90. foreach (string k in new string[] { "foo", "bar", "banana", "flibber" })
  91. {
  92. Assert.False(look1.Contains(k));
  93. Assert.False(look2.Contains(k));
  94. Assert.Empty(look1[k]);
  95. Assert.Empty(look2[k]);
  96. }
  97. }
  98. private void CompareLookups2(ILookup<string, int> look1, CachingDictionary<string, int> look2, HashSet<string> keys)
  99. {
  100. foreach (string k in look1.Select(g => g.Key))
  101. {
  102. CheckEqualEnumerable(look1[k], look2[k]);
  103. }
  104. foreach (string k in look2.Keys)
  105. {
  106. CheckEqualEnumerable(look1[k], look2[k]);
  107. }
  108. Assert.Equal(look1.Count, look2.Count);
  109. }
  110. private void CompareLookups2(CachingDictionary<string, int> look1, ILookup<string, int> look2, HashSet<string> keys)
  111. {
  112. foreach (string k in look1.Keys)
  113. {
  114. CheckEqualEnumerable(look1[k], look2[k]);
  115. }
  116. foreach (string k in look2.Select(g => g.Key))
  117. {
  118. CheckEqualEnumerable(look1[k], look2[k]);
  119. }
  120. Assert.Equal(look1.Count, look2.Count);
  121. }
  122. [Fact]
  123. public void CachingLookupCorrectResults()
  124. {
  125. StringComparer comparer = StringComparer.Ordinal;
  126. int[] numbers = RandomNumbers(200, 11234);
  127. var dict = new Dictionary<string, ImmutableArray<int>>(comparer);
  128. foreach (string k in Keys(numbers, false, comparer))
  129. {
  130. dict.Add(k, Values(k, numbers, false));
  131. }
  132. var look1 = CreateLookup(numbers, false);
  133. var look2 = new CachingDictionary<string, int>(
  134. s => dict.ContainsKey(s) ? dict[s] : ImmutableArray.Create<int>(),
  135. (c) => Keys(numbers, false, comparer: c), comparer);
  136. CompareLookups1(look1, look2, Keys(numbers, false, comparer));
  137. look1 = CreateLookup(numbers, false);
  138. look2 = new CachingDictionary<string, int>(
  139. s => dict.ContainsKey(s) ? dict[s] : ImmutableArray.Create<int>(),
  140. (c) => Keys(numbers, false, comparer: c), comparer);
  141. CompareLookups2(look1, look2, Keys(numbers, false, comparer));
  142. CompareLookups1(look1, look2, Keys(numbers, false, comparer));
  143. look1 = CreateLookup(numbers, false);
  144. look2 = new CachingDictionary<string, int>(
  145. s => dict.ContainsKey(s) ? dict[s] : ImmutableArray.Create<int>(),
  146. (c) => Keys(numbers, false, comparer: c), comparer);
  147. CompareLookups2(look2, look1, Keys(numbers, false, comparer));
  148. CompareLookups1(look1, look2, Keys(numbers, false, comparer));
  149. }
  150. [Fact]
  151. public void CachingLookupCaseInsensitive()
  152. {
  153. StringComparer comparer = StringComparer.OrdinalIgnoreCase;
  154. int[] numbers = RandomNumbers(300, 719);
  155. var dict = new Dictionary<string, ImmutableArray<int>>(comparer);
  156. foreach (string k in Keys(numbers, false, comparer))
  157. {
  158. dict.Add(k, Values(k, numbers, false));
  159. }
  160. var look1 = CreateLookup(numbers, true);
  161. var look2 = new CachingDictionary<string, int>(
  162. s => dict.ContainsKey(s) ? dict[s] : ImmutableArray.Create<int>(),
  163. (c) => Keys(numbers, true, comparer: c), comparer);
  164. CompareLookups1(look1, look2, Keys(numbers, true, comparer));
  165. look1 = CreateLookup(numbers, true);
  166. look2 = new CachingDictionary<string, int>(
  167. s => dict.ContainsKey(s) ? dict[s] : ImmutableArray.Create<int>(),
  168. (c) => Keys(numbers, true, comparer: c), comparer);
  169. CompareLookups2(look1, look2, Keys(numbers, true, comparer));
  170. CompareLookups1(look1, look2, Keys(numbers, true, comparer));
  171. look1 = CreateLookup(numbers, true);
  172. look2 = new CachingDictionary<string, int>(
  173. s => dict.ContainsKey(s) ? dict[s] : ImmutableArray.Create<int>(),
  174. (c) => Keys(numbers, true, comparer: c), comparer);
  175. CompareLookups2(look2, look1, Keys(numbers, true, comparer));
  176. CompareLookups1(look1, look2, Keys(numbers, true, comparer));
  177. }
  178. [Fact]
  179. public void CachingLookupCaseInsensitiveNoCacheMissingKeys()
  180. {
  181. StringComparer comparer = StringComparer.OrdinalIgnoreCase;
  182. int[] numbers = RandomNumbers(435, 19874);
  183. var dict = new Dictionary<string, ImmutableArray<int>>(comparer);
  184. foreach (string k in Keys(numbers, false, comparer))
  185. {
  186. dict.Add(k, Values(k, numbers, false));
  187. }
  188. var look1 = CreateLookup(numbers, true);
  189. var look2 = new CachingDictionary<string, int>(s => dict.ContainsKey(s) ? dict[s] : ImmutableArray.Create<int>(),
  190. (c) => Keys(numbers, true, comparer: c), comparer);
  191. CompareLookups1(look1, look2, Keys(numbers, true, comparer));
  192. look1 = CreateLookup(numbers, true);
  193. look2 = new CachingDictionary<string, int>(s => dict.ContainsKey(s) ? dict[s] : ImmutableArray.Create<int>(),
  194. (c) => Keys(numbers, true, comparer: c), comparer);
  195. CompareLookups2(look1, look2, Keys(numbers, true, comparer));
  196. CompareLookups1(look1, look2, Keys(numbers, true, comparer));
  197. look1 = CreateLookup(numbers, true);
  198. look2 = new CachingDictionary<string, int>(s => dict.ContainsKey(s) ? dict[s] : ImmutableArray.Create<int>(),
  199. (c) => Keys(numbers, true, comparer: c), comparer);
  200. CompareLookups2(look2, look1, Keys(numbers, true, comparer));
  201. CompareLookups1(look1, look2, Keys(numbers, true, comparer));
  202. }
  203. // Ensure that we are called back exactly once per key.
  204. [Fact]
  205. public void CallExactlyOncePerKey()
  206. {
  207. StringComparer comparer = StringComparer.OrdinalIgnoreCase;
  208. int[] numbers = RandomNumbers(435, 19874);
  209. var dict = new Dictionary<string, ImmutableArray<int>>(comparer);
  210. foreach (string k in Keys(numbers, false, comparer))
  211. {
  212. dict.Add(k, Values(k, numbers, false));
  213. }
  214. HashSet<string> lookedUp = new HashSet<string>(comparer);
  215. bool askedForKeys = false;
  216. var look1 = new CachingDictionary<string, int>(s =>
  217. {
  218. Assert.False(lookedUp.Contains(s));
  219. lookedUp.Add(s);
  220. return dict.ContainsKey(s) ? dict[s] : ImmutableArray.Create<int>();
  221. },
  222. (c) =>
  223. {
  224. Assert.False(askedForKeys);
  225. askedForKeys = true;
  226. return Keys(numbers, true, comparer: c);
  227. }, comparer);
  228. string key1 = GetKey(numbers[0], false);
  229. string key2 = GetKey(numbers[1], false);
  230. string key3 = GetKey(numbers[2], false);
  231. ImmutableArray<int> retval;
  232. retval = look1[key1];
  233. retval = look1[key2];
  234. retval = look1[key3];
  235. retval = look1[key1];
  236. retval = look1[key2];
  237. retval = look1[key3];
  238. retval = look1[key1];
  239. retval = look1[key2];
  240. retval = look1[key3];
  241. retval = look1[key1];
  242. retval = look1[key2];
  243. retval = look1[key3];
  244. }
  245. }
  246. }