Commits

Jordan Earls committed a39e8d1

Finally added in unit tests for the generated code. Now just need to test the code generator more

Comments (0)

Files changed (10)

CacheGen.Tests/CacheGen.Tests.csproj

   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
     <Compile Include="CacheGenTests.cs" />
+    <Compile Include="CacheGenTestT4.cs">
+      <DependentUpon>CacheGenTestT4.tt</DependentUpon>
+    </Compile>
+    <Compile Include="GeneratedCodeTests.cs" />
+    <Compile Include="MockCacheMechanism.cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\CacheGen\CacheGen.csproj">
       <Name>CacheGen</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="CacheGenTestT4.tt">
+      <Generator>TextTemplatingFileGenerator</Generator>
+      <LastGenOutput>CacheGenTestT4.cs</LastGenOutput>
+    </None>
+  </ItemGroup>
 </Project>

CacheGen.Tests/CacheGenTestT4.cs

+
+//built in `usings`
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Earlz.CacheGen;
+using Earlz.CacheGen.Tests;
+
+//Add custom `using namespace` statements here
+//using MyProgram.Foo.Bar;
+
+namespace Earlz.CacheGen.Tests{
+        ///<summary>
+        ///
+        ///</summary>
+     class TestCache: BaseCacheClass
+    {
+                ///<summary>
+        ///
+        ///</summary>
+            static public string Testfoo{
+        get{ return ((string) __Cacher.Get("__cachegen__TestCache__Testfoo"));}
+        set{  __Cacher.Set("__cachegen__TestCache__Testfoo", value, __cacher_Testfoo);}
+        }
+
+                ///<summary>
+        ///
+        ///</summary>
+            static public CacheDictionary<int, string> testdictionary{
+        get;
+        private set;
+        }
+
+        static  TestCache()
+        {
+__cacher_Testfoo=new CacheObject{
+			Name="Testfoo",
+			AbsoluteExpirationFromNow=null,
+			SlidingExpiration=null,
+			Priority=CachePriority.Default
+			};
+
+		testdictionary=new CacheDictionary<int, string>(
+			"__cachegen__TestCache__testdictionary", //basekey
+			__cacher_testdictionary, //CacheObject
+			((k, v, i) => __Cacher.Set(k, v, i)), //pass through set
+			((k) => __Cacher.Get(k)) //pass through get
+			);
+__cacher_testdictionary=new CacheObject{
+			Name="testdictionary",
+			AbsoluteExpirationFromNow=null,
+			SlidingExpiration=null,
+			Priority=CachePriority.Default
+			};
+
+        }
+                ///<summary>
+        ///
+        ///</summary>
+        internal static CacheMechanism __Cacher=new MockCacheMechanism();
+                ///<summary>
+        ///
+        ///</summary>
+        static CacheObject __cacher_Testfoo=null;
+                ///<summary>
+        ///
+        ///</summary>
+        static CacheObject __cacher_testdictionary=null;
+
+    }
+}
+//

CacheGen.Tests/CacheGenTestT4.tt

+<#@ template language="C#" #>
+<#@ output extension="cs" #>
+<#@ assembly name="System.Core" #>
+<#@ import namespace="System.IO" #>
+<#@ import namespace="System.Text" #>
+<#@ import namespace="System.Collections.Generic" #>
+<#@ import namespace="System" #>
+<#@ import namespace="System.Linq" #>
+
+<#
+/*
+Copyright (c) 2012 Jordan "Earlz" Earls  <http://earlz.net>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+   
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#>
+//built in `usings`
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Earlz.CacheGen;
+using Earlz.CacheGen.Tests;
+
+//Add custom `using namespace` statements here
+//using MyProgram.Foo.Bar;
+
+<#
+//begin configuration
+
+
+
+//end configuration
+//do not touch anything below this line
+
+var gen=new CacheGenerator("TestCache", "new MockCacheMechanism()");
+gen.Namespace="Earlz.CacheGen.Tests";
+gen.AddItem(new CacheObject{Name="Testfoo", Type="string"});
+gen.AddItem(new CacheObject{Name="testdictionary", KeyType="int", ValueType="string"});
+Write(gen.ToString());
+
+
+#>
+<#@ include file="../CacheGen/CacheGenInternal.tt.cs" #>

CacheGen.Tests/CacheGenTests.cs

 
 namespace Earlz.CacheGen.Tests
 {
+	/// <summary>
+	/// These will test that the code generator doesn't throw exceptions or output clearly incorrect code
+	/// </summary>
 	[TestFixture]
 	public class CacheGenTests
 	{

CacheGen.Tests/GeneratedCodeTests.cs

+using System;
+using NUnit.Framework;
+using System.Linq;
+
+namespace Earlz.CacheGen.Tests
+{
+	/// <summary>
+	/// This will test that the generated code behaves properly when messing with a mock cache
+	/// </summary>
+	[TestFixture]
+	public class GeneratedCodeTests
+	{
+		MockCacheMechanism Cacher;
+		[TestFixtureSetUp]
+		public void Setup()
+		{
+			Cacher=(MockCacheMechanism)TestCache.__Cacher;
+		}
+		[TestFixtureTearDown]
+		public void Teardown()
+		{
+			Cacher.Reset();
+		}
+
+		[Test]
+		public void BasicOperations()
+		{
+			//these look really retarded, but remember that the methods behind these properties are what we're testing
+			//test initial add
+			TestCache.Testfoo="Foo";
+			Assert.AreEqual("Foo", TestCache.Testfoo);
+			//test that clearing the cache doesn't cause any exceptions
+			Cacher.Reset();
+			Assert.AreEqual(null, TestCache.Testfoo);
+			//test replacement
+			TestCache.Testfoo="meh";
+			Assert.AreEqual("meh", TestCache.Testfoo);
+			TestCache.Testfoo="biz";
+			Assert.AreEqual("biz", TestCache.Testfoo);
+		}
+		[Test]
+		public void DictionaryOperations()
+		{
+			TestCache.testdictionary[0]="foo";
+			TestCache.testdictionary[1]="bar";
+			Assert.AreEqual(TestCache.testdictionary[0], "foo");
+			Assert.AreEqual(TestCache.testdictionary[1], "bar");
+			Assert.AreEqual(2, TestCache.testdictionary.TrackedCount);
+
+			Cacher.Reset();
+			Assert.AreEqual(2, TestCache.testdictionary.TrackedCount);
+			Assert.AreEqual(TestCache.testdictionary[0], null);
+			Assert.AreEqual(TestCache.testdictionary[1], null);
+			Assert.AreEqual(0, TestCache.testdictionary.TrackedCount); //ensure keys are removed after we know they don't exist
+
+			TestCache.testdictionary[0]="foo";
+			TestCache.testdictionary[0]="meh";
+			Assert.AreEqual(1, TestCache.testdictionary.TrackedCount); //ensure no duplicate keys for the same object
+			Assert.AreEqual(TestCache.testdictionary[0], "meh");
+			Assert.AreEqual(TestCache.testdictionary.Remove(0), "meh");
+			Assert.AreEqual(0, TestCache.testdictionary.TrackedCount); //ensure keys removed after Remove()
+			Assert.AreEqual(TestCache.testdictionary[0], null);
+			TestCache.testdictionary[0]="biz";
+			TestCache.testdictionary[10]="baz";
+			Assert.AreEqual(TestCache.testdictionary[2], null);
+			TestCache.testdictionary.Clear();
+			Assert.AreEqual(0, TestCache.testdictionary.TrackedCount); //ensure empty after clearing
+			Assert.AreEqual(Cacher.Cache.Count, 0);
+
+		}
+
+
+	}
+}
+

CacheGen.Tests/MockCacheMechanism.cs

+using System;
+using System.Collections.Generic;
+using System.Collections.Concurrent;
+
+namespace Earlz.CacheGen.Tests
+{
+	public class MockCacheMechanism : CacheMechanism
+	{
+		//make it concurrent so we can eventually test concurrency
+		public ConcurrentDictionary<string, object> Cache=new ConcurrentDictionary<string, object>();
+		public ConcurrentDictionary<string, CacheObject> CacheInfo=new ConcurrentDictionary<string, CacheObject>();
+		public override object Get (string key)
+		{
+			object tmp=null;
+			Cache.TryGetValue(key, out tmp);
+			return tmp;
+		}
+		public override object Set (string key, object obj, CacheObject info)
+		{
+			if(obj==null)
+			{
+				CacheObject trash=null;
+				Cache.TryRemove(key, out obj);
+				CacheInfo.TryRemove(key, out trash); 
+				return obj;
+			}
+
+			CacheInfo[key]=info;
+			return Cache[key]=obj;
+		}
+		public void Reset()
+		{
+			Cache.Clear();
+			CacheInfo.Clear();
+		}
+	}
+}
+

CacheGen/CacheDictionary.cs

 		readonly CacheObject Info;
 		StoreToCache StoreTo;
 		GetFromCache GetFrom;
+		/// <summary>
+		/// This returns the amount of keys we are tracking within this CacheDictionary.
+		/// Note: This does not necessarily indicate how many items are actually still in the cache! 
+		/// </summary>
+		/// <returns>
+		/// The count.
+		/// </returns>
+		public int TrackedCount
+		{
+			get
+			{
+				return RealKeys.Count;
+			}
+		}
 		public CacheDictionary(string basekey, CacheObject info, StoreToCache store, GetFromCache get)
 		{
 			BaseKey=basekey;
 			GetFrom=get;
 		}
 
-
-		public int Count
-		{
-			get
-			{
-				return RealKeys.Count;
-			}
-		}
 		void Add (K key, V value)
 		{
 			string realkey=RealKeys.GetOrAdd(key, (s) => AddKey(key));
 				}
 				else
 				{
+					string trash=null;
+					RealKeys.TryRemove(key, out trash); //cleanup
 					return default(V);
 				}
 			}

CacheGen/CacheGen.cs

         set{  __Cacher.Set("__cachegen__TestCache__Testfoo", value, __cacher_Testfoo);}
         }
 
+                ///<summary>
+        ///
+        ///</summary>
+            static public CacheDictionary<string, int?> testdictionary{
+        get;
+        private set;
+        }
+
         static  TestCache()
         {
 __cacher_Testfoo=new CacheObject{
 			Name="Testfoo",
 			AbsoluteExpirationFromNow=null,
 			SlidingExpiration=null,
-			Priority=(CachePriority)Enum.Parse(typeof(CachePriority), "Default")
+			Priority=CachePriority.Default
+			};
+
+		testdictionary=new CacheDictionary<string, int?>(
+			"__cachegen__TestCache__testdictionary", //basekey
+			__cacher_testdictionary, //CacheObject
+			((k, v, i) => __Cacher.Set(k, v, i)), //pass through set
+			((k) => __Cacher.Get(k)) //pass through get
+			);
+__cacher_testdictionary=new CacheObject{
+			Name="testdictionary",
+			AbsoluteExpirationFromNow=null,
+			SlidingExpiration=null,
+			Priority=CachePriority.Default
 			};
 
         }
         ///
         ///</summary>
         static CacheObject __cacher_Testfoo=null;
+                ///<summary>
+        ///
+        ///</summary>
+        static CacheObject __cacher_testdictionary=null;
 
     }
 }

CacheGen/CacheGen.tt

 var gen=new CacheGenerator("TestCache", "new ASPCacheMechanism()");
 gen.Namespace="Earlz.Testing";
 gen.AddItem(new CacheObject{Name="Testfoo", Type="string"});
+gen.AddItem(new CacheObject{Name="testdictionary", KeyType="string", ValueType="int?"});
 Write(gen.ToString());
 
 

CacheGen/CacheGenInternal.tt.cs

 		void AddInitialThings()
 		{
 			Fields.Add(new Field{
-				Accessibility="static",
+				Accessibility="internal static",
 				Type="CacheMechanism",
 				InitialValue=CacheMechanism,
 				Name="__Cacher"
 			{3}, //CacheObject
 			((k, v, i) => __Cacher.Set(k, v, i)), //pass through set
 			((k) => __Cacher.Get(k)) //pass through get
-			);", c.Name, type, "tmp", GetCacheObjectName(p.Name)));
+			);", c.Name, type, GetUniqueKey(p.Name), GetCacheObjectName(p.Name)));
 			}
 			Properties.Add(p);
 
 			Name=""{1}"",
 			AbsoluteExpirationFromNow={2},
 			SlidingExpiration={3},
-			Priority=(CachePriority)Enum.Parse(typeof(CachePriority), ""{4}"")
+			Priority=CachePriority.{4}
 			}};",
 				GetCacheObjectName(p.Name),
 				c.Name,