public void StringCacheEnforcesSizeLimit() { // Test correct normal behavior with large limit StringCache cache = new StringCache(2000000, 10); cache.Add(key2, value2); Assert.AreEqual(value2, cache.Get(key2)); // Edge case: cache size limit is exactly the calculated size of the cached item (requires knowledge of the implementation details of the cache). // In this case, we are using a reference type for key and value, which means 3 references will be counted. // We also have one reference for the CacheItem used to wrap around the Value, and 8 bytes for the DateTime used to calculate its age. int overhead = (ObjectSize.ReferenceSize * 4) + 8; int requiredSize = overhead + (int)ObjectSize.SizeOf(key2) + (int)ObjectSize.SizeOf(value2); cache = new StringCache(requiredSize, 10); cache.Add(key2, value2); Assert.AreEqual(value2, cache.Get(key2)); // Edge case: cache size limit one byte smaller than required cache = new StringCache(requiredSize - 1, 10); cache.Add(key2, value2); Assert.IsNull(cache.Get(key2)); // Value should fail to load from the cache, because it should have been removed for being over the limit. cache.Add(key0, value0); // Adding a shorter value should work Assert.AreEqual(value0, cache.Get(key0)); cache.Add(key0, value0); // Adding the same key again with the same value should change nothing Assert.AreEqual(value0, cache.Get(key0)); cache.Add(key0, value1); // Adding the same key again with a DIFFERENT but equal length value should work Assert.AreEqual(value1, cache.Get(key0)); cache.Add(key2, value2); // Adding the oversized value again should cause the cache to be empty. Assert.IsNull(cache.Get(key0)); // Value should fail to load from the cache, because it should have been removed for being over the limit. Assert.IsNull(cache.Get(key2)); // Value should fail to load from the cache, because it should have been removed for being over the limit. }
public void TestObjectSizeExhaustive() { // Strings // strings have an overhead of 4 bytes for the m_stringLength field and 2 bytes for the m_firstChar field. Assert.AreEqual(14, ObjectSize.SizeOf("test")); Assert.AreEqual(16, ObjectSize.SizeOf("tests")); // Primitive Types Assert.AreEqual(1, ObjectSize.SizeOf(false)); Assert.AreEqual(1, ObjectSize.SizeOf(true)); Assert.AreEqual(1, ObjectSize.SizeOf(byte.MaxValue)); Assert.AreEqual(1, ObjectSize.SizeOf(sbyte.MaxValue)); Assert.AreEqual(2, ObjectSize.SizeOf(ushort.MaxValue)); Assert.AreEqual(2, ObjectSize.SizeOf(short.MaxValue)); Assert.AreEqual(4, ObjectSize.SizeOf(uint.MaxValue)); Assert.AreEqual(4, ObjectSize.SizeOf(int.MaxValue)); Assert.AreEqual(8, ObjectSize.SizeOf(ulong.MaxValue)); Assert.AreEqual(8, ObjectSize.SizeOf(long.MaxValue)); Assert.AreEqual(2, ObjectSize.SizeOf(char.MaxValue)); Assert.AreEqual(4, ObjectSize.SizeOf(float.MaxValue)); Assert.AreEqual(8, ObjectSize.SizeOf(double.MaxValue)); Assert.AreEqual(16, ObjectSize.SizeOf(decimal.MaxValue)); Assert.AreEqual(8, ObjectSize.SizeOf(DateTime.MinValue)); Assert.AreEqual(ObjectSize.ReferenceSize, ObjectSize.SizeOf(UIntPtr.Zero)); Assert.AreEqual(ObjectSize.ReferenceSize, ObjectSize.SizeOf(IntPtr.Zero)); // Arrays of primitive types Assert.AreEqual(30, ObjectSize.SizeOf(new bool[30])); Assert.AreEqual(30, ObjectSize.SizeOf(new byte[30])); Assert.AreEqual(60, ObjectSize.SizeOf(new char[30])); Assert.AreEqual(60, ObjectSize.SizeOf(new short[30])); Assert.AreEqual(120, ObjectSize.SizeOf(new int[30])); Assert.AreEqual(240, ObjectSize.SizeOf(new long[30])); Assert.AreEqual(480, ObjectSize.SizeOf(new decimal[30])); Assert.AreEqual(0, ObjectSize.SizeOf(new decimal[0])); // Array of string string[] strArr = new string[] { "test", "tests" }; int strArrExpectedSize = 30 + (ObjectSize.ReferenceSize * 2); Assert.AreEqual(strArrExpectedSize, ObjectSize.SizeOf(strArr)); // Array of objects object[] objArr = new object[] { /* 14 */ "test", /* 1 */ byte.MinValue, /* 1 */ false, /* 8 */ long.MinValue }; int objArrExpectedSize = 14 + 1 + 1 + 8 + (ObjectSize.ReferenceSize * 4); Assert.AreEqual(objArrExpectedSize, ObjectSize.SizeOf(objArr)); // Generic Lists int list_overhead = 0; list_overhead += ObjectSize.ReferenceSize; // Reference to internal array list_overhead += 4; // (int) size list_overhead += 4; // (int) _version list_overhead += ObjectSize.ReferenceSize; // Reference to internal syncroot object (which will be null) List <byte> list_byte = new List <byte>(3); Assert.AreEqual(list_overhead + 3, ObjectSize.SizeOf(list_byte)); List <string> list_string = new List <string>(strArr); Assert.AreEqual(list_overhead + strArrExpectedSize, ObjectSize.SizeOf(list_string)); List <object> list_object = new List <object>(objArr); Assert.AreEqual(list_overhead + objArrExpectedSize, ObjectSize.SizeOf(list_object)); List <object> list_object_nulls = new List <object>(3); Assert.AreEqual(list_overhead + (ObjectSize.ReferenceSize * 3), ObjectSize.SizeOf(list_object_nulls)); // Complex objects object dyn = new { f1 = "tests", f2 = false, f3 = new { f1 = (int)234190, f2 = float.MinValue } }; // Expected: ((ref size) + 16 + 1 + (ref size) + 4 + 4) = 24 + (ref size) + (ref size) Assert.AreEqual(25 + (ObjectSize.ReferenceSize * 2), ObjectSize.SizeOf(dyn)); // Expected: ((ref size) + 16 + 1 + (ref size) + 4 + 4 + 4 + 4 + 4) = 36 + (ref size) + (ref size) Assert.AreEqual(37 + (ObjectSize.ReferenceSize * 2), ObjectSize.SizeOf(new InternalClass1())); }