Click here to Skip to main content
15,878,959 members
Articles / Programming Languages / C#

CodeDom Assistant

Rate me:
Please Sign up or sign in to vote.
4.84/5 (26 votes)
21 Sep 20074 min read 137.2K   6.6K   82  
Generating CodeDom Code By Parsing C# or VB
// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
//     <version>$Revision: 2522 $</version>
// </file>

using System;
using System.IO;
using NUnit.Framework;
using ICSharpCode.NRefactory.Parser;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.PrettyPrinter;

namespace ICSharpCode.NRefactory.Tests.PrettyPrinter
{
	[TestFixture]
	public class CSharpOutputTest
	{
		void TestProgram(string program)
		{
			IParser parser = ParserFactory.CreateParser(SupportedLanguage.CSharp, new StringReader(program));
			parser.Parse();
			Assert.AreEqual("", parser.Errors.ErrorOutput);
			CSharpOutputVisitor outputVisitor = new CSharpOutputVisitor();
			outputVisitor.VisitCompilationUnit(parser.CompilationUnit, null);
			Assert.AreEqual("", outputVisitor.Errors.ErrorOutput);
			Assert.AreEqual(StripWhitespace(program), StripWhitespace(outputVisitor.Text));
		}
		
		internal static string StripWhitespace(string text)
		{
			return text.Trim().Replace("\t", "").Replace("\r", "").Replace("\n", " ").Replace("  ", " ");
		}
		
		void TestTypeMember(string program)
		{
			TestProgram("class A { " + program + " }");
		}
		
		void TestStatement(string statement)
		{
			TestTypeMember("void Method() { " + statement + " }");
		}
		
		void TestExpression(string expression)
		{
			// SEMICOLON HACK : without a trailing semicolon, parsing expressions does not work correctly
			IParser parser = ParserFactory.CreateParser(SupportedLanguage.CSharp, new StringReader(expression + ";"));
			Expression e = parser.ParseExpression();
			Assert.AreEqual("", parser.Errors.ErrorOutput);
			CSharpOutputVisitor outputVisitor = new CSharpOutputVisitor();
			e.AcceptVisitor(outputVisitor, null);
			Assert.AreEqual("", outputVisitor.Errors.ErrorOutput);
			Assert.AreEqual(StripWhitespace(expression), StripWhitespace(outputVisitor.Text));
		}
		
		[Test]
		public void Namespace()
		{
			TestProgram("namespace System { }");
		}
		
		[Test]
		public void CustomEvent()
		{
			TestTypeMember("public event EventHandler Click {" +
			               " add { obj.Click += value; }" +
			               " remove { obj.Click -= value; } " +
			               "}");
		}
		
		[Test]
		public void EventWithInitializer()
		{
			TestTypeMember("public event EventHandler Click = delegate { };");
		}
		
		[Test]
		public void Field()
		{
			TestTypeMember("int a;");
		}
		
		[Test]
		public void Method()
		{
			TestTypeMember("void Method() { }");
		}
		
		[Test]
		public void PartialModifier()
		{
			TestProgram("public partial class Foo { }");
		}
		
		[Test]
		public void GenericClassDefinition()
		{
			TestProgram("public class Foo<T> where T : IDisposable, ICloneable { }");
		}
		
		[Test]
		public void GenericClassDefinitionWithBaseType()
		{
			TestProgram("public class Foo<T> : BaseClass where T : IDisposable, ICloneable { }");
		}
		
		[Test]
		public void GenericMethodDefinition()
		{
			TestTypeMember("public void Foo<T>(T arg) where T : IDisposable, ICloneable { }");
		}
		
		[Test]
		public void ArrayRank()
		{
			TestStatement("object[,,] a = new object[1, 2, 3];");
		}
		
		[Test]
		public void JaggedArrayRank()
		{
			TestStatement("object[,][,,] a = new object[1, 2][,,];");
		}
		
		[Test]
		public void ArrayInitializer()
		{
			TestStatement("object[] a = new object[] {1, 2, 3};");
		}
		
		[Test]
		public void IfStatement()
		{
			TestStatement("if (a) { m1(); } else { m2(); }");
			
			TestStatement("if (a) m1(); else m2(); ");
			
			TestStatement("if (a) {\n" +
			              "\tm1();\n" +
			              "} else if (b) {\n" +
			              "\tm2();\n" +
			              "} else {\n" +
			              "\tm3();\n" +
			              "}");
		}
		
		[Test]
		public void Assignment()
		{
			TestExpression("a = b");
		}
		
		[Test]
		public void UnaryOperator()
		{
			TestExpression("a = -b");
		}
		
		[Test]
		public void BlockStatements()
		{
			TestStatement("checked { }");
			TestStatement("unchecked { }");
			TestStatement("unsafe { }");
		}
		
		[Test]
		public void ExceptionHandling()
		{
			TestStatement("try { throw new Exception(); } " +
			              "catch (FirstException e) { } " +
			              "catch (SecondException) { } " +
			              "catch { throw; } " +
			              "finally { }");
		}
		
		[Test]
		public void LoopStatements()
		{
			TestStatement("foreach (Type var in col) { }");
			TestStatement("while (true) { }");
			TestStatement("do { } while (true);");
		}
		
		[Test]
		public void SizeOf()
		{
			TestExpression("sizeof(IntPtr)");
		}
		
		[Test]
		public void ParenthesizedExpression()
		{
			TestExpression("(a)");
		}
		
