OSDN Git Service

d3a639f8e7d6f9ec2701ea13bc71df155fd542fd
[wptscs/wpts.git] / HmLibTest / Models / MemoryCacheTest.cs
1 // ================================================================================================
2 // <summary>
3 //      MemoryCacheのテストクラスソース。</summary>
4 //
5 // <copyright file="MemoryCacheTest.cs" company="honeplusのメモ帳">
6 //      Copyright (C) 2012 Honeplus. All rights reserved.</copyright>
7 // <author>
8 //      Honeplus</author>
9 // ================================================================================================
10
11 namespace Honememo.Models
12 {
13     using System;
14     using System.Collections.Generic;
15     using System.Threading;
16     using System.Threading.Tasks;
17     using NUnit.Framework;
18
19     /// <summary>
20     /// <see cref="MemoryCache&lt;TKey, TValue&gt;"/>のテストクラスです。
21     /// </summary>
22     [TestFixture]
23     internal class MemoryCacheTest
24     {
25         #region プロパティテストケース
26
27         /// <summary>
28         /// <see cref="MemoryCache&lt;TKey, TValue&gt;.Capacity"/>プロパティテストケース(正常系)。
29         /// </summary>
30         [Test]
31         public void TestCapacity()
32         {
33             MemoryCache<string, string> cache = new MemoryCache<string, string>();
34             cache.Capacity = 1;
35             Assert.AreEqual(1, cache.Capacity);
36             cache.Capacity = 100;
37             Assert.AreEqual(100, cache.Capacity);
38             cache.Capacity = int.MaxValue;
39             Assert.AreEqual(int.MaxValue, cache.Capacity);
40         }
41
42         /// <summary>
43         /// <see cref="MemoryCache&lt;TKey, TValue&gt;.Capacity"/>プロパティテストケース(0以下の値)。
44         /// </summary>
45         [Test]
46         [ExpectedException(typeof(ArgumentException))]
47         public void TestCapacityZero()
48         {
49             new MemoryCache<string, string>().Capacity = 0;
50         }
51
52         #endregion
53
54         #region インデクサーテストケース
55
56         /// <summary>
57         /// インデクサーテストケース(正常系)。
58         /// </summary>
59         [Test]
60         public void TestThis()
61         {
62             // ※ 以下古いほうから削除の確認のために、登録時に毎回ウェイトを入れる
63             MemoryCache<string, string> cache = new MemoryCache<string, string>();
64
65             // 普通にget/set
66             cache["testkey"] = "testvalue";
67             Assert.AreEqual("testvalue", cache["testkey"]);
68             Assert.IsFalse(cache.ContainsKey("testkey2"));
69             Assert.IsFalse(cache.ContainsKey("testkey3"));
70             Thread.Sleep(1);
71
72             cache["testkey2"] = "testvalue2";
73             Assert.AreEqual("testvalue", cache["testkey"]);
74             Assert.AreEqual("testvalue2", cache["testkey2"]);
75             Assert.IsFalse(cache.ContainsKey("testkey3"));
76             Thread.Sleep(1);
77
78             // インデクサーは上書き可
79             cache["testkey2"] = "testvalue2-2";
80             Assert.AreEqual("testvalue2-2", cache["testkey2"]);
81             Thread.Sleep(1);
82
83             // nullも格納可能
84             cache["testkey3"] = null;
85             Assert.IsTrue(cache.ContainsKey("testkey3"));
86             Assert.IsNull(cache["testkey3"]);
87             Thread.Sleep(1);
88
89             // キャッシュが100件を超えると最後にgetされたのが古い方から10件削除される
90             for (int i = 4; i <= 100; i++)
91             {
92                 cache[i.ToString()] = i.ToString();
93                 Thread.Sleep(1);
94             }
95
96             // 100件丁度ではまだ存在する
97             Assert.IsTrue(cache.ContainsKey("testkey"));
98             Assert.IsTrue(cache.ContainsKey("testkey2"));
99             Assert.IsTrue(cache.ContainsKey("testkey3"));
100             Assert.IsTrue(cache.ContainsKey("4"));
101             Assert.IsTrue(cache.ContainsKey("11"));
102             Assert.IsTrue(cache.ContainsKey("12"));
103             Assert.IsTrue(cache.ContainsKey("100"));
104             Assert.IsFalse(cache.ContainsKey("testkey101"));
105
106             // 片方だけgetを呼んだ上で一件追加
107             Assert.AreEqual("testvalue2-2", cache["testkey2"]);
108             cache["testkey101"] = "testvalue101";
109
110             // アクセスが古い方から10件が削除される
111             Assert.IsFalse(cache.ContainsKey("testkey"));
112             Assert.IsTrue(cache.ContainsKey("testkey2"));
113             Assert.IsFalse(cache.ContainsKey("testkey3"));
114             Assert.IsFalse(cache.ContainsKey("4"));
115             Assert.IsFalse(cache.ContainsKey("11"));
116             Assert.IsTrue(cache.ContainsKey("12"));
117             Assert.IsTrue(cache.ContainsKey("100"));
118             Assert.IsTrue(cache.ContainsKey("testkey101"));
119             Assert.AreEqual("testvalue2-2", cache["testkey2"]);
120             Assert.AreEqual("12", cache["12"]);
121             Assert.AreEqual("testvalue101", cache["testkey101"]);
122         }
123
124         /// <summary>
125         /// インデクサーテストケース(getでnull)。
126         /// </summary>
127         [Test]
128         [ExpectedException(typeof(ArgumentNullException))]
129         public void TestThisGetNull()
130         {
131             string dummy = new MemoryCache<string, string>()[null];
132         }
133
134         /// <summary>
135         /// インデクサーテストケース(getで値無し)。
136         /// </summary>
137         [Test]
138         [ExpectedException(typeof(KeyNotFoundException))]
139         public void TestThisGetEmpty()
140         {
141             string dummy = new MemoryCache<string, string>()["ignore key"];
142         }
143
144         /// <summary>
145         /// インデクサーテストケース(setでnull)。
146         /// </summary>
147         [Test]
148         [ExpectedException(typeof(ArgumentNullException))]
149         public void TestThisSetNull()
150         {
151             new MemoryCache<string, string>()[null] = "test";
152         }
153
154         #endregion
155
156         #region IDictionaryインタフェースにあわせたメソッド
157
158         /// <summary>
159         /// <see cref="MemoryCache&lt;TKey, TValue&gt;.Add"/>メソッドテストケース(正常系)。
160         /// </summary>
161         [Test]
162         public void TestAdd()
163         {
164             // ※ 2012年2月現在、重複チェック以外はインデクサーと同じなので割愛
165             MemoryCache<string, string> cache = new MemoryCache<string, string>();
166
167             cache.Add("testkey", "testvalue");
168             Assert.AreEqual("testvalue", cache["testkey"]);
169             Assert.IsFalse(cache.ContainsKey("testkey2"));
170
171             cache.Add("testkey2", "testvalue2");
172             Assert.AreEqual("testvalue", cache["testkey"]);
173             Assert.AreEqual("testvalue2", cache["testkey2"]);
174         }
175
176         /// <summary>
177         /// <see cref="MemoryCache&lt;TKey, TValue&gt;.Add"/>メソッドテストケース(null)。
178         /// </summary>
179         [Test]
180         [ExpectedException(typeof(ArgumentNullException))]
181         public void TestAddNull()
182         {
183             new MemoryCache<string, string>().Add(null, "dummy");
184         }
185
186         /// <summary>
187         /// <see cref="MemoryCache&lt;TKey, TValue&gt;.Add"/>メソッドテストケース(重複)。
188         /// </summary>
189         [Test]
190         [ExpectedException(typeof(ArgumentException))]
191         public void TestAddAlready()
192         {
193             // 同じ値を重複登録
194             MemoryCache<string, string> cache = new MemoryCache<string, string>();
195             cache["testkey"] = "testvalue";
196             cache.Add("testkey", "testvalue");
197         }
198
199         /// <summary>
200         /// <see cref="MemoryCache&lt;TKey, TValue&gt;.ContainsKey"/>メソッドテストケース。
201         /// </summary>
202         [Test]
203         public void TestContainsKey()
204         {
205             MemoryCache<string, string> cache = new MemoryCache<string, string>();
206
207             Assert.IsFalse(cache.ContainsKey("testkey"));
208             Assert.IsFalse(cache.ContainsKey("testkey2"));
209             
210             cache["testkey"] = "testvalue";
211             Assert.IsTrue(cache.ContainsKey("testkey"));
212             Assert.IsFalse(cache.ContainsKey("testkey2"));
213
214             cache["testkey2"] = "testvalue2";
215             Assert.IsTrue(cache.ContainsKey("testkey"));
216             Assert.IsTrue(cache.ContainsKey("testkey2"));
217         }
218
219         /// <summary>
220         /// <see cref="MemoryCache&lt;TKey, TValue&gt;.ContainsKey"/>メソッドテストケース(null)。
221         /// </summary>
222         [Test]
223         [ExpectedException(typeof(ArgumentNullException))]
224         public void TestContainsKeyNull()
225         {
226             new MemoryCache<string, string>().ContainsKey(null);
227         }
228
229         /// <summary>
230         /// <see cref="MemoryCache&lt;TKey, TValue&gt;.Remove"/>メソッドテストケース。
231         /// </summary>
232         [Test]
233         public void TestRemove()
234         {
235             // 指定されたキャッシュが削除される
236             MemoryCache<string, string> cache = new MemoryCache<string, string>();
237             cache["testkey"] = "testvalue";
238             cache["testkey2"] = "testvalue2";
239             Assert.IsTrue(cache.ContainsKey("testkey"));
240             Assert.IsTrue(cache.ContainsKey("testkey2"));
241             Assert.AreEqual("testvalue", cache.Get("testkey"));
242             Assert.AreEqual("testvalue2", cache.Get("testkey2"));
243
244             Assert.IsTrue(cache.Remove("testkey"));
245             Assert.IsFalse(cache.ContainsKey("testkey"));
246             Assert.IsTrue(cache.ContainsKey("testkey2"));
247
248             Assert.IsTrue(cache.Remove("testkey2"));
249             Assert.IsFalse(cache.ContainsKey("testkey"));
250             Assert.IsFalse(cache.ContainsKey("testkey2"));
251
252             // Removeは値が無くても呼べる
253             Assert.IsFalse(cache.Remove("testkey"));
254         }
255
256         /// <summary>
257         /// <see cref="MemoryCache&lt;TKey, TValue&gt;.Remove"/>メソッドテストケース(null)。
258         /// </summary>
259         [Test]
260         [ExpectedException(typeof(ArgumentNullException))]
261         public void TestRemoveNull()
262         {
263             new MemoryCache<string, string>().Remove(null);
264         }
265
266         /// <summary>
267         /// <see cref="MemoryCache&lt;TKey, TValue&gt;.TryGetValue"/>メソッドテストケース(正常系)。
268         /// </summary>
269         [Test]
270         public void TestTryGetValue()
271         {
272             // ※ 2012年2月現在、例外処理以外についてはインデクサーやGetと同じなので割愛
273             MemoryCache<string, string> cache = new MemoryCache<string, string>();
274             string result;
275
276             Assert.IsFalse(cache.TryGetValue("testkey", out result));
277
278             cache["testkey"] = "testvalue";
279             Assert.IsTrue(cache.TryGetValue("testkey", out result));
280             Assert.AreEqual("testvalue", cache.Get("testkey"));
281         }
282
283         /// <summary>
284         /// <see cref="MemoryCache&lt;TKey, TValue&gt;.TryGetValue"/>メソッドテストケース(null)。
285         /// </summary>
286         [Test]
287         [ExpectedException(typeof(ArgumentNullException))]
288         public void TestTryGetValueNull()
289         {
290             string dummy;
291             new MemoryCache<string, string>().TryGetValue(null, out dummy);
292         }
293
294         /// <summary>
295         /// <see cref="MemoryCache&lt;TKey, TValue&gt;.Clear"/>メソッドテストケース。
296         /// </summary>
297         [Test]
298         public void TestClear()
299         {
300             // 全てのキャッシュが削除される
301             MemoryCache<string, string> cache = new MemoryCache<string, string>();
302             cache["testkey"] = "testvalue";
303             cache["testkey2"] = "testvalue2";
304             Assert.IsTrue(cache.ContainsKey("testkey"));
305             Assert.IsTrue(cache.ContainsKey("testkey2"));
306             Assert.AreEqual("testvalue", cache.Get("testkey"));
307             Assert.AreEqual("testvalue2", cache.Get("testkey2"));
308
309             cache.Clear();
310             Assert.IsFalse(cache.ContainsKey("testkey"));
311             Assert.IsFalse(cache.ContainsKey("testkey2"));
312         }
313
314         #endregion
315
316         #region 独自のメソッドテストケース
317         
318         /// <summary>
319         /// <see cref="MemoryCache&lt;TKey, TValue&gt;.Get"/>メソッドテストケース(正常系)。
320         /// </summary>
321         [Test]
322         public void TestGet()
323         {
324             // ※ 2012年2月現在インデクサーを呼んでいるだけなのでテスト割愛
325             MemoryCache<string, string> cache = new MemoryCache<string, string>();
326             cache["testkey"] = "testvalue";
327             Assert.AreEqual("testvalue", cache.Get("testkey"));
328         }
329
330         /// <summary>
331         /// <see cref="MemoryCache&lt;TKey, TValue&gt;.Get"/>メソッドテストケース(null)。
332         /// </summary>
333         [Test]
334         [ExpectedException(typeof(ArgumentNullException))]
335         public void TestGetNull()
336         {
337             new MemoryCache<string, string>().Get(null);
338         }
339
340         /// <summary>
341         /// <see cref="MemoryCache&lt;TKey, TValue&gt;.Get"/>メソッドテストケース(値無し)。
342         /// </summary>
343         [Test]
344         [ExpectedException(typeof(KeyNotFoundException))]
345         public void TestGetEmpty()
346         {
347             new MemoryCache<string, string>().Get("ignore key");
348         }
349
350         /// <summary>
351         /// <see cref="MemoryCache&lt;TKey, TValue&gt;.GetAndAddIfEmpty"/>メソッドテストケース(正常系)。
352         /// </summary>
353         [Test]
354         public void TestGetAndAddIfEmpty()
355         {
356             MemoryCache<string, string> cache = new MemoryCache<string, string>();
357
358             // 値があればその値を、無ければファンクションが返す値を返す
359             cache["testkey"] = "testvalue";
360             Assert.AreEqual("testvalue", cache.GetAndAddIfEmpty("testkey", (string str) => "testvalue2"));
361             Assert.AreEqual("testvalue2", cache.GetAndAddIfEmpty("testkey2", (string str) => "testvalue2"));
362             Assert.AreEqual("testvalue2", cache.GetAndAddIfEmpty("testkey3", (string str) => "testvalue2"));
363
364             // ファンクションが返した値はキャッシュに登録される
365             Assert.AreEqual("testvalue2", cache["testkey2"]);
366             Assert.AreEqual("testvalue2", cache["testkey3"]);
367
368             // nullもキャッシュされる
369             Assert.IsNull(cache.GetAndAddIfEmpty("testkey4", (string str) => null));
370             Assert.IsTrue(cache.ContainsKey("testkey4"));
371         }
372
373         /// <summary>
374         /// <see cref="MemoryCache&lt;TKey, TValue&gt;.GetAndAddIfEmpty"/>メソッドテストケース(null)。
375         /// </summary>
376         [Test]
377         [ExpectedException(typeof(ArgumentNullException))]
378         public void TestGetAndAddIfEmptyNull()
379         {
380             new MemoryCache<string, string>().GetAndAddIfEmpty(null, (string str) => "testvalue2");
381         }
382
383         #endregion
384
385         #region 全体のテストケース
386
387         /// <summary>
388         /// 全体のテストケース(並列実行)。
389         /// </summary>
390         [Test, Timeout(1500)]
391         public void TestMemoryCacheParallel()
392         {
393             // 並列実行でいくつかのメソッドを呼んで問題ないかを確認する
394             // ※ 結果などはあまり確認できないので、とりあえず変なエラーにならないことだけ
395             MemoryCache<int, string> cache = new MemoryCache<int, string>();
396             Parallel.For(
397                 0,
398                 100000,
399                 (int i)
400                     =>
401                 {
402                     int key = i % 200;
403                     cache[key] = i.ToString();
404                     string result;
405                     if (cache.TryGetValue(key, out result))
406                     {
407                         // ※ 登録した直後でも、別スレッドからの登録でキャッシュがあふれて消えることもあるので
408                         Assert.AreEqual(key, int.Parse(result) % 200);
409                     }
410                 });
411             cache.Clear();
412         }
413
414         #endregion
415     }
416 }