/base/Windows/mkjig/mkjig.cs
C# | 395 lines | 327 code | 28 blank | 40 comment | 34 complexity | 35454a715c422d89c46543e864666dea MD5 | raw file
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Microsoft Research Singularity
- //
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //
- // Examine assembly metadata to generate test jig code.
- //
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.IO;
- using System.Runtime.InteropServices;
- using System.Text;
- using System.Xml;
-
- using Bartok.MSIL;
-
-
- internal class SuiteDesc
- {
- public readonly List<string> tests = new List<string>();
- public string init = null;
- public string cleanup = null;
- public string testInit = null;
- public string testCleanup = null;
- }
-
- internal class ModuleDesc
- {
- public readonly IDictionary<string, SuiteDesc> suites = new SortedDictionary<string, SuiteDesc>();
- public string init = null;
- public string cleanup = null;
- public SuiteDesc ProvideSuite(string className)
- {
- SuiteDesc res;
- if (!suites.TryGetValue(className, out res)) {
- res = new SuiteDesc();
- suites.Add(className, res);
- }
- return res;
- }
- public SuiteDesc ProvideSuite(MetaDataObject m, out string child)
- {
- string className;
- child = mktests.Tail(m.FullName, '.', out className);
- return ProvideSuite(className);
- }
- }
-
- public class mktests
- {
- const string ATTRIBUTE_PREFIX = "Microsoft.Singularity.UnitTest.";
-
- private string m_outpath;
- private ModuleDesc m_module;
- private IDictionary<string, MetaDataObject> m_suites = new SortedDictionary<string, MetaDataObject>();
-
- // TEMPLATE STRINGS DEFINE AT BOTTOM OF FILE
-
- private mktests(string path)
- {
- m_outpath = path;
- m_module = new ModuleDesc();
- }
-
- public static int Main(string[] args)
- {
- if (args.Length != 2) {
- Usage();
- return -1;
- }
- DateTime timeBegin = DateTime.Now;
- string outfile = args[0];
- string infile = args[1];
- ArrayList infiles = new ArrayList();
- infiles.Add(infile);
-
- mktests it = new mktests(outfile);
- it.ProcessAssembly(infiles);
- //FileStream oo = new FileStream(outfile, FileMode.Create, FileAccess.Write);
- // try {
- // }
- // finally {
- // oo.Close();
- // }
-
- TimeSpan elapsed = DateTime.Now - timeBegin;
- Console.WriteLine("mkjig: {0} seconds elapsed.", elapsed.TotalSeconds);
- return 0;
- }
-
- private static void Usage()
- {
- Console.WriteLine("Usage:\n mkjig <test_jig_source> <assembly> \n");
- }
-
- private void ProcessAssembly(ArrayList infiles)
- {
- MetaDataResolver resolver =
- new MetaDataResolver(infiles, new ArrayList(), new DateTime(), false, false);
-
- MetaDataResolver.ResolveCustomAttributes(new MetaDataResolver[] { resolver });
- foreach (MetaData md in resolver.MetaDataList) {
- // Assume that if we are processing an assembly, it will contain tests
- string name = md.Name;
- string prefix = name.Substring(0, name.LastIndexOf('.')); // trim extension
- string module = prefix.Substring(prefix.LastIndexOf('\\')+1); // extract filename
- ProcessAssembly(md);
- }
- }
-
- private void ProcessAssembly(MetaData md)
- {
- // Look for the annotation that tells us that this assembly is a stand-alone
- // test app.
- MetaDataAssembly mda = (MetaDataAssembly) md.Assemblies[0];
- foreach (MetaDataCustomAttribute attrib in md.CustomAttributes) {
- MetaDataObject parent = attrib.Parent;
- //Console.WriteLine("Found: {0} in {1} {2}", attrib.Name, parent.FullName, parent.FullNameWithContext);
- if (!attrib.Name.StartsWith(ATTRIBUTE_PREFIX)) {
- continue;
- }
- Console.WriteLine("Found: {0} in {1} {2}", attrib.Name, parent.FullName, parent.FullNameWithContext);
- string attribName = attrib.Name.Substring(ATTRIBUTE_PREFIX.Length);
- string className;
- string item = Tail(attrib.Parent, out className);
- if (attribName == "TestClassAttribute") {
- m_suites.Add(attrib.Parent.FullName, attrib);
- }
- else if (attribName == "TestMethodAttribute") {
- m_module.ProvideSuite(className).tests.Add(item);
- }
- else if (attribName == "ClassInitializeAttribute") {
- m_module.ProvideSuite(className).init = item;
- }
- else if (attribName == "ClassCleanupAttribute") {
- m_module.ProvideSuite(className).cleanup = item;
- }
- else if (attribName == "TestInitializeAttribute") {
- m_module.ProvideSuite(className).testInit = item;
- }
- else if (attribName == "TestCleanupAttribute") {
- m_module.ProvideSuite(className).testCleanup = item;
- }
- else if (attribName == "AssemblyInitializeAttribute") {
- m_module.init = item;
- }
- else if (attribName == "TestCleanupAttribute") {
- m_module.cleanup = item;
- }
- else {
- // IGNORE
- }
- }
- StringBuilder suiteStr = new StringBuilder();
- StringBuilder jigsStr = new StringBuilder();
- foreach (KeyValuePair<string, SuiteDesc> kvp in m_module.suites) {
- string fullname = kvp.Key;
- if (!m_suites.ContainsKey(fullname)) {
- Console.WriteLine("TestMethod declared outside of a TestClass: {0}", fullname);
- continue;
- }
- string pkg;
- string className = Tail(fullname, '.', out pkg);
- SuiteDesc desc = kvp.Value;
- GenTests(className, pkg, desc, suiteStr);
- jigsStr.AppendFormat(SUITE_CASE_TEMPLATE, className, pkg);
- }
- string modulename = "Foo";
- StringBuilder otherStr = new StringBuilder();
- //AppendOpt(MODULE_INIT_TEMPLATE, m_module.init, otherStr);
- //AppendOpt(MODULE_INIT_TEMPLATE, m_module.cleanup, otherStr);
- string content = string.Format(FILE_TEMPLATE, modulename, jigsStr, otherStr, suiteStr);
- File.WriteAllText(m_outpath, content);
- }
-
- private void GenTests(string className, string pkg, SuiteDesc desc, StringBuilder suiteStr)
- {
- StringBuilder caseStr = new StringBuilder();
- desc.tests.Sort();
- foreach (string t in desc.tests) {
- caseStr.AppendFormat(TEST_CASE_TEMPLATE, t);
- }
- StringBuilder otherStr = new StringBuilder();
- AppendOpt(INIT_TEMPLATE, desc.init, otherStr);
- AppendOpt(CLEANUP_TEMPLATE, desc.cleanup, otherStr);
- // TODO test init
- suiteStr.AppendFormat(SUITE_TEMPLATE, className, pkg, caseStr, otherStr);
- }
-
- private static void AppendOpt(string format, string optS, StringBuilder otherStr)
- {
- if (optS != null) {
- otherStr.AppendFormat(format, optS);
- }
- }
-
- // Split a string at the last occcurence of a character, returning both
- // the before and after. If the character is not present, then the tail
- // is empty and before is the entire string.
- public static string Tail(string it, char pattern, out string before)
- {
- int i = it.LastIndexOf(pattern);
- if (i < 0) {
- before = it;
- return "";
- }
- else {
- before = it.Substring(0, i);
- return it.Substring(i + 1);
- }
- }
-
- public static string Tail(MetaDataObject m, out string before)
- {
- return Tail(m.FullName, '.', out before);
- }
-
- //Assert(m != null, "TestMethod attribute is on a method");
- // oo.WriteStartElement("Suite");
- // oo.WriteAttributeString("Name", );
- // inSuite = true;
- // object timeout = psItem.Fields["Test Timeout"].Value;
- // if (timeout != null) {
- // oo.WriteAttributeString("Timeout", timeout.ToString());
- // }
- // object knownFailure = psItem.Fields["Test Known Failure"].Value;
- // if (knownFailure != null) {
- // oo.WriteAttributeString("KnownFailure", knownFailure.ToString());
- // }
- private static void Assert(bool cond, string trueText)
- {
- if (!cond) {
- throw new Exception("Expected: " + trueText);
- }
- }
-
- private const string TEST_INIT_TEMPLATE = @"
- override public void TestInitialize()
- {{
- m_test.{0}();
- }}
- ";
-
- private const string TEST_CLEANUP_TEMPLATE = @"
- override public void TestCleanup()
- {{
- m_test.{0}();
- }}
- ";
-
- private const string INIT_TEMPLATE = @"
- override public void Initialize()
- {{
- m_test.{0}();
- }}
- ";
-
- private const string CLEANUP_TEMPLATE = @"
- override public void Cleanup()
- {{
- m_test.{0}();
- }}
- ";
-
- private const string TEST_CASE_TEMPLATE = @"
- case ""{0}"":
- m_test.{0}();
- break;
- ";
-
- private const string SUITE_CASE_TEMPLATE = @"
- case ""{0}"":
- return new {1}.{0}_Jig(log);
- ";
-
- // suite name, suite namespace, suite cases, suite other
- private const string SUITE_TEMPLATE = @"
- namespace {1} {{
- internal class {0}_Jig : SuiteJig
- {{
- private {0}! m_test;
-
- public {0}_Jig(TestLog! log)
- {{
- {0} t = new {0}();
- t.SetLog(log);
- m_test = t;
- }}
-
- override public void DoTest(string! test)
- {{
- switch (test) {{
- {2}
- default:
- base.DoTest(test);
- break;
- }}
- }}
- {3}
- }}
- }}
- ";
-
- // module name, module cases, module other, suite jigs
- private const string FILE_TEMPLATE = @"
- ///////////////////////////////////////////////////////////////////////////////
- //
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //
- // Generated test jig code
-
- using System;
- using System.Threading;
-
- using Microsoft.Singularity.UnitTest;
-
- using Microsoft.Singularity.Channels;
- using Microsoft.Contracts;
- using Microsoft.SingSharp.Reflection;
- using Microsoft.Singularity.Applications;
- using Microsoft.Singularity.Io;
- using Microsoft.Singularity.Configuration;
- using Microsoft.Singularity.Test.Contracts;
- using Microsoft.Singularity.Configuration;
-
- [assembly: Transform(typeof(ApplicationResourceTransform))]
-
- // GENERATED SUITE JIGS
- {3}
-
- namespace Microsoft.Singularity.Applications {{
-
- // GENERATED MODULE JIG
- public class {0}_ModuleJig : ModuleJig
- {{
- override public SuiteJig GetSuite(string! name, TestLog! log)
- {{
- switch (name) {{
- {1}
- default:
- return base.GetSuite(name, log);
- }}
- }}
- {2}
- }}
-
- [ConsoleCategory(HelpMessage=""ModuleTester"", Action=""test"")]
- internal class ModuleTest_Category {{
- [InputEndpoint(""data"")]
- public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
- [OutputEndpoint(""data"")]
- public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
-
- [CustomEndpoint]
- public readonly TRef<ModuleTesterContract.Exp:START> testerRef;
-
- reflective internal ModuleTest_Category();
-
- internal int AppMain() {{
- if (testerRef == null) {{
- DebugStub.WriteLine(""TEST endpoint not setup"");
- throw new Exception(""TEST endpoint not setup "");
- }}
- ModuleTesterContract.Exp tester = testerRef.Acquire();
- if (tester == null) {{
- DebugStub.WriteLine(""TEST unable to acquite handle to test driver"");
- throw new Exception(""Unable to acquire handle to the test driver"");
- }}
- ModuleJig jig = new {0}_ModuleJig();
- ModuleTester.RunTests(tester, jig);
- return 0;
- }}
- }}
-
- // Currently required to get process launch code generated.
- [ConsoleCategory(HelpMessage=""Run using the test framework"", DefaultAction=true)]
- internal class ModuleConsole_Category {{
- [InputEndpoint(""data"")]
- public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
- [OutputEndpoint(""data"")]
- public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
-
- reflective internal ModuleConsole_Category();
-
- internal int AppMain() {{
- Console.WriteLine(""This is a test application and can only be run from the tester."");
- return -1;
- }}
- }}
- }}
- ";
- }