		[Test]
		public void MethodOnGenericClass()
		{
			TestExpression("Container<string>.CreateInstance()");
		}
		
		[Test]
		public void EmptyStatement()
		{
			TestStatement(";");
		}
		
		[Test]
		public void Yield()
		{
			TestStatement("yield break;");
			TestStatement("yield return null;");
		}
		
		[Test]
		public void Integer()
		{
			TestExpression("12");
		}
		
		[Test]
		public void LongInteger()
		{
			TestExpression("12l");
		}
		
		[Test]
		public void LongUnsignedInteger()
		{
			TestExpression("12ul");
		}
		
		[Test]
		public void UnsignedInteger()
		{
			TestExpression("12u");
		}
		
		[Test]
		public void Double()
		{
			TestExpression("12.5");
			TestExpression("12.0");
		}
		
		[Test]
		public void GenericMethodInvocation()
		{
			TestExpression("GenericMethod<T>(arg)");
		}
		
		[Test]
		public void Cast()
		{
			TestExpression("(T)a");
		}
		
		[Test]
		public void AsCast()
		{
			TestExpression("a as T");
		}
		
		[Test]
		public void NullCoalescing()
		{
			TestExpression("a ?? b");
		}
		
		[Test]
		public void SpecialIdentifierName()
		{
			TestExpression("@class");
		}
		
		[Test]
		public void InnerClassTypeReference()
		{
			TestExpression("typeof(List<string>.Enumerator)");
		}
		
		[Test]
		public void GenericDelegate()
		{
			TestProgram("public delegate void Predicate<T>(T item) where T : IDisposable, ICloneable;");
		}
		
		[Test]
		public void Enum()
		{
			TestProgram("enum MyTest { Red, Green, Blue, Yellow }");
		}
		
		[Test]
		public void EnumWithInitializers()
		{
			TestProgram("enum MyTest { Red = 1, Green = 2, Blue = 4, Yellow = 8 }");
		}
		
		[Test]
		public void SyncLock()
		{
			TestStatement("lock (a) { Work(); }");
		}
		
		[Test]
		public void Using()
		{
			TestStatement("using (A a = new A()) { a.Work(); }");
		}
		
		[Test]
		public void AbstractProperty()
		{
			TestTypeMember("public abstract bool ExpectsValue { get; set; }");
			TestTypeMember("public abstract bool ExpectsValue { get; }");
			TestTypeMember("public abstract bool ExpectsValue { set; }");
		}
		
		[Test]
		public void SetOnlyProperty()
		{
			TestTypeMember("public bool ExpectsValue { set { DoSomething(value); } }");
		}
		
		[Test]
		public void AbstractMethod()
		{
			TestTypeMember("public abstract void Run();");
			TestTypeMember("public abstract bool Run();");
		}
		
		[Test]
		public void AnonymousMethod()
		{
			TestStatement("Func b = delegate { return true; };");
			TestStatement("Func a = delegate() { return false; };");
		}
		
		[Test]
		public void Interface()
		{
			TestProgram("interface ITest {" +
			            " bool GetterAndSetter { get; set; }" +
			            " bool GetterOnly { get; }" +
			            " bool SetterOnly { set; }" +
			            " void InterfaceMethod();" +
			            " string InterfaceMethod2();\n" +
			            "}");
		}
		
		[Test]
		public void IndexerDeclaration()
		{
			TestTypeMember("public string this[int index] { get { return index.ToString(); } set { } }");
			TestTypeMember("public string IList.this[int index] { get { return index.ToString(); } set { } }");
		}
		
		[Test]
		public void OverloadedConversionOperators()
		{
			TestTypeMember("public static explicit operator TheBug(XmlNode xmlNode) { }");
			TestTypeMember("public static implicit operator XmlNode(TheBug bugNode) { }");
		}
		
		[Test]
		public void OverloadedTrueFalseOperators()
		{
			TestTypeMember("public static bool operator true(TheBug bugNode) { }");
			TestTypeMember("public static bool operator false(TheBug bugNode) { }");
		}
		
		[Test]
		public void OverloadedOperators()
		{
			TestTypeMember("public static TheBug operator +(TheBug bugNode, TheBug bugNode2) { }");
			TestTypeMember("public static TheBug operator >>(TheBug bugNode, int b) { }");
		}
		
		[Test]
		public void PropertyWithAccessorAccessModifiers()
		{
			TestTypeMember("public bool ExpectsValue {\n" +
			               "\tinternal get {\n" +
			               "\t}\n" +
			               "\tprotected set {\n" +
			               "\t}\n" +
			               "}");
		}
		
		[Test]
		public void UsingStatementForExistingVariable()
		{
			TestStatement("using (obj) {\n}");
		}
		
		[Test]
		public void NewConstraint()
		{
			TestProgram("public struct Rational<T, O> where O : IRationalMath<T>, new()\n{\n}");
		}
		
		[Test]
		public void StructConstraint()
		{
			TestProgram("public struct Rational<T, O> where O : struct\n{\n}");
		}
		
		[Test]
		public void ClassConstraint()
		{
			TestProgram("public struct Rational<T, O> where O : class\n{\n}");
		}
		
		[Test]
		public void FixedStructField()
		{
			TestProgram(@"unsafe struct CrudeMessage
{
	public fixed byte data[256];
}");
		}
		
		[Test]
		public void FixedStructField2()
		{
			TestProgram(@"unsafe struct CrudeMessage
{
	fixed byte data[4 * sizeof(int)], data2[10];
}");
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions