diff --git a/src/AddIns/Analysis/MachineSpecifications/MachineSpecifications/MachineSpecifications.addin b/src/AddIns/Analysis/MachineSpecifications/MachineSpecifications/MachineSpecifications.addin index 718cd3096d..e552dd08d1 100644 --- a/src/AddIns/Analysis/MachineSpecifications/MachineSpecifications/MachineSpecifications.addin +++ b/src/AddIns/Analysis/MachineSpecifications/MachineSpecifications/MachineSpecifications.addin @@ -4,6 +4,10 @@ description = "Runner for Machine.Specifications unit tests for SharpDevelop" addInManagerHidden = "preinstalled"> + + + + diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/AspNet.Mvc.sln b/src/AddIns/BackendBindings/AspNet.Mvc/AspNet.Mvc.sln index 26144ff509..1aa05f4665 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/AspNet.Mvc.sln +++ b/src/AddIns/BackendBindings/AspNet.Mvc/AspNet.Mvc.sln @@ -44,10 +44,10 @@ Global {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Debug|x86.ActiveCfg = Debug|x86 {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Release|x86.Build.0 = Release|x86 {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Release|x86.ActiveCfg = Release|x86 - {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Release|Any CPU.Build.0 = Release|Any CPU - {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Debug|Any CPU.Build.0 = Debug|x86 + {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Debug|Any CPU.ActiveCfg = Debug|x86 + {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Release|Any CPU.Build.0 = Release|x86 + {0B12A079-B2DB-42B9-8A8E-AA5CBC2B3225}.Release|Any CPU.ActiveCfg = Release|x86 {2748AD25-9C63-4E12-877B-4DCE96FBED54}.Debug|x86.Build.0 = Debug|Any CPU {2748AD25-9C63-4E12-877B-4DCE96FBED54}.Debug|x86.ActiveCfg = Debug|Any CPU {2748AD25-9C63-4E12-877B-4DCE96FBED54}.Debug|Any CPU.Build.0 = Debug|Any CPU diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.addin b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.addin index 7bdb43077a..d68ee53668 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.addin +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.addin @@ -124,4 +124,16 @@ class="ICSharpCode.AspNet.Mvc.WebProjectOptionsPanel"/> + + + + + + + + diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj index 34524f74cd..d16b77692d 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/AspNet.Mvc.csproj @@ -122,6 +122,14 @@ + + + + + + + + @@ -257,6 +265,7 @@ + diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpCompletionBinding.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpCompletionBinding.cs new file mode 100644 index 0000000000..d0a5ada85b --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpCompletionBinding.cs @@ -0,0 +1,27 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.SharpDevelop.Editor; +using ICSharpCode.SharpDevelop.Editor.CodeCompletion; + +namespace ICSharpCode.AspNet.Mvc.Completion +{ + public class RazorCSharpCompletionBinding : DefaultCodeCompletionBinding + { + public RazorCSharpCompletionBinding() + { + } + + public override CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch) + { + if (ch == '.') { + new RazorCSharpDotCompletionDataProvider().ShowCompletion(editor); + return CodeCompletionKeyPressResult.Completed; + } else if (ch == '(') { + return base.HandleKeyPress(editor, ch); + } + return CodeCompletionKeyPressResult.None; + } + } +} diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs new file mode 100644 index 0000000000..7a033d314f --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpDotCompletionDataProvider.cs @@ -0,0 +1,17 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver; +using ICSharpCode.SharpDevelop.Editor; +using ICSharpCode.SharpDevelop.Editor.CodeCompletion; + +namespace ICSharpCode.AspNet.Mvc.Completion +{ + public class RazorCSharpDotCompletionDataProvider : DotCodeCompletionItemProvider + { + } +} diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpExpressionFinder.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpExpressionFinder.cs new file mode 100644 index 0000000000..705f4c8029 --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpExpressionFinder.cs @@ -0,0 +1,43 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.SharpDevelop.Dom; + +namespace ICSharpCode.AspNet.Mvc.Completion +{ + public class RazorCSharpExpressionFinder : IExpressionFinder + { + public RazorCSharpExpressionFinder() + { + } + + public ExpressionResult FindExpression(string text, int offset) + { + int position = offset - 1; + while (position > 0 && IsValidCharacter(text[position])) { + position--; + } + position++; + string expression = text.Substring(position, offset - position); + return new ExpressionResult(expression); + } + + bool IsValidCharacter(char ch) + { + return Char.IsLetterOrDigit(ch) || + (ch == '.') || + (ch == '_'); + } + + public ExpressionResult FindFullExpression(string text, int offset) + { + return ExpressionResult.Empty; + } + + public string RemoveLastPart(string expression) + { + return expression; + } + } +} diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpModelTypeLocater.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpModelTypeLocater.cs new file mode 100644 index 0000000000..36c72f8381 --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpModelTypeLocater.cs @@ -0,0 +1,34 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Web.Razor; +using ICSharpCode.SharpDevelop; + +namespace ICSharpCode.AspNet.Mvc.Completion +{ + public class RazorCSharpModelTypeLocater + { + public RazorCSharpModelTypeLocater(ITextBuffer textBuffer) + { + ParserResults results = ParseTemplate(textBuffer); + ModelTypeName = GetModelTypeName(results); + } + + ParserResults ParseTemplate(ITextBuffer textBuffer) + { + var host = new RazorEngineHost(new CSharpRazorCodeLanguage()); + var engine = new RazorTemplateEngine(host); + return engine.ParseTemplate(textBuffer.CreateReader()); + } + + string GetModelTypeName(ParserResults results) + { + var visitor = new RazorCSharpParserModelTypeVisitor(); + results.Document.Accept(visitor); + return visitor.ModelTypeName; + } + + public string ModelTypeName { get; private set; } + } +} diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs new file mode 100644 index 0000000000..7bd506f5c4 --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParser.cs @@ -0,0 +1,53 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.IO; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Dom.CSharp; +using ICSharpCode.SharpDevelop.Project; + +namespace ICSharpCode.AspNet.Mvc.Completion +{ + public class RazorCSharpParser : IParser + { + public RazorCSharpParser() + { + } + + public string[] LexerTags { get; set; } + + public LanguageProperties Language { + get { return LanguageProperties.CSharp; } + } + + public IExpressionFinder CreateExpressionFinder(string fileName) + { + return new RazorCSharpExpressionFinder(); + } + + public bool CanParse(string fileName) + { + return Path.GetExtension(fileName).Equals(".cshtml", StringComparison.OrdinalIgnoreCase); + } + + public bool CanParse(IProject project) + { + return project.Language == "C#"; + } + + public ICompilationUnit Parse(IProjectContent projectContent, string fileName, ITextBuffer fileContent) + { + var modelTypeLocater = new RazorCSharpModelTypeLocater(fileContent); + return new RazorCompilationUnit(projectContent) { + ModelTypeName = modelTypeLocater.ModelTypeName + }; + } + + public IResolver CreateResolver() + { + return new RazorCSharpResolver(); + } + } +} diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParserModelTypeVisitor.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParserModelTypeVisitor.cs new file mode 100644 index 0000000000..c1424045ca --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpParserModelTypeVisitor.cs @@ -0,0 +1,59 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Web.Razor.Parser; +using System.Web.Razor.Parser.SyntaxTree; + +namespace ICSharpCode.AspNet.Mvc.Completion +{ + public class RazorCSharpParserModelTypeVisitor : ParserVisitor + { + bool foundModelTypeName; + + public RazorCSharpParserModelTypeVisitor() + { + ModelTypeName = String.Empty; + } + + public string ModelTypeName { get; private set; } + + public override void VisitSpan(Span span) + { + Console.WriteLine("Span.Kind: " + span.Kind); + Console.WriteLine("Span.GetType(): " + span.GetType().Name); + Console.WriteLine("Span.Content: '" + span.Content + "'"); + + if (foundModelTypeName) + return; + + if (IsModelSpan(span)) { + VisitModelNameSpan(span.Next); + } + } + + bool IsModelSpan(Span span) + { + return span.Content == "model"; + } + + void VisitModelNameSpan(Span span) + { + if (span == null) + return; + + string firstLineOfMarkup = GetFirstLine(span.Content); + ModelTypeName = firstLineOfMarkup.Trim(); + foundModelTypeName = true; + } + + string GetFirstLine(string text) + { + int endOfLineIndex = text.IndexOf('\r'); + if (endOfLineIndex > 0) { + return text.Substring(0, endOfLineIndex); + } + return text; + } + } +} diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpResolver.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpResolver.cs new file mode 100644 index 0000000000..b4641316c6 --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCSharpResolver.cs @@ -0,0 +1,105 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver; + +namespace ICSharpCode.AspNet.Mvc.Completion +{ + public class RazorCSharpResolver : IResolver + { + NRefactoryResolver resolver = new NRefactoryResolver(LanguageProperties.CSharp); + + public ResolveResult Resolve(ExpressionResult expressionResult, ParseInformation parseInfo, string fileContent) + { + ParseInformation parseInfoWithWebViewPageClass = CreateParseInformationWithWebViewPageClass(parseInfo); + expressionResult.Region = GetRegionInMiddleOfWebViewPageClass(); + return resolver.Resolve(expressionResult, parseInfoWithWebViewPageClass, fileContent); + } + + ParseInformation CreateParseInformationWithWebViewPageClass(ParseInformation parseInfo) + { + RazorCompilationUnit compilationUnit = RazorCompilationUnit.CreateFromParseInfo(parseInfo); + AddDefaultUsings(compilationUnit); + AddWebViewPageClass(compilationUnit); + return new ParseInformation(compilationUnit); + } + + void AddDefaultUsings(ICompilationUnit compilationUnit) + { + AddUsing("System.Web.Mvc", compilationUnit); + AddUsing("System.Web.Mvc.Ajax", compilationUnit); + AddUsing("System.Web.Mvc.Html", compilationUnit); + AddUsing("System.Web.Routing", compilationUnit); + } + + void AddUsing(string name, ICompilationUnit compilationUnit) + { + DefaultUsing defaultUsing = CreateUsing(name, compilationUnit.ProjectContent); + compilationUnit.UsingScope.Usings.Add(defaultUsing); + } + + DefaultUsing CreateUsing(string namespaceName, IProjectContent projectContent) + { + var defaultUsing = new DefaultUsing(projectContent); + defaultUsing.Usings.Add(namespaceName); + return defaultUsing; + } + + void AddWebViewPageClass(RazorCompilationUnit compilationUnit) + { + DefaultClass webViewPageClass = CreateWebViewPageClass(compilationUnit); + compilationUnit.Classes.Add(webViewPageClass); + } + + DefaultClass CreateWebViewPageClass(RazorCompilationUnit compilationUnit) + { + var webViewPageClass = new DefaultClass(compilationUnit, "RazorWebViewPage") { + Region = new DomRegion(1, 0, 3, 0) + }; + IReturnType modelType = GetModelReturnType(compilationUnit); + AddWebViewPageBaseClass(webViewPageClass, modelType); + return webViewPageClass; + } + + IReturnType GetModelReturnType(RazorCompilationUnit compilationUnit) + { + IClass modelType = GetClassIfTypeNameIsNotEmpty(compilationUnit.ProjectContent, compilationUnit.ModelTypeName); + if (modelType != null) { + return modelType.DefaultReturnType; + } + return new DynamicReturnType(compilationUnit.ProjectContent); + } + + IClass GetClassIfTypeNameIsNotEmpty(IProjectContent projectContent, string modelTypeName) + { + if (!String.IsNullOrEmpty(modelTypeName)) { + return projectContent.GetClass(modelTypeName, 0); + } + return null; + } + + void AddWebViewPageBaseClass(DefaultClass webViewPageClass, IReturnType modelType) + { + IClass webViewPageBaseClass = webViewPageClass.ProjectContent.GetClass("System.Web.Mvc.WebViewPage", 1); + if (webViewPageBaseClass != null) { + IReturnType returnType = GetWebViewPageBaseClassReturnType(webViewPageBaseClass, modelType); + webViewPageClass.BaseTypes.Add(returnType); + } + } + + IReturnType GetWebViewPageBaseClassReturnType(IClass webViewPageBaseClass, IReturnType modelType) + { + var typeArguments = new List(); + typeArguments.Add(modelType); + return new ConstructedReturnType(webViewPageBaseClass.DefaultReturnType, typeArguments); + } + + DomRegion GetRegionInMiddleOfWebViewPageClass() + { + return new DomRegion(2, 0, 2, 0); + } + } +} diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCompilationUnit.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCompilationUnit.cs new file mode 100644 index 0000000000..498c929da1 --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Completion/RazorCompilationUnit.cs @@ -0,0 +1,34 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.SharpDevelop.Dom; + +namespace ICSharpCode.AspNet.Mvc.Completion +{ + public class RazorCompilationUnit : DefaultCompilationUnit + { + public RazorCompilationUnit(IProjectContent projectContent) + : base(projectContent) + { + } + + public static RazorCompilationUnit CreateFromParseInfo(ParseInformation parseInformation) + { + return new RazorCompilationUnit(parseInformation.CompilationUnit.ProjectContent) { + ModelTypeName = GetModelTypeName(parseInformation.CompilationUnit) + }; + } + + static string GetModelTypeName(ICompilationUnit compilationUnit) + { + var originalRazorCompilationUnit = compilationUnit as RazorCompilationUnit; + if (originalRazorCompilationUnit != null) { + return originalRazorCompilationUnit.ModelTypeName; + } + return String.Empty; + } + + public string ModelTypeName { get; set; } + } +} diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Folding/FoldGenerator.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Folding/FoldGenerator.cs index a65867b9bb..9dcefd4b2a 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Folding/FoldGenerator.cs +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/Folding/FoldGenerator.cs @@ -30,8 +30,8 @@ namespace ICSharpCode.AspNet.Mvc.Folding public void Dispose() { - IsParseInformationFoldingEnabled = true; textEditor.Dispose(); + IsParseInformationFoldingEnabled = true; } public void GenerateFolds() diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Test/AspNet.Mvc.Tests.csproj b/src/AddIns/BackendBindings/AspNet.Mvc/Test/AspNet.Mvc.Tests.csproj index e4487ba0af..f0bf407d37 100644 --- a/src/AddIns/BackendBindings/AspNet.Mvc/Test/AspNet.Mvc.Tests.csproj +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Test/AspNet.Mvc.Tests.csproj @@ -117,6 +117,7 @@ + @@ -189,6 +190,7 @@ + \ No newline at end of file diff --git a/src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/Completion/RazorCSharpParserTests.cs b/src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/Completion/RazorCSharpParserTests.cs new file mode 100644 index 0000000000..0ec664c234 --- /dev/null +++ b/src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/Completion/RazorCSharpParserTests.cs @@ -0,0 +1,148 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.AspNet.Mvc.Completion; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Dom; +using NUnit.Framework; + +namespace AspNet.Mvc.Tests.Completion +{ + [TestFixture] + public class RazorCSharpParserTests + { + RazorCSharpParser parser; + + void CreateParser() + { + parser = new RazorCSharpParser(); + } + + ICompilationUnit Parse(string code) + { + var projectContent = new DefaultProjectContent(); + var textBuffer = new StringTextBuffer(code); + return parser.Parse(projectContent, @"d:\MyProject\Views\Index.cshtml", textBuffer); + } + + [Test] + public void Parse_ModelDirectiveWithTypeName_ModelTypeNameFound() + { + CreateParser(); + string code = "@model MvcApplication.MyModel\r\n"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual("MvcApplication.MyModel", compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_ModelDirectiveWithTypeNameFollowedByHtmlMarkup_ModelTypeNameFound() + { + CreateParser(); + string code = + "@model MvcApplication.LogonModel\r\n" + + "

Index

\r\n"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual("MvcApplication.LogonModel", compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_SingleLineFileWithModelDirectiveAndTypeNameButNoNewLineAtEnd_ModelTypeNameFound() + { + CreateParser(); + string code = "@model MvcApplication.MyModel"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual("MvcApplication.MyModel", compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_ModelTypeDirectiveWithTypeNameFollowedByRazorBlock_ModelTypeNameFound() + { + CreateParser(); + + string code = + "@model IEnumerable\r\n" + + "\r\n" + + "@{\r\n" + + " ViewBag.Title = \"Title1\";\r\n" + + "}\r\n" + + "\r\n"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual("IEnumerable", compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_UsingDirective_ModelTypeNameIsEmptyString() + { + CreateParser(); + string code = "@using System.Xml\r\n"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_HelperDirective_ModelTypeNameIsEmptyString() + { + CreateParser(); + string code = "@helper MyHelper\r\n"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_HtmlMarkupOnly_ModelTypeNameIsEmptyString() + { + CreateParser(); + string code = "

heading

\r\n"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_ModelDirectiveOnly_ModelTypeNameIsEmptyString() + { + CreateParser(); + string code = "@model"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_ModelStringInsideParagraphTags_ModelTypeNameIsEmptyString() + { + CreateParser(); + string code = "

model

"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName); + } + + [Test] + public void Parse_ModelStringOnlyWithoutRazorTransition_ModelTypeNameIsEmptyString() + { + CreateParser(); + string code = "model"; + + var compilationUnit = Parse(code) as RazorCompilationUnit; + + Assert.AreEqual(String.Empty, compilationUnit.ModelTypeName); + } + } +} diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/TextViewOptions.xaml b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/TextViewOptions.xaml index 3e97ec3bb9..1239bbcfd4 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/TextViewOptions.xaml +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/TextViewOptions.xaml @@ -42,6 +42,8 @@ Content="{core:Localize Dialog.Options.IDEOptions.TextEditor.Markers.AtRowLabel}" /> diff --git a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj index f67b13d684..8fc60c7231 100644 --- a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj +++ b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj @@ -74,6 +74,7 @@ + @@ -94,10 +95,12 @@ + + @@ -116,10 +119,18 @@ + + + + + + + + @@ -132,12 +143,19 @@ + + + + + + + @@ -205,6 +223,7 @@ + @@ -450,6 +469,7 @@ + diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/ClassKindUpdater.cs b/src/AddIns/Misc/PackageManagement/Project/Src/ClassKindUpdater.cs new file mode 100644 index 0000000000..e355235cc7 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/ClassKindUpdater.cs @@ -0,0 +1,66 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Dom.Refactoring; + +namespace ICSharpCode.PackageManagement +{ + public class ClassKindUpdater : IClassKindUpdater + { + public ClassKindUpdater(IClass c) + : this(c, new DocumentLoader()) + { + } + + public ClassKindUpdater(IClass c, IDocumentLoader documentLoader) + { + this.Class = c; + this.DocumentLoader = documentLoader; + } + + IClass Class { get; set; } + IDocumentLoader DocumentLoader { get; set; } + IRefactoringDocument Document { get; set; } + + public void MakeClassPartial() + { + if (Class.IsPartial) + return; + + OpenFileContainingClass(); + int offset = GetPartialKeywordInsertOffset(); + InsertPartialKeyword(offset); + } + + void OpenFileContainingClass() + { + Document = DocumentLoader.LoadRefactoringDocument(Class.CompilationUnit.FileName); + } + + int GetPartialKeywordInsertOffset() + { + IRefactoringDocumentLine line = Document.GetLine(Class.Region.BeginLine); + int offset = line.Text.IndexOf(" class", StringComparison.OrdinalIgnoreCase); + if (offset >= 0) { + return offset + line.Offset + 1; + } + throw new ApplicationException("Unable to find 'class' declaration."); + } + + void InsertPartialKeyword(int offset) + { + string partialKeyword = GetLanguageSpecificPartialKeyword(); + Document.Insert(offset, partialKeyword + " "); + } + + string GetLanguageSpecificPartialKeyword() + { + if (Class.ProjectContent.Language == LanguageProperties.VBNet) { + return "Partial"; + } + return "partial"; + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/Design/FakePackageManagementProjectService.cs b/src/AddIns/Misc/PackageManagement/Project/Src/Design/FakePackageManagementProjectService.cs index ff28aa3eed..2c8390a1ab 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/Design/FakePackageManagementProjectService.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/Design/FakePackageManagementProjectService.cs @@ -99,5 +99,20 @@ namespace ICSharpCode.PackageManagement.Design { return ProjectBrowserUpdater; } + + Dictionary defaultCustomTools = new Dictionary(); + + public void AddDefaultCustomToolForFileName(string fileName, string customTool) + { + defaultCustomTools.Add(fileName, customTool); + } + + public string GetDefaultCustomToolForFileName(FileProjectItem projectItem) + { + if (defaultCustomTools.ContainsKey(projectItem.FileName)) { + return defaultCustomTools[projectItem.FileName]; + } + return String.Empty; + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ChildProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ChildProjectItems.cs index f04a8e55b1..d1548b0569 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ChildProjectItems.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ChildProjectItems.cs @@ -2,7 +2,6 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; -using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; @@ -12,7 +11,7 @@ using SD = ICSharpCode.SharpDevelop.Project; namespace ICSharpCode.PackageManagement.EnvDTE { - public class ChildProjectItems : IEnumerable + public class ChildProjectItems : EnumerableProjectItems { public ChildProjectItems(ProjectItem projectItem) { @@ -25,18 +24,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE Project Project { get; set; } List ProjectItems { get; set; } - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public IEnumerator GetEnumerator() - { - List projectItems = GetProjectItems().ToList(); - return projectItems.GetEnumerator(); - } - - IEnumerable GetProjectItems() + protected override IEnumerable GetProjectItems() { foreach (SD.ProjectItem msbuildProjectItem in Project.MSBuildProject.Items) { ProjectItem item = GetChildProjectItem(msbuildProjectItem); diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeAttributes.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeAttributes.cs index a3bd7761ef..a41cd3d50b 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeAttributes.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeAttributes.cs @@ -11,17 +11,24 @@ namespace ICSharpCode.PackageManagement.EnvDTE { public class CodeAttributes : CodeElementsList { - IEntity entity; - public CodeAttributes(IEntity entity) + : this(entity.Attributes) + { + } + + public CodeAttributes(IParameter parameter) + : this(parameter.Attributes) + { + } + + public CodeAttributes(IEnumerable attributes) { - this.entity = entity; - GetAttributes(); + AddAttributes(attributes); } - void GetAttributes() + void AddAttributes(IEnumerable attributes) { - foreach (IAttribute attribute in entity.Attributes) { + foreach (IAttribute attribute in attributes) { AddAttribute(attribute); } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs index b0050fcdcf..db0a41464c 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeClass2.cs @@ -8,8 +8,16 @@ namespace ICSharpCode.PackageManagement.EnvDTE { public class CodeClass2 : CodeClass { - public CodeClass2(IProjectContent projectContent, IClass c) + IClassKindUpdater classKindUpdater; + + public CodeClass2(IProjectContent projectContent, IClass c, IClassKindUpdater classKindUpdater) : base(projectContent, c) + { + this.classKindUpdater = classKindUpdater; + } + + public CodeClass2(IProjectContent projectContent, IClass c) + : this(projectContent, c, new ClassKindUpdater(c)) { } @@ -22,5 +30,29 @@ namespace ICSharpCode.PackageManagement.EnvDTE IClass baseTypeClass = baseType.GetUnderlyingClass(); return new CodeClass2(projectContent, baseTypeClass); } + + public bool IsGeneric { + get { return Class.DotNetName.Contains("`"); } + } + + public vsCMClassKind ClassKind { + get { + if (Class.IsPartial) { + return vsCMClassKind.vsCMClassKindPartialClass; + } + return vsCMClassKind.vsCMClassKindMainClass; + } + set { + if (value == vsCMClassKind.vsCMClassKindPartialClass) { + classKindUpdater.MakeClassPartial(); + } else { + throw new NotImplementedException(); + } + } + } + + public bool IsAbstract { + get { return Class.IsAbstract; } + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs index dc90f2ccbf..b1afbed8d1 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction.cs @@ -8,19 +8,20 @@ namespace ICSharpCode.PackageManagement.EnvDTE { public class CodeFunction : CodeElement { - IMethodOrProperty method; IDocumentLoader documentLoader; + IVirtualMethodUpdater methodUpdater; public CodeFunction(IMethod method) - : this(method, new DocumentLoader()) + : this(method, new DocumentLoader(), new VirtualMethodUpdater(method)) { } - public CodeFunction(IMethod method, IDocumentLoader documentLoader) + public CodeFunction(IMethod method, IDocumentLoader documentLoader, IVirtualMethodUpdater methodUpdater) : base(method) { - this.method = method; + this.Method = method; this.documentLoader = documentLoader; + this.methodUpdater = methodUpdater; } public CodeFunction() @@ -32,6 +33,8 @@ namespace ICSharpCode.PackageManagement.EnvDTE { } + protected IMethodOrProperty Method { get; private set; } + public override vsCMElement Kind { get { return vsCMElement.vsCMElementFunction; } } @@ -43,20 +46,53 @@ namespace ICSharpCode.PackageManagement.EnvDTE public override TextPoint GetStartPoint() { - return new TextPoint(method.GetStartPosition(), documentLoader); + return new TextPoint(Method.GetStartPosition(), documentLoader); } public override TextPoint GetEndPoint() { - return new TextPoint(method.GetEndPosition(), documentLoader); + return new TextPoint(Method.GetEndPosition(), documentLoader); } public virtual CodeElements Parameters { - get { return new CodeParameters(method.ProjectContent, method.Parameters); } + get { return new CodeParameters(Method.ProjectContent, Method.Parameters); } } public virtual CodeTypeRef2 Type { - get { return new CodeTypeRef2(method.ProjectContent, this, method.ReturnType); } + get { return new CodeTypeRef2(Method.ProjectContent, this, Method.ReturnType); } + } + + public virtual CodeElements Attributes { + get { return new CodeAttributes(Method); } + } + + public virtual bool CanOverride { + get { return Method.IsOverridable; } + set { + if (value) { + methodUpdater.MakeMethodVirtual(); + } + } + } + + public virtual vsCMFunction FunctionKind { + get { return GetFunctionKind(); } + } + + vsCMFunction GetFunctionKind() + { + if (Method.IsConstructor()) { + return vsCMFunction.vsCMFunctionConstructor; + } + return vsCMFunction.vsCMFunctionFunction; + } + + public virtual bool IsShared { + get { return Method.IsStatic; } + } + + public virtual bool MustImplement { + get { return Method.IsAbstract; } } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs new file mode 100644 index 0000000000..6b7cf2f682 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeFunction2.cs @@ -0,0 +1,40 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.SharpDevelop.Dom; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public class CodeFunction2 : CodeFunction + { + public CodeFunction2(IMethod method) + : base(method) + { + } + + public virtual bool IsGeneric { + get { return Method.HasTypeParameters(); } + } + + public virtual vsCMOverrideKind OverrideKind { + get { return GetOverrideKind(); } + } + + vsCMOverrideKind GetOverrideKind() + { + if (Method.IsAbstract) { + return vsCMOverrideKind.vsCMOverrideKindAbstract; + } else if (Method.IsVirtual) { + return vsCMOverrideKind.vsCMOverrideKindVirtual; + } else if (Method.IsOverride) { + return vsCMOverrideKind.vsCMOverrideKindOverride; + } else if (Method.IsSealed) { + return vsCMOverrideKind.vsCMOverrideKindSealed; + } else if (Method.IsNew) { + return vsCMOverrideKind.vsCMOverrideKindNew; + } + return vsCMOverrideKind.vsCMOverrideKindNone; + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeNamespace.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeNamespace.cs index 9c93be2971..a5b323dff9 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeNamespace.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeNamespace.cs @@ -40,7 +40,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE get { return namespaceName.LastPart; } } - public CodeElements Members { + public virtual CodeElements Members { get { return new CodeElementsInNamespace(projectContent, namespaceName); } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter.cs index 22e0e9b2b8..a8c16b5ad4 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter.cs @@ -9,24 +9,29 @@ namespace ICSharpCode.PackageManagement.EnvDTE public class CodeParameter : CodeElement { IProjectContent projectContent; - IParameter parameter; public CodeParameter(IProjectContent projectContent, IParameter parameter) { this.projectContent = projectContent; - this.parameter = parameter; + this.Parameter = parameter; } + protected IParameter Parameter { get; private set; } + public override vsCMElement Kind { get { return vsCMElement.vsCMElementParameter; } } public override string Name { - get { return parameter.Name; } + get { return Parameter.Name; } } public virtual CodeTypeRef2 Type { - get { return new CodeTypeRef2(projectContent, this, parameter.ReturnType); } + get { return new CodeTypeRef2(projectContent, this, Parameter.ReturnType); } + } + + public virtual CodeElements Attributes { + get { return new CodeAttributes(Parameter); } } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter2.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter2.cs new file mode 100644 index 0000000000..40b78f73ec --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameter2.cs @@ -0,0 +1,36 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.SharpDevelop.Dom; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public class CodeParameter2 : CodeParameter + { + public CodeParameter2(IProjectContent projectContent, IParameter parameter) + : base(projectContent, parameter) + { + } + + public virtual vsCMParameterKind ParameterKind { + get { return GetParameterKind(); } + } + + vsCMParameterKind GetParameterKind() + { + if (Parameter.IsOptional) { + return vsCMParameterKind.vsCMParameterKindOptional; + } else if (Parameter.IsOut) { + return vsCMParameterKind.vsCMParameterKindOut; + } else if (Parameter.IsRef) { + return vsCMParameterKind.vsCMParameterKindRef; + } else if (Parameter.IsParams) { + return vsCMParameterKind.vsCMParameterKindParamArray; + } else if (Parameter.IsIn()) { + return vsCMParameterKind.vsCMParameterKindIn; + } + return vsCMParameterKind.vsCMParameterKindNone; + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameters.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameters.cs index 97d7de2a22..057f55da17 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameters.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeParameters.cs @@ -26,7 +26,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE void AddParameters(IParameter parameter) { - AddCodeElement(new CodeParameter(projectContent, parameter)); + AddCodeElement(new CodeParameter2(projectContent, parameter)); } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeType.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeType.cs index 71811e8c46..25b9df8a8b 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeType.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeType.cs @@ -2,6 +2,7 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.Linq; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Project; @@ -66,16 +67,25 @@ namespace ICSharpCode.PackageManagement.EnvDTE } public virtual CodeNamespace Namespace { - get { return new CodeNamespace(ProjectContent, Class.Namespace); } + get { return new FileCodeModelCodeNamespace(ProjectContent, Class.Namespace); } } public virtual ProjectItem ProjectItem { get { if (ProjectContent.Project != null) { - return new ProjectItem((MSBuildBasedProject)ProjectContent.Project, Class); + return new ProjectItem(ProjectContent, Class); } return null; } } + + /// + /// Returns true if the current type matches the fully qualified name or any of its + /// base types are a match. + /// + public virtual bool IsDerivedFrom(string fullName) + { + return Class.IsDerivedFrom(fullName); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeMembers.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeMembers.cs index fa352035ab..d2c6ab10dd 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeMembers.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeMembers.cs @@ -33,7 +33,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE void AddMethod(IMethod method) { - AddCodeElement(new CodeFunction(method)); + AddCodeElement(new CodeFunction2(method)); } void AddField(IField field) diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeRef.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeRef.cs index 5bfdb6aa17..6c1aa2b600 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeRef.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/CodeTypeRef.cs @@ -44,5 +44,9 @@ namespace ICSharpCode.PackageManagement.EnvDTE public virtual CodeType CodeType { get { return new CodeClass2(projectContent, ReturnType.GetUnderlyingClass()); } } + + public virtual vsCMTypeRef TypeKind { + get { return ReturnType.GetTypeKind(); } + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Constants.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Constants.cs index 1245b8114b..7e7c8164db 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Constants.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Constants.cs @@ -7,7 +7,8 @@ namespace ICSharpCode.PackageManagement.EnvDTE { public static class Constants { - public static readonly string VsProjectItemKindPhysicalFile = "{6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C}"; - public static readonly string VsProjectItemKindPhysicalFolder = "{6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}"; + public static readonly string vsProjectItemKindPhysicalFile = "{6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C}"; + public static readonly string vsProjectItemKindPhysicalFolder = "{6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}"; + public static readonly string vsViewKindCode = "{7651A701-06E5-11D1-8EBD-00A0C90F26EA}"; } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/DirectoryProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/DirectoryProjectItems.cs index 0d76dce23e..1569024717 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/DirectoryProjectItems.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/DirectoryProjectItems.cs @@ -3,6 +3,7 @@ using System; using System.Collections; +using System.Collections.Generic; namespace ICSharpCode.PackageManagement.EnvDTE { @@ -16,10 +17,9 @@ namespace ICSharpCode.PackageManagement.EnvDTE this.projectItem = projectItem; } - public override IEnumerator GetEnumerator() + protected override IEnumerable GetProjectItems() { - var items = new ChildProjectItems(projectItem); - return items.GetEnumerator(); + return new ChildProjectItems(projectItem); } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs new file mode 100644 index 0000000000..bcff49be22 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Document.cs @@ -0,0 +1,26 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.SharpDevelop.Gui; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public class Document : MarshalByRefObject + { + IViewContent view; + + public Document(string fileName, IViewContent view) + { + this.FullName = fileName; + this.view = view; + } + + public virtual bool Saved { + get { return !view.IsDirty; } + set { view.PrimaryFile.IsDirty = !value; } + } + + public string FullName { get; private set; } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/EnumerableProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/EnumerableProjectItems.cs new file mode 100644 index 0000000000..7bef56ffef --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/EnumerableProjectItems.cs @@ -0,0 +1,33 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public abstract class EnumerableProjectItems : MarshalByRefObject, IEnumerable + { + public EnumerableProjectItems() + { + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public IEnumerator GetEnumerator() + { + return GetProjectItems().ToList().GetEnumerator(); + } + + protected abstract IEnumerable GetProjectItems(); + + internal virtual int Count { + get { return GetProjectItems().Count(); } + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModel2.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModel2.cs index 8c03c33a09..f0cb71267d 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModel2.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModel2.cs @@ -7,7 +7,7 @@ using ICSharpCode.SharpDevelop.Project; namespace ICSharpCode.PackageManagement.EnvDTE { - public class FileCodeModel2 + public class FileCodeModel2 : MarshalByRefObject { Project project; FileProjectItem projectItem; diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeElements.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeElements.cs index 2ee8af40d5..39bb3f4636 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeElements.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeElements.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Project; @@ -11,6 +12,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE public class FileCodeModelCodeElements : CodeElementsList { ICompilationUnit compilationUnit; + List fileCodeModelNamespaces = new List(); public FileCodeModelCodeElements(ICompilationUnit compilationUnit) { @@ -23,6 +25,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE foreach (IUsing namespaceUsing in GetNamespaceImports()) { AddNamespaceImport(namespaceUsing); } + AddClasses(); } IList GetNamespaceImports() @@ -36,5 +39,35 @@ namespace ICSharpCode.PackageManagement.EnvDTE { AddCodeElement(new CodeImport(import)); } + + void AddClasses() + { + foreach (IClass c in compilationUnit.Classes) { + FileCodeModelCodeNamespace codeNamespace = GetOrCreateFileCodeModelNamespace(c); + codeNamespace.AddClass(compilationUnit.ProjectContent, c); + } + } + + FileCodeModelCodeNamespace GetOrCreateFileCodeModelNamespace(IClass c) + { + var codeNamespace = FindFileCodeModelNamespace(c); + if (codeNamespace != null) { + return codeNamespace; + } + return CreateFileCodeModelNamespace(c); + } + + FileCodeModelCodeNamespace FindFileCodeModelNamespace(IClass c) + { + return fileCodeModelNamespaces.FirstOrDefault(ns => ns.FullName == c.Namespace); + } + + FileCodeModelCodeNamespace CreateFileCodeModelNamespace(IClass c) + { + var codeNamespace = new FileCodeModelCodeNamespace(compilationUnit.ProjectContent, c.Namespace); + AddCodeElement(codeNamespace); + fileCodeModelNamespaces.Add(codeNamespace); + return codeNamespace; + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeNamespace.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeNamespace.cs new file mode 100644 index 0000000000..12fb129859 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeNamespace.cs @@ -0,0 +1,38 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.SharpDevelop.Dom; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + /// + /// File code model namespaces take the full name of the namespace that a class + /// is inside. So for the FileCodeModelNamespace class the CodeNamespace.Name + /// would be ICSharpCode.PackageManagement.EnvDTE. + /// This differs from the CodeModel CodeNamespace which breaks up the namespaces into + /// parts. + /// + public class FileCodeModelCodeNamespace : CodeNamespace + { + FileCodeModelCodeNamespaceMembers members = new FileCodeModelCodeNamespaceMembers(); + + public FileCodeModelCodeNamespace(IProjectContent projectContent, string namespaceName) + : base(projectContent, namespaceName) + { + } + + public override string Name { + get { return base.FullName; } + } + + public override CodeElements Members { + get { return members; } + } + + public void AddClass(IProjectContent projectContent, IClass c) + { + members.AddClass(projectContent, c); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeNamespaceMembers.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeNamespaceMembers.cs new file mode 100644 index 0000000000..99e00c8c58 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileCodeModelCodeNamespaceMembers.cs @@ -0,0 +1,21 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.SharpDevelop.Dom; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public class FileCodeModelCodeNamespaceMembers : CodeElementsList + { + public FileCodeModelCodeNamespaceMembers() + { + } + + public void AddClass(IProjectContent projectContent, IClass c) + { + var codeClass = new CodeClass2(projectContent, c); + AddCodeElement(codeClass); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItemExtensions.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItemExtensions.cs new file mode 100644 index 0000000000..ca9941192b --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItemExtensions.cs @@ -0,0 +1,34 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.IO; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Project; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public static class FileProjectItemExtensions + { + public static bool IsDependentUponAnotherFile(this FileProjectItem projectItem) + { + return !String.IsNullOrEmpty(projectItem.DependentUpon); + } + + public static bool IsDependentUpon(this FileProjectItem projectItem, FileProjectItem otherProjectItem) + { + return projectItem.DependentUpon == otherProjectItem.Include; + } + + public static bool IsDependentUponFileName(this FileProjectItem projectItem, string fileName) + { + return FileUtility.IsEqualFileName(projectItem.GetDependentUponFileName(), fileName); + } + + public static string GetDependentUponFileName(this FileProjectItem projectItem) + { + string directory = Path.GetDirectoryName(projectItem.FileName); + return Path.Combine(directory, projectItem.DependentUpon); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItems.cs new file mode 100644 index 0000000000..523a352117 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/FileProjectItems.cs @@ -0,0 +1,67 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using ICSharpCode.SharpDevelop.Gui; +using SD = ICSharpCode.SharpDevelop.Project; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + /// + /// A file can have child project items if it has files that depend upon it. + /// For example, winform designer files (MainForm.Designer.cs) + /// + public class FileProjectItems : ProjectItems + { + ProjectItem projectItem; + IPackageManagementFileService fileService; + + public FileProjectItems(ProjectItem projectItem) + : this(projectItem, new PackageManagementFileService()) + { + } + + public FileProjectItems(ProjectItem projectItem, IPackageManagementFileService fileService) + : base(projectItem.ContainingProject, projectItem, fileService) + { + this.projectItem = projectItem; + this.fileService = fileService; + } + + protected override IEnumerable GetProjectItems() + { + return GetChildDependentProjectItems().ToList(); + } + + IEnumerable GetChildDependentProjectItems() + { + foreach (SD.FileProjectItem fileProjectItem in GetFileProjectItems()) { + if (fileProjectItem.IsDependentUpon(projectItem.MSBuildProjectItem)) { + yield return new ProjectItem(Project, fileProjectItem); + } + } + } + + IEnumerable GetFileProjectItems() + { + return Project + .MSBuildProject + .Items + .Where(item => item is SD.FileProjectItem) + .Select(item => (SD.FileProjectItem)item); + } + + protected override ProjectItem AddFileProjectItemToProject(string fileName) + { + return AddFileProjectItemWithDependent(fileName); + } + + ProjectItem AddFileProjectItemWithDependent(string fileName) + { + return Project.AddFileProjectItemWithDependentUsingFullPath(fileName, projectItem.Name); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IClassExtensions.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IClassExtensions.cs new file mode 100644 index 0000000000..68d38b9081 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IClassExtensions.cs @@ -0,0 +1,43 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Linq; +using ICSharpCode.SharpDevelop.Dom; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public static class IClassExtensions + { + /// + /// Returns true if the class fully qualified name matches the name or + /// any class in the inheritance tree matches the name. + /// + public static bool IsDerivedFrom(this IClass c, string typeName) + { + if (c.FullyQualifiedName == typeName) { + return true; + } + + if (TypeNameMatchesBaseType(c.BaseType, typeName)) { + return true; + } + + return IsTypeInClassInheritanceTree(c, typeName); + } + + static bool TypeNameMatchesBaseType(IReturnType baseType, string typeName) + { + return + (baseType != null) && + (baseType.FullyQualifiedName == typeName); + } + + static bool IsTypeInClassInheritanceTree(IClass c, string typeName) + { + return c + .ClassInheritanceTreeClassesOnly + .Any(inheritedClass => inheritedClass.FullyQualifiedName == typeName); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IParameterExtensions.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IParameterExtensions.cs new file mode 100644 index 0000000000..89b949c521 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IParameterExtensions.cs @@ -0,0 +1,16 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.SharpDevelop.Dom; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public static class IParameterExtensions + { + public static bool IsIn(this IParameter parameter) + { + return (parameter.Modifiers & ParameterModifiers.In) == ParameterModifiers.In; + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IReturnTypeExtensions.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IReturnTypeExtensions.cs index 492b1f7e38..ca3b769d7c 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IReturnTypeExtensions.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/IReturnTypeExtensions.cs @@ -35,5 +35,52 @@ namespace ICSharpCode.PackageManagement.EnvDTE } return returnType.GetFullName(); } + + public static vsCMTypeRef GetTypeKind(this IReturnType returnType) + { + vsCMTypeRef typeRef = GetSystemTypeKind(returnType.FullyQualifiedName); + if (typeRef != vsCMTypeRef.vsCMTypeRefOther) { + return typeRef; + } + + if (returnType.IsReferenceType.GetValueOrDefault()) { + return vsCMTypeRef.vsCMTypeRefCodeType; + } + return vsCMTypeRef.vsCMTypeRefOther; + } + + static vsCMTypeRef GetSystemTypeKind(string fullyQualifiedTypeName) + { + switch (fullyQualifiedTypeName) { + case "System.String": + return vsCMTypeRef.vsCMTypeRefString; + case "System.Void": + return vsCMTypeRef.vsCMTypeRefVoid; + case "System.Boolean": + return vsCMTypeRef.vsCMTypeRefBool; + case "System.Int16": + case "System.UInt16": + return vsCMTypeRef.vsCMTypeRefShort; + case "System.Int32": + case "System.UInt32": + return vsCMTypeRef.vsCMTypeRefInt; + case "System.Int64": + case "System.UInt64": + return vsCMTypeRef.vsCMTypeRefLong; + case "System.Decimal": + return vsCMTypeRef.vsCMTypeRefDecimal; + case "System.Char": + return vsCMTypeRef.vsCMTypeRefChar; + case "System.Byte": + return vsCMTypeRef.vsCMTypeRefByte; + case "System.Object": + return vsCMTypeRef.vsCMTypeRefObject; + case "System.Double": + return vsCMTypeRef.vsCMTypeRefDouble; + case "System.Single": + return vsCMTypeRef.vsCMTypeRefFloat; + } + return vsCMTypeRef.vsCMTypeRefOther; + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs index cd45d6a465..17a71d99b3 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Project.cs @@ -5,8 +5,10 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; + using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Project; using Microsoft.Build.Construction; using SD = ICSharpCode.SharpDevelop.Project; @@ -155,9 +157,15 @@ namespace ICSharpCode.PackageManagement.EnvDTE } internal ProjectItem AddFileProjectItemUsingFullPath(string path) + { + return AddFileProjectItemWithDependentUsingFullPath(path, null); + } + + internal ProjectItem AddFileProjectItemWithDependentUsingFullPath(string path, string dependentUpon) { FileProjectItem fileProjectItem = CreateFileProjectItemUsingFullPath(path); fileProjectItem.FileName = path; + fileProjectItem.DependentUpon = dependentUpon; AddProjectItemToMSBuildProject(fileProjectItem); return new ProjectItem(this, fileProjectItem); } @@ -280,5 +288,24 @@ namespace ICSharpCode.PackageManagement.EnvDTE { projectService.RemoveProjectItem(MSBuildProject, projectItem.MSBuildProjectItem); } + + internal ProjectItem FindProjectItem(string fileName) + { + SD.FileProjectItem item = MSBuildProject.FindFile(fileName); + if (item != null) { + return new ProjectItem(this, item); + } + return null; + } + + internal IViewContent GetOpenFile(string fileName) + { + return fileService.GetOpenFile(fileName); + } + + internal void OpenFile(string fileName) + { + fileService.OpenFile(fileName); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs index 851bf53fb8..8f6e5ebad5 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItem.cs @@ -7,6 +7,7 @@ using System.IO; using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Project; using SD = ICSharpCode.SharpDevelop.Project; @@ -24,22 +25,35 @@ namespace ICSharpCode.PackageManagement.EnvDTE { this.projectItem = projectItem; this.ContainingProject = project; - this.ProjectItems = new DirectoryProjectItems(this); + this.ProjectItems = CreateProjectItems(projectItem); CreateProperties(); Kind = GetKindFromFileProjectItemType(); } + ProjectItems CreateProjectItems(FileProjectItem projectItem) + { + if (projectItem.ItemType == ItemType.Folder) { + return new DirectoryProjectItems(this); + } + return new FileProjectItems(this); + } + internal ProjectItem(MSBuildBasedProject project, IClass c) : this(new Project(project), project.FindFile(c.CompilationUnit.FileName)) { } + internal ProjectItem(IProjectContent projectContent, IClass c) + : this((MSBuildBasedProject)projectContent.Project, c) + { + } + string GetKindFromFileProjectItemType() { if (IsDirectory) { - return Constants.VsProjectItemKindPhysicalFolder; + return Constants.vsProjectItemKindPhysicalFolder; } - return Constants.VsProjectItemKindPhysicalFile; + return Constants.vsProjectItemKindPhysicalFile; } bool IsDirectory { @@ -162,7 +176,30 @@ namespace ICSharpCode.PackageManagement.EnvDTE public virtual string FileNames(short index) { - return projectItem.FileName; + return FileName; + } + + string FileName { + get { return projectItem.FileName; } + } + + public virtual Document Document { + get { return GetOpenDocument(); } + } + + Document GetOpenDocument() + { + IViewContent view = ContainingProject.GetOpenFile(FileName); + if (view != null) { + return new Document(FileName, view); + } + return null; + } + + public virtual Window Open(string viewKind) + { + ContainingProject.OpenFile(FileName); + return null; } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs index 37ce66d606..5b694bc970 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItems.cs @@ -11,13 +11,12 @@ namespace ICSharpCode.PackageManagement.EnvDTE { public class ProjectItems : MarshalByRefObject, IEnumerable { - Project project; IPackageManagementFileService fileService; object parent; public ProjectItems(Project project, object parent, IPackageManagementFileService fileService) { - this.project = project; + this.Project = project; this.fileService = fileService; this.parent = parent; } @@ -26,6 +25,8 @@ namespace ICSharpCode.PackageManagement.EnvDTE { } + protected Project Project { get; private set; } + public virtual object Parent { get { return parent; } } @@ -34,8 +35,8 @@ namespace ICSharpCode.PackageManagement.EnvDTE { string include = GetIncludePathForFileCopy(filePath); CopyFileIntoProject(filePath, include); - project.AddFileProjectItemUsingPathRelativeToProject(include); - project.Save(); + Project.AddFileProjectItemUsingPathRelativeToProject(include); + Project.Save(); } /// @@ -68,13 +69,17 @@ namespace ICSharpCode.PackageManagement.EnvDTE string GetFileNameInProjectFromProjectItemInclude(string projectItemInclude) { - return Path.Combine(project.MSBuildProject.Directory, projectItemInclude); + return Path.Combine(Project.MSBuildProject.Directory, projectItemInclude); } public virtual IEnumerator GetEnumerator() { - var items = new ProjectItemsInsideProject(project); - return items.GetEnumerator(); + return GetProjectItems().GetEnumerator(); + } + + protected virtual IEnumerable GetProjectItems() + { + return new ProjectItemsInsideProject(Project); } internal virtual ProjectItem Item(string name) @@ -84,13 +89,14 @@ namespace ICSharpCode.PackageManagement.EnvDTE return item; } } - return null; + throw new ArgumentException("Unable to find item: " + name, "name"); } internal virtual ProjectItem Item(int index) { - var items = new ProjectItemsInsideProject(project); - return items.GetItem(index - 1); + return GetProjectItems() + .Skip(index - 1) + .First(); } public virtual ProjectItem Item(object index) @@ -103,25 +109,33 @@ namespace ICSharpCode.PackageManagement.EnvDTE public virtual ProjectItem AddFromDirectory(string directory) { - using (IProjectBrowserUpdater updater = project.CreateProjectBrowserUpdater()) { - ProjectItem directoryItem = project.AddDirectoryProjectItemUsingFullPath(directory); - project.Save(); + using (IProjectBrowserUpdater updater = Project.CreateProjectBrowserUpdater()) { + ProjectItem directoryItem = Project.AddDirectoryProjectItemUsingFullPath(directory); + Project.Save(); return directoryItem; } } public virtual ProjectItem AddFromFile(string fileName) { - using (IProjectBrowserUpdater updater = project.CreateProjectBrowserUpdater()) { - ProjectItem projectItem = project.AddFileProjectItemUsingFullPath(fileName); - project.Save(); + using (IProjectBrowserUpdater updater = Project.CreateProjectBrowserUpdater()) { + ProjectItem projectItem = AddFileProjectItemToProject(fileName); + Project.Save(); fileService.ParseFile(fileName); return projectItem; } } + /// + /// Adds a file to the project with this ProjectItems as its parent. + /// + protected virtual ProjectItem AddFileProjectItemToProject(string fileName) + { + return Project.AddFileProjectItemUsingFullPath(fileName); + } + public virtual int Count { - get { return new ProjectItemsInsideProject(project).Count; } + get { return GetProjectItems().Count(); } } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItemsInsideProject.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItemsInsideProject.cs index 53ef0fa3ff..9288b193a1 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItemsInsideProject.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/ProjectItemsInsideProject.cs @@ -2,7 +2,6 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; -using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; @@ -12,7 +11,7 @@ using ICSharpCode.SharpDevelop.Project; namespace ICSharpCode.PackageManagement.EnvDTE { - public class ProjectItemsInsideProject : IEnumerable + public class ProjectItemsInsideProject : EnumerableProjectItems { Project project; Dictionary directoriesIncluded = new Dictionary(); @@ -22,17 +21,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE this.project = project; } - public IEnumerator GetEnumerator() - { - List projectItems = GetProjectItems().ToList(); - return projectItems.GetEnumerator(); - } - - internal virtual int Count { - get { return GetProjectItems().Count(); } - } - - IEnumerable GetProjectItems() + protected override IEnumerable GetProjectItems() { foreach (SD.ProjectItem item in project.MSBuildProject.Items) { ProjectItem projectItem = ConvertToProjectItem(item); @@ -45,7 +34,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE ProjectItem ConvertToProjectItem(SD.ProjectItem item) { var fileItem = item as FileProjectItem; - if (fileItem != null) { + if ((fileItem != null) && !fileItem.IsDependentUponAnotherFile()) { return ConvertFileToProjectItem(fileItem); } return null; @@ -128,7 +117,7 @@ namespace ICSharpCode.PackageManagement.EnvDTE { var directoryItem = new FileProjectItem(project.MSBuildProject, ItemType.Folder); directoryItem.Include = directoryName; - return new ProjectItem(project, directoryItem) { Kind = Constants.VsProjectItemKindPhysicalFolder }; + return new ProjectItem(project, directoryItem) { Kind = Constants.vsProjectItemKindPhysicalFolder }; } string GetFirstSubDirectoryName(string include) @@ -136,16 +125,5 @@ namespace ICSharpCode.PackageManagement.EnvDTE string[] directoryNames = include.Split('\\'); return directoryNames[0]; } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - internal ProjectItem GetItem(int index) - { - List projectItems = GetProjectItems().ToList(); - return projectItems[index]; - } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Projects.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Projects.cs index cd533e8255..c60763915b 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Projects.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Projects.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; using SD = ICSharpCode.SharpDevelop.Project; namespace ICSharpCode.PackageManagement.EnvDTE @@ -16,18 +17,18 @@ namespace ICSharpCode.PackageManagement.EnvDTE { this.projectService = projectService; } - - public IEnumerator GetEnumerator() - { - return GetProjectsInSolution().GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - IEnumerable GetProjectsInSolution() + + public IEnumerator GetEnumerator() + { + return GetProjectsInSolution().GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerable GetProjectsInSolution() { foreach (SD.MSBuildBasedProject msbuildProject in GetOpenMSBuildProjects()) { yield return new Project(msbuildProject); @@ -38,5 +39,19 @@ namespace ICSharpCode.PackageManagement.EnvDTE { return projectService.GetOpenProjects(); } + + /// + /// Index of 1 returns the first project. + /// + public Project Item(int index) + { + return GetProjectsInSolution() + .Skip(index - 1) + .First(); + } + + public int Count { + get { return GetProjectsInSolution().Count(); } + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Solution.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Solution.cs index 4959e2f86d..1b095a7b34 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Solution.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Solution.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using ICSharpCode.SharpDevelop.Project; using SD = ICSharpCode.SharpDevelop.Project; namespace ICSharpCode.PackageManagement.EnvDTE @@ -44,9 +45,15 @@ namespace ICSharpCode.PackageManagement.EnvDTE projectService.Save(solution); } - internal bool IsSameSolution(SD.Solution solution) + public ProjectItem FindProjectItem(string fileName) { - throw new NotImplementedException(); + foreach (Project project in Projects) { + ProjectItem item = project.FindProjectItem(fileName); + if (item != null) { + return item; + } + } + return null; } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Window.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Window.cs new file mode 100644 index 0000000000..6c7f06e374 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/Window.cs @@ -0,0 +1,14 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public class Window : MarshalByRefObject + { + public Window() + { + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMClassKind.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMClassKind.cs new file mode 100644 index 0000000000..05c70f5c68 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMClassKind.cs @@ -0,0 +1,13 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public enum vsCMClassKind + { + vsCMClassKindMainClass = 1, + vsCMClassKindPartialClass = 4 + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMFunction.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMFunction.cs index 56de6e10f4..f74bc36afe 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMFunction.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMFunction.cs @@ -7,6 +7,8 @@ namespace ICSharpCode.PackageManagement.EnvDTE { public enum vsCMFunction { - vsCMFunctionFunction = 128 + vsCMFunctionOther = 0, + vsCMFunctionConstructor = 1, + vsCMFunctionFunction = 128 } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMOverrideKind.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMOverrideKind.cs new file mode 100644 index 0000000000..83d54ec1a1 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMOverrideKind.cs @@ -0,0 +1,17 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public enum vsCMOverrideKind + { + vsCMOverrideKindNone = 0, + vsCMOverrideKindAbstract = 1, + vsCMOverrideKindVirtual = 2, + vsCMOverrideKindOverride = 4, + vsCMOverrideKindNew = 8, + vsCMOverrideKindSealed = 16 + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMParameterKind.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMParameterKind.cs new file mode 100644 index 0000000000..8ffd82a8d2 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMParameterKind.cs @@ -0,0 +1,17 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public enum vsCMParameterKind + { + vsCMParameterKindNone = 0, + vsCMParameterKindIn = 1, + vsCMParameterKindRef = 2, + vsCMParameterKindOut = 4, + vsCMParameterKindOptional = 8, + vsCMParameterKindParamArray = 16 + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMTypeRef.cs b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMTypeRef.cs new file mode 100644 index 0000000000..670eb8549d --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/EnvDTE/vsCMTypeRef.cs @@ -0,0 +1,28 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.PackageManagement.EnvDTE +{ + public enum vsCMTypeRef + { + vsCMTypeRefOther = 0, + vsCMTypeRefCodeType = 1, + vsCMTypeRefArray = 2, + vsCMTypeRefVoid = 3, + vsCMTypeRefPointer = 4, + vsCMTypeRefString = 5, + vsCMTypeRefObject = 6, + vsCMTypeRefByte = 7, + vsCMTypeRefChar = 8, + vsCMTypeRefShort = 9, + vsCMTypeRefInt = 10, + vsCMTypeRefLong = 11, + vsCMTypeRefFloat = 12, + vsCMTypeRefDouble = 13, + vsCMTypeRefDecimal = 14, + vsCMTypeRefBool = 15, + vsCMTypeRefVariant = 16 + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/IClassKindUpdater.cs b/src/AddIns/Misc/PackageManagement/Project/Src/IClassKindUpdater.cs new file mode 100644 index 0000000000..85abf2fca7 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/IClassKindUpdater.cs @@ -0,0 +1,12 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.PackageManagement +{ + public interface IClassKindUpdater + { + void MakeClassPartial(); + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/IMethodOrPropertyExtensions.cs b/src/AddIns/Misc/PackageManagement/Project/Src/IMethodOrPropertyExtensions.cs index aea93f505e..fb688063b8 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/IMethodOrPropertyExtensions.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/IMethodOrPropertyExtensions.cs @@ -25,5 +25,23 @@ namespace ICSharpCode.PackageManagement { return method.DeclaringType.ClassType == ClassType.Interface; } + + public static bool IsConstructor(this IMethodOrProperty methodOrProperty) + { + var method = methodOrProperty as IMethod; + if (method != null) { + return method.IsConstructor; + } + return false; + } + + public static bool HasTypeParameters(this IMethodOrProperty methodOrProperty) + { + var method = methodOrProperty as IMethod; + if ((method != null) && (method.TypeParameters != null)) { + return method.TypeParameters.Count > 0; + } + return false; + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementFileService.cs b/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementFileService.cs index 0dc8415f96..3dccaa8318 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementFileService.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementFileService.cs @@ -3,6 +3,7 @@ using System; using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Gui; namespace ICSharpCode.PackageManagement { @@ -11,6 +12,7 @@ namespace ICSharpCode.PackageManagement void RemoveFile(string path); void RemoveDirectory(string path); void OpenFile(string fileName); + IViewContent GetOpenFile(string fileName); void CopyFile(string oldFileName, string newFileName); bool FileExists(string fileName); string[] GetFiles(string path); diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementProjectService.cs b/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementProjectService.cs index 1dfb33be21..f6b5267be1 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementProjectService.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/IPackageManagementProjectService.cs @@ -25,9 +25,11 @@ namespace ICSharpCode.PackageManagement void Save(Solution solution); IEnumerable GetOpenProjects(); - + IProjectContent GetProjectContent(IProject project); - + IProjectBrowserUpdater CreateProjectBrowserUpdater(); + + string GetDefaultCustomToolForFileName(FileProjectItem projectItem); } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/IVirtualMethodUpdater.cs b/src/AddIns/Misc/PackageManagement/Project/Src/IVirtualMethodUpdater.cs new file mode 100644 index 0000000000..1333a789ca --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/IVirtualMethodUpdater.cs @@ -0,0 +1,15 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.PackageManagement +{ + /// + /// Used to update a method's source code and make the method virtual. + /// + public interface IVirtualMethodUpdater + { + void MakeMethodVirtual(); + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementFileService.cs b/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementFileService.cs index 5545777835..902c0b7a5f 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementFileService.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementFileService.cs @@ -41,6 +41,15 @@ namespace ICSharpCode.PackageManagement } } + public IViewContent GetOpenFile(string fileName) + { + if (WorkbenchSingleton.InvokeRequired) { + return WorkbenchSingleton.SafeThreadFunction(() => GetOpenFile(fileName)); + } else { + return FileService.GetOpenFile(fileName); + } + } + public void CopyFile(string oldFileName, string newFileName) { if (WorkbenchSingleton.InvokeRequired) { diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementProjectService.cs b/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementProjectService.cs index 9c19c31d58..b0acff35dd 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementProjectService.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementProjectService.cs @@ -3,6 +3,8 @@ using System; using System.Collections.Generic; +using System.Linq; + using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Gui; @@ -109,5 +111,10 @@ namespace ICSharpCode.PackageManagement { return new ThreadSafeProjectBrowserUpdater(); } + + public string GetDefaultCustomToolForFileName(FileProjectItem projectItem) + { + return CustomToolsService.GetCompatibleCustomToolNames(projectItem).FirstOrDefault(); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/SharpDevelopProjectSystem.cs b/src/AddIns/Misc/PackageManagement/Project/Src/SharpDevelopProjectSystem.cs index e6a387c059..cb22695907 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/SharpDevelopProjectSystem.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/SharpDevelopProjectSystem.cs @@ -212,8 +212,9 @@ namespace ICSharpCode.PackageManagement FileProjectItem CreateFileProjectItem(string path) { ItemType itemType = project.GetDefaultItemType(path); - FileProjectItem fileItem = new FileProjectItem(project, itemType); + var fileItem = new FileProjectItem(project, itemType); fileItem.FileName = path; + fileItem.CustomTool = projectService.GetDefaultCustomToolForFileName(fileItem); return fileItem; } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/UpdateProjectBrowserFileNodesVisitor.cs b/src/AddIns/Misc/PackageManagement/Project/Src/UpdateProjectBrowserFileNodesVisitor.cs index 2c67688086..12edaef7a8 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/UpdateProjectBrowserFileNodesVisitor.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/UpdateProjectBrowserFileNodesVisitor.cs @@ -10,6 +10,7 @@ using System.Windows.Forms; using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Project; +using DTE = ICSharpCode.PackageManagement.EnvDTE; namespace ICSharpCode.PackageManagement { @@ -48,7 +49,9 @@ namespace ICSharpCode.PackageManagement return null; if (IsImmediateParentForNewFile(directoryNode)) { - if (IsChildFileNodeMissingForNewFile(directoryNode)) { + if (IsNewFileIsDependentUponAnotherFile()) { + base.Visit(directoryNode, data); + } else if (IsChildFileNodeMissingForNewFile(directoryNode)) { AddFileOrDirectoryNodeTo(directoryNode); } } else if (IsChildDirectoryNodeMissingForNewFile(directoryNode)) { @@ -79,6 +82,11 @@ namespace ICSharpCode.PackageManagement return FileUtility.IsBaseDirectory(DirectoryForNewFileAddedToProject, directoryNode.Directory); } + bool IsNewFileIsDependentUponAnotherFile() + { + return !String.IsNullOrEmpty(newFileAddedToProject.DependentUpon); + } + string GetDirectoryForFileAddedToProject() { return Path.GetDirectoryName(newFileAddedToProject.FileName); @@ -121,10 +129,10 @@ namespace ICSharpCode.PackageManagement AddFileNodeTo(directoryNode); } } - - void AddFileNodeTo(TreeNode node) + + void AddFileNodeTo(TreeNode node, FileNodeStatus status = FileNodeStatus.InProject) { - var fileNode = new FileNode(newFileAddedToProject.FileName, FileNodeStatus.InProject); + var fileNode = new FileNode(newFileAddedToProject.FileName, status); fileNode.InsertSorted(node); } @@ -169,5 +177,21 @@ namespace ICSharpCode.PackageManagement { return parentNode.AllNodes.OfType(); } + + public override object Visit(FileNode fileNode, object data) + { + if (IsNewFileIsDependentUponAnotherFile()) { + if (IsImmediateParentForNewFile(fileNode)) { + AddFileNodeTo(fileNode, FileNodeStatus.BehindFile); + return null; + } + } + return base.Visit(fileNode, data); + } + + bool IsImmediateParentForNewFile(FileNode fileNode) + { + return DTE.FileProjectItemExtensions.IsDependentUponFileName(newFileAddedToProject, fileNode.FileName); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/VirtualMethodUpdater.cs b/src/AddIns/Misc/PackageManagement/Project/Src/VirtualMethodUpdater.cs new file mode 100644 index 0000000000..37daf016e1 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/VirtualMethodUpdater.cs @@ -0,0 +1,67 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Dom.Refactoring; + +namespace ICSharpCode.PackageManagement +{ + public class VirtualMethodUpdater : IVirtualMethodUpdater + { + public VirtualMethodUpdater(IMethod method) + : this(method, new DocumentLoader()) + { + } + + public VirtualMethodUpdater(IMethod method, IDocumentLoader documentLoader) + { + this.Method = method; + this.DocumentLoader = documentLoader; + } + + IMethod Method { get; set; } + IDocumentLoader DocumentLoader { get; set; } + IRefactoringDocument Document { get; set; } + + public void MakeMethodVirtual() + { + if (Method.IsVirtual) + return; + + OpenFileContainingMethod(); + int offset = GetVirtualKeywordInsertOffset(); + InsertVirtualKeyword(offset); + } + + void OpenFileContainingMethod() + { + Document = DocumentLoader.LoadRefactoringDocument(Method.CompilationUnit.FileName); + } + + int GetVirtualKeywordInsertOffset() + { + IRefactoringDocumentLine line = Document.GetLine(Method.Region.BeginLine); + int offset = line.Text.IndexOf("public ", StringComparison.OrdinalIgnoreCase); + if (offset >= 0) { + int publicKeywordLength = 6; + return offset + line.Offset + publicKeywordLength + 1; + } + throw new ApplicationException("Unable to find 'method' declaration."); + } + + void InsertVirtualKeyword(int offset) + { + string virtualKeyword = GetLanguageSpecificVirtualKeyword(); + Document.Insert(offset, virtualKeyword + " "); + } + + string GetLanguageSpecificVirtualKeyword() + { + if (Method.ProjectContent.Language == LanguageProperties.VBNet) { + return "Overridable"; + } + return "virtual"; + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/VisualStudio/SDTE.cs b/src/AddIns/Misc/PackageManagement/Project/Src/VisualStudio/SDTE.cs new file mode 100644 index 0000000000..ee1e471937 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/VisualStudio/SDTE.cs @@ -0,0 +1,15 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.PackageManagement.EnvDTE; + +namespace Microsoft.VisualStudio.Shell.Interop +{ + public class SDTE : DTE + { + public SDTE() + { + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj index df836b2955..750344421d 100644 --- a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj +++ b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj @@ -76,26 +76,32 @@ Properties\GlobalAssemblyInfo.cs + + + + + + @@ -110,6 +116,7 @@ + @@ -120,6 +127,7 @@ + @@ -178,6 +186,7 @@ + diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/ClassKindUpdaterTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/ClassKindUpdaterTests.cs new file mode 100644 index 0000000000..54a92eeb0b --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/ClassKindUpdaterTests.cs @@ -0,0 +1,165 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.PackageManagement; +using ICSharpCode.SharpDevelop.Dom.Refactoring; +using NUnit.Framework; +using PackageManagement.Tests.Helpers; +using Rhino.Mocks; + +namespace PackageManagement.Tests +{ + [TestFixture] + public class ClassKindUpdaterTests + { + ClassKindUpdater updater; + ClassHelper classHelper; + IRefactoringDocument document; + IDocumentLoader documentLoader; + + [SetUp] + public void Init() + { + classHelper = new ClassHelper(); + document = MockRepository.GenerateStub(); + documentLoader = MockRepository.GenerateStub(); + } + + void CreatePublicCSharpClass() + { + classHelper.CreatePublicClass("MyClass"); + classHelper.ProjectContentHelper.ProjectContentIsForCSharpProject(); + } + + void CreatePublicVisualBasicClass() + { + classHelper.CreatePublicClass("MyClass"); + classHelper.ProjectContentHelper.ProjectContentIsForVisualBasicProject(); + } + + void SetDocumentFileName(string fileName) + { + documentLoader.Stub(loader => loader.LoadRefactoringDocument(fileName)).Return(document); + } + + void CreateClassKindUpdater() + { + updater = new ClassKindUpdater(classHelper.Class, documentLoader); + } + + void SetClassFileName(string fileName) + { + classHelper.SetClassFileName(fileName); + SetDocumentFileName(fileName); + } + + void SetClassDeclarationLineWithOffset(int line, string text, int offset) + { + classHelper.SetRegionBeginLine(line); + SetDocumentLineText(line, text, offset); + } + + void SetClassDeclarationLine(int line, string text) + { + SetClassDeclarationLineWithOffset(line, text, 0); + } + + void SetDocumentLineText(int lineNumber, string text, int offset) + { + IRefactoringDocumentLine documentLine = MockRepository.GenerateStub(); + documentLine.Stub(line => line.Text).Return(text); + documentLine.Stub(line => line.Offset).Return(offset); + document.Stub(doc => doc.GetLine(lineNumber)).Return(documentLine); + } + + [Test] + public void MakeClassPartial_PublicCSharpClassWithNoOtherModifiers_OpensFileContainingClassInSharpDevelop() + { + CreatePublicCSharpClass(); + CreateClassKindUpdater(); + string fileName = @"d:\projects\MyProject\MyClass.cs"; + SetClassFileName(fileName); + SetClassDeclarationLine(1, "public class MyClass"); + + updater.MakeClassPartial(); + + documentLoader.AssertWasCalled(loader => loader.LoadRefactoringDocument(fileName)); + } + + [Test] + public void MakeClassPartial_PublicCSharpClassWithNoOtherModifiers_AddsPartialKeywordToClassDefinition() + { + CreatePublicCSharpClass(); + CreateClassKindUpdater(); + SetClassFileName(@"d:\projects\MyProject\MyClass.cs"); + SetClassDeclarationLine(1, "public class MyClass"); + + updater.MakeClassPartial(); + + document.AssertWasCalled(doc => doc.Insert(7, "partial ")); + } + + [Test] + public void MakeClassPartial_PublicCSharpClassThatIsAlreadyPartial_ClassDefinitionIsUnchanged() + { + CreatePublicCSharpClass(); + CreateClassKindUpdater(); + classHelper.MakeClassPartial(); + SetClassFileName(@"d:\projects\MyProject\MyClass.cs"); + SetClassDeclarationLine(1, "public class MyClass"); + + updater.MakeClassPartial(); + + document.AssertWasNotCalled(doc => doc.Insert(Arg.Is.Anything, Arg.Is.Anything)); + } + + [Test] + public void MakeClassPartial_PublicVisualBasicClassWithNoOtherModifiers_AddsVisualBasicPartialKeywordToClassDefinition() + { + CreatePublicVisualBasicClass(); + CreateClassKindUpdater(); + SetClassFileName(@"d:\projects\MyProject\MyClass.vb"); + SetClassDeclarationLine(1, "Public Class MyClass"); + + updater.MakeClassPartial(); + + document.AssertWasCalled(doc => doc.Insert(7, "Partial ")); + } + + [Test] + public void MakeClassPartial_NoClassKeywordInClassDeclarationLine_ExceptionIsThrown() + { + CreatePublicCSharpClass(); + CreateClassKindUpdater(); + SetClassFileName(@"d:\projects\MyProject\test.cs"); + SetClassDeclarationLine(1, "public test"); + + Assert.Throws(() => updater.MakeClassPartial()); + } + + [Test] + public void MakeClassPartial_NoClassKeywordButClassNameIncludesClassKeyword_ExceptionIsThrown() + { + CreatePublicCSharpClass(); + CreateClassKindUpdater(); + SetClassFileName(@"d:\projects\MyProject\MyClass.cs"); + SetClassDeclarationLine(1, "public MyClass"); + + Assert.Throws(() => updater.MakeClassPartial()); + } + + [Test] + public void MakeClassPartial_PublicCSharpClassNotOnFirstLine_AddsPartialKeywordToClassDefinitionAtCorrectOffset() + { + CreatePublicCSharpClass(); + CreateClassKindUpdater(); + SetClassFileName(@"d:\projects\MyProject\MyClass.cs"); + SetClassDeclarationLineWithOffset(1, "public class MyClass", offset: 10); + + updater.MakeClassPartial(); + + document.AssertWasCalled(doc => doc.Insert(17, "partial ")); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs index 1f69713ee0..90056df6c2 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeClass2Tests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using ICSharpCode.PackageManagement; using ICSharpCode.PackageManagement.EnvDTE; using ICSharpCode.SharpDevelop.Dom; using NUnit.Framework; @@ -16,6 +17,7 @@ namespace PackageManagement.Tests.EnvDTE { CodeClass2 codeClass; ClassHelper helper; + IClassKindUpdater classKindUpdater; void CreateProjectContent() { @@ -42,7 +44,8 @@ namespace PackageManagement.Tests.EnvDTE void CreateClass() { - codeClass = new CodeClass2(helper.ProjectContentHelper.ProjectContent, helper.Class); + classKindUpdater = MockRepository.GenerateStub(); + codeClass = new CodeClass2(helper.ProjectContentHelper.ProjectContent, helper.Class, classKindUpdater); } void AddInterfaceToProjectContent(string fullName) @@ -85,6 +88,26 @@ namespace PackageManagement.Tests.EnvDTE helper.AddFieldToClass(fullyQualifiedName); } + void ClassIsAbstract() + { + helper.MakeClassAbstract(); + } + + void ClassIsPartial() + { + helper.MakeClassPartial(); + } + + void ClassIsGeneric() + { + helper.SetDotNetName("MyClass`1"); + } + + void ClassIsNotGeneric() + { + helper.SetDotNetName("MyClass"); + } + [Test] public void Language_CSharpProject_ReturnsCSharpModelLanguage() { @@ -191,7 +214,7 @@ namespace PackageManagement.Tests.EnvDTE AddMethodToClass("MyClass.MyMethod"); CodeElements codeElements = codeClass.Members; - CodeFunction codeFunction = codeElements.FirstCodeFunctionOrDefault(); + CodeFunction2 codeFunction = codeElements.FirstCodeFunction2OrDefault(); Assert.AreEqual(1, codeElements.Count); Assert.AreEqual("MyMethod", codeFunction.Name); @@ -249,6 +272,19 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual("MyNamespace.Test", codeNamespace.FullName); } + [Test] + public void Namespace_PublicClassAndNamespaceNameChecked_ReturnsFullyQualifiedClassNamespace() + { + CreateProjectContent(); + helper.CreatePublicClass("MyNamespace.Test.MyClass"); + helper.AddClassNamespace("MyNamespace.Test"); + CreateClass(); + + CodeNamespace codeNamespace = codeClass.Namespace; + + Assert.AreEqual("MyNamespace.Test", codeNamespace.Name); + } + [Test] public void PartialClasses_ClassIsNotPartial_ReturnsClass() { @@ -278,5 +314,95 @@ namespace PackageManagement.Tests.EnvDTE bool contains = properties.Contains(property2); Assert.IsTrue(contains); } + + [Test] + public void IsAbstract_ClassIsAbstract_ReturnsTrue() + { + CreateProjectContent(); + CreatePublicClass("MyClass"); + ClassIsAbstract(); + + bool isAbstract = codeClass.IsAbstract; + + Assert.IsTrue(isAbstract); + } + + [Test] + public void IsAbstract_ClassIsNotAbstract_ReturnsFalse() + { + CreateProjectContent(); + CreatePublicClass("MyClass"); + + bool isAbstract = codeClass.IsAbstract; + + Assert.IsFalse(isAbstract); + } + + [Test] + public void ClassKind_ClassIsPartial_ReturnsPartialClassKind() + { + CreateProjectContent(); + CreatePublicClass("MyClass"); + ClassIsPartial(); + + vsCMClassKind kind = codeClass.ClassKind; + + Assert.AreEqual(vsCMClassKind.vsCMClassKindPartialClass, kind); + } + + [Test] + public void ClassKind_ClassIsNotPartial_ReturnsMainClassKind() + { + CreateProjectContent(); + CreatePublicClass("MyClass"); + + vsCMClassKind kind = codeClass.ClassKind; + + Assert.AreEqual(vsCMClassKind.vsCMClassKindMainClass, kind); + } + + [Test] + public void IsGeneric_ClassIsGeneric_ReturnsTrue() + { + CreateProjectContent(); + CreatePublicClass("MyClass"); + ClassIsGeneric(); + + bool generic = codeClass.IsGeneric; + + Assert.IsTrue(generic); + } + + [Test] + public void IsGeneric_ClassIsNotGeneric_ReturnsFalse() + { + CreateProjectContent(); + CreatePublicClass("MyClass"); + ClassIsNotGeneric(); + + bool generic = codeClass.IsGeneric; + + Assert.IsFalse(generic); + } + + [Test] + public void ClassKind_ChangeClassToBePartial_UsesClassKindUpdaterToModifyClass() + { + CreateProjectContent(); + CreatePublicClass("MyClass"); + + codeClass.ClassKind = vsCMClassKind.vsCMClassKindPartialClass; + + classKindUpdater.AssertWasCalled(updater => updater.MakeClassPartial()); + } + + [Test] + public void ClassKind_ChangeClassToBeMainClass_ThrowsNotImplementedException() + { + CreateProjectContent(); + CreatePublicClass("MyClass"); + + Assert.Throws(() => codeClass.ClassKind = vsCMClassKind.vsCMClassKindMainClass); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunction2Tests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunction2Tests.cs new file mode 100644 index 0000000000..ce4cac4b7f --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunction2Tests.cs @@ -0,0 +1,131 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.PackageManagement.EnvDTE; +using NUnit.Framework; +using PackageManagement.Tests.Helpers; + +namespace PackageManagement.Tests.EnvDTE +{ + [TestFixture] + public class CodeFunction2Tests + { + CodeFunction2 codeFunction; + MethodHelper helper; + + [SetUp] + public void Init() + { + helper = new MethodHelper(); + } + + void CreatePublicFunction(string name) + { + helper.CreatePublicMethod(name); + CreateFunction(); + } + + void CreateFunction() + { + codeFunction = new CodeFunction2(helper.Method); + } + + [Test] + public void OverrideKind_OrdinaryMethod_ReturnsNone() + { + CreatePublicFunction("MyClass.MyFunction"); + + vsCMOverrideKind kind = codeFunction.OverrideKind; + + Assert.AreEqual(vsCMOverrideKind.vsCMOverrideKindNone, kind); + } + + [Test] + public void OverrideKind_AbstractMethod_ReturnsAbstract() + { + CreatePublicFunction("MyClass.MyFunction"); + helper.MakeMethodAbstract(); + + vsCMOverrideKind kind = codeFunction.OverrideKind; + + Assert.AreEqual(vsCMOverrideKind.vsCMOverrideKindAbstract, kind); + } + + [Test] + public void OverrideKind_VirtualMethod_ReturnsVirtual() + { + CreatePublicFunction("MyClass.MyFunction"); + helper.MakeMethodVirtual(); + + vsCMOverrideKind kind = codeFunction.OverrideKind; + + Assert.AreEqual(vsCMOverrideKind.vsCMOverrideKindVirtual, kind); + } + + [Test] + public void OverrideKind_MethodOverride_ReturnsOverride() + { + CreatePublicFunction("MyClass.MyFunction"); + helper.MakeMethodOverride(); + + vsCMOverrideKind kind = codeFunction.OverrideKind; + + Assert.AreEqual(vsCMOverrideKind.vsCMOverrideKindOverride, kind); + } + + [Test] + public void OverrideKind_SealedMethod_ReturnsSealed() + { + CreatePublicFunction("MyClass.MyFunction"); + helper.MakeMethodSealed(); + + vsCMOverrideKind kind = codeFunction.OverrideKind; + + Assert.AreEqual(vsCMOverrideKind.vsCMOverrideKindSealed, kind); + } + + [Test] + public void OverrideKind_MethodHiddenByNewKeyword_ReturnsNew() + { + CreatePublicFunction("MyClass.MyFunction"); + helper.MakeMethodNewOverride(); + + vsCMOverrideKind kind = codeFunction.OverrideKind; + + Assert.AreEqual(vsCMOverrideKind.vsCMOverrideKindNew, kind); + } + + [Test] + public void IsGeneric_MethodHasTypeParameter_ReturnsTrue() + { + CreatePublicFunction("MyClass.MyFunction"); + helper.AddTypeParameter("TResult"); + + bool generic = codeFunction.IsGeneric; + + Assert.IsTrue(generic); + } + + [Test] + public void IsGeneric_MethodHasTypeParameters_ReturnsFalse() + { + CreatePublicFunction("MyClass.MyFunction"); + helper.NoTypeParameters(); + + bool generic = codeFunction.IsGeneric; + + Assert.IsFalse(generic); + } + + [Test] + public void IsGeneric_MethodTypeParametersIsNull_ReturnsFalse() + { + CreatePublicFunction("MyClass.MyFunction"); + + bool generic = codeFunction.IsGeneric; + + Assert.IsFalse(generic); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs index 9fd2169bf4..8fcd19c0cd 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeFunctionTests.cs @@ -2,6 +2,7 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using ICSharpCode.PackageManagement; using ICSharpCode.PackageManagement.EnvDTE; using ICSharpCode.SharpDevelop.Dom; using NUnit.Framework; @@ -15,6 +16,7 @@ namespace PackageManagement.Tests.EnvDTE { CodeFunction codeFunction; MethodHelper helper; + IVirtualMethodUpdater methodUpdater; [SetUp] public void Init() @@ -36,7 +38,14 @@ namespace PackageManagement.Tests.EnvDTE void CreateFunction() { - codeFunction = new CodeFunction(helper.Method); + methodUpdater = MockRepository.GenerateStub(); + codeFunction = new CodeFunction(helper.Method, null, methodUpdater); + } + + void CreatePublicConstructor(string name) + { + helper.CreatePublicConstructor(name); + CreateFunction(); } void SetDeclaringTypeAsInterface(string name) @@ -64,6 +73,31 @@ namespace PackageManagement.Tests.EnvDTE helper.AddReturnTypeToMethod(type); } + void MakeMethodStatic() + { + helper.MakeMethodStatic(); + } + + void MakeMethodAbstract() + { + helper.MakeMethodAbstract(); + } + + void MakeMethodVirtual() + { + helper.MakeMethodVirtual(); + } + + void AddMethodAttribute(string attributeTypeName) + { + helper.AddAttributeToMethod(attributeTypeName); + } + + void MakeMethodOverridable() + { + helper.MakeMethodOverridable(); + } + [Test] public void Access_PublicFunction_ReturnsPublic() { @@ -171,12 +205,12 @@ namespace PackageManagement.Tests.EnvDTE } [Test] - public void Parameters_MethodHasOneParameter_ReturnsOneCodeParameter() + public void Parameters_MethodHasOneParameter_ReturnsOneCodeParameter2() { AddParameterToMethod("test"); CreatePublicFunction("MyClass.MyMethod"); - CodeParameter parameter = codeFunction.Parameters.FirstCodeParameterOrDefault(); + CodeParameter2 parameter = codeFunction.Parameters.FirstCodeParameter2OrDefault(); Assert.AreEqual("test", parameter.Name); } @@ -246,5 +280,121 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual(codeFunction, typeRef.Parent); } + + [Test] + public void FunctionKind_ClassMethod_ReturnsFunctionKind() + { + CreatePublicFunction("MyClass.MyFunction"); + + vsCMFunction kind = codeFunction.FunctionKind; + + Assert.AreEqual(vsCMFunction.vsCMFunctionFunction, kind); + } + + [Test] + public void FunctionKind_ClassConstructor_ReturnsConstructorKind() + { + CreatePublicConstructor("MyClass.MyClass"); + + vsCMFunction kind = codeFunction.FunctionKind; + + Assert.AreEqual(vsCMFunction.vsCMFunctionConstructor, kind); + } + + [Test] + public void IsShared_StaticMethod_ReturnsTrue() + { + CreatePublicFunction("MyClass.MyFunction"); + MakeMethodStatic(); + + bool shared = codeFunction.IsShared; + + Assert.IsTrue(shared); + } + + [Test] + public void IsShared_MethodIsNotStatic_ReturnsFalse() + { + CreatePublicFunction("MyClass.MyFunction"); + + bool shared = codeFunction.IsShared; + + Assert.IsFalse(shared); + } + + [Test] + public void MustImplement_AbstractMethod_ReturnsTrue() + { + CreatePublicFunction("MyClass.MyFunction"); + MakeMethodAbstract(); + + bool mustImplement = codeFunction.MustImplement; + + Assert.IsTrue(mustImplement); + } + + [Test] + public void MustImplement_MethodIsNotAbstract_ReturnsFalse() + { + CreatePublicFunction("MyClass.MyFunction"); + + bool mustImplement = codeFunction.MustImplement; + + Assert.IsFalse(mustImplement); + } + + [Test] + public void CanOverride_MethodIsOverridable_ReturnsTrue() + { + CreatePublicFunction("MyClass.MyFunction"); + MakeMethodOverridable(); + + bool canOverride = codeFunction.CanOverride; + + Assert.IsTrue(canOverride); + } + + [Test] + public void CanOverride_MethodIsNotAbstractOrVirtual_ReturnsFalse() + { + CreatePublicFunction("MyClass.MyFunction"); + + bool canOverride = codeFunction.CanOverride; + + Assert.IsFalse(canOverride); + } + + [Test] + public void Attributes_MethodHasOneAttribute_ReturnsOneAttribute() + { + CreatePublicFunction("MyClass.MyFunction"); + AddMethodAttribute("System.ObsoleteAttribute"); + + CodeElements attributes = codeFunction.Attributes; + + CodeAttribute2 attribute = attributes.FirstCodeAttribute2OrDefault(); + Assert.AreEqual(1, attributes.Count); + Assert.AreEqual("System.ObsoleteAttribute", attribute.FullName); + } + + [Test] + public void CanOverride_SetToTrueForFunction_VirtualKeywordAddedToFunction() + { + CreatePublicFunction("MyClass.MyFunction"); + + codeFunction.CanOverride = true; + + methodUpdater.AssertWasCalled(updater => updater.MakeMethodVirtual()); + } + + [Test] + public void CanOverride_SetToFalseForFunction_VirtualKeywordNotAddedToFunction() + { + CreatePublicFunction("MyClass.MyFunction"); + + codeFunction.CanOverride = false; + + methodUpdater.AssertWasNotCalled(updater => updater.MakeMethodVirtual()); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameter2Tests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameter2Tests.cs new file mode 100644 index 0000000000..ad0b6d934d --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameter2Tests.cs @@ -0,0 +1,93 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.PackageManagement.EnvDTE; +using NUnit.Framework; +using PackageManagement.Tests.Helpers; + +namespace PackageManagement.Tests.EnvDTE +{ + [TestFixture] + public class CodeParameter2Tests + { + ParameterHelper helper; + CodeParameter2 parameter; + + [SetUp] + public void Init() + { + helper = new ParameterHelper(); + } + + void CreateParameter() + { + parameter = new CodeParameter2(null, helper.Parameter); + } + + [Test] + public void ParameterKind_NormalParameter_ReturnsNone() + { + CreateParameter(); + + vsCMParameterKind kind = parameter.ParameterKind; + + Assert.AreEqual(vsCMParameterKind.vsCMParameterKindNone, kind); + } + + [Test] + public void ParameterKind_OptionalParameter_ReturnsOptional() + { + CreateParameter(); + helper.MakeOptionalParameter(); + + vsCMParameterKind kind = parameter.ParameterKind; + + Assert.AreEqual(vsCMParameterKind.vsCMParameterKindOptional, kind); + } + + [Test] + public void ParameterKind_OutParameter_ReturnsOut() + { + CreateParameter(); + helper.MakeOutParameter(); + + vsCMParameterKind kind = parameter.ParameterKind; + + Assert.AreEqual(vsCMParameterKind.vsCMParameterKindOut, kind); + } + + [Test] + public void ParameterKind_RefParameter_ReturnsRef() + { + CreateParameter(); + helper.MakeRefParameter(); + + vsCMParameterKind kind = parameter.ParameterKind; + + Assert.AreEqual(vsCMParameterKind.vsCMParameterKindRef, kind); + } + + [Test] + public void ParameterKind_ParamArrayParameter_ReturnsParamArray() + { + CreateParameter(); + helper.MakeParamArrayParameter(); + + vsCMParameterKind kind = parameter.ParameterKind; + + Assert.AreEqual(vsCMParameterKind.vsCMParameterKindParamArray, kind); + } + + [Test] + public void ParameterKind_InParameter_ReturnsIn() + { + CreateParameter(); + helper.MakeInParameter(); + + vsCMParameterKind kind = parameter.ParameterKind; + + Assert.AreEqual(vsCMParameterKind.vsCMParameterKindIn, kind); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameterTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameterTests.cs index 5fd217f712..f596afbfe9 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameterTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeParameterTests.cs @@ -4,17 +4,25 @@ using System; using ICSharpCode.PackageManagement.EnvDTE; using NUnit.Framework; +using PackageManagement.Tests.Helpers; namespace PackageManagement.Tests.EnvDTE { [TestFixture] public class CodeParameterTests { + ParameterHelper helper; CodeParameter parameter; + [SetUp] + public void Init() + { + helper = new ParameterHelper(); + } + void CreateParameter() { - parameter = new CodeParameter(null, null); + parameter = new CodeParameter(null, helper.Parameter); } [Test] @@ -26,5 +34,18 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual(vsCMElement.vsCMElementParameter, kind); } + + [Test] + public void Attributes_ParameterHasOneAttribute_ReturnsOneAttribute() + { + CreateParameter(); + helper.AddAttributeToParameter("System.Web.Mvc.BindAttribute"); + + CodeElements attributes = parameter.Attributes; + + CodeAttribute2 attribute = parameter.Attributes.FirstCodeAttribute2OrDefault(); + Assert.AreEqual(1, attributes.Count); + Assert.AreEqual("System.Web.Mvc.BindAttribute", attribute.FullName); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeTypeRef2Tests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeTypeRef2Tests.cs index 9855719155..68a2acad41 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeTypeRef2Tests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeTypeRef2Tests.cs @@ -187,5 +187,195 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual("Test.MyClass", name); } + + [Test] + public void TypeKind_ReturnTypeIsReferenceType_ReturnsClassType() + { + helper.CreateReturnType("Test.MyClass"); + AddUnderlyingClassToReturnType("Test.MyClass"); + helper.MakeReferenceType(); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefCodeType, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsNotReferenceType_ReturnsNonClassType() + { + helper.CreateReturnType("Test.MyClass"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefOther, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemVoid_ReturnsVoidType() + { + helper.CreateReturnType("System.Void"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefVoid, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemString_ReturnsStringType() + { + helper.CreateReturnType("System.String"); + helper.MakeReferenceType(); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefString, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemBoolean_ReturnsBooleanType() + { + helper.CreateReturnType("System.Boolean"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefBool, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemByte_ReturnsByteType() + { + helper.CreateReturnType("System.Byte"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefByte, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemChar_ReturnsCharType() + { + helper.CreateReturnType("System.Char"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefChar, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemDecimal_ReturnsDecimalType() + { + helper.CreateReturnType("System.Decimal"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefDecimal, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemDouble_ReturnsDoubleType() + { + helper.CreateReturnType("System.Double"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefDouble, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemSingle_ReturnsFloatType() + { + helper.CreateReturnType("System.Single"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefFloat, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemInt32_ReturnsIntType() + { + helper.CreateReturnType("System.Int32"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefInt, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemInt16_ReturnsShortType() + { + helper.CreateReturnType("System.Int16"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefShort, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemInt64_ReturnsLongType() + { + helper.CreateReturnType("System.Int64"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefLong, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemUInt32_ReturnsIntType() + { + helper.CreateReturnType("System.UInt32"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefInt, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemUInt16_ReturnsShortType() + { + helper.CreateReturnType("System.UInt16"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefShort, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemUInt64_ReturnsLongType() + { + helper.CreateReturnType("System.UInt64"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefLong, kind); + } + + [Test] + public void TypeKind_ReturnTypeIsSystemObject_ReturnsObjectType() + { + helper.CreateReturnType("System.Object"); + CreateCodeTypeRef2(); + + vsCMTypeRef kind = typeRef.TypeKind; + + Assert.AreEqual(vsCMTypeRef.vsCMTypeRefObject, kind); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeTypeTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeTypeTests.cs index 0615a38957..4935c36043 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeTypeTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/CodeTypeTests.cs @@ -46,7 +46,15 @@ namespace PackageManagement.Tests.EnvDTE SDProject.FileProjectItem AddFileToProjectAndProjectContent(TestableProject project, string fileName) { helper.CompilationUnitHelper.SetFileName(fileName); - return project.AddFile(fileName); + return project.AddFile(fileName); + } + + /// + /// Classes at the end of the array are at the top of the inheritance tree. + /// + void AddClassInheritanceTree(params string[] classNames) + { + helper.AddClassInheritanceTreeClassesOnly(classNames); } [Test] @@ -121,5 +129,70 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual("test.cs", item.Name); } + + [Test] + public void IsDerivedFrom_ClassFullyQualifiedNameMatchesTypeNameBeingChecked_ReturnsTrue() + { + CreateProjectContent(); + CreateClass("System.Web.Mvc.ActionResult"); + CreateCodeType(); + + bool derivedFrom = codeType.IsDerivedFrom("System.Web.Mvc.ActionResult"); + + Assert.IsTrue(derivedFrom); + } + + [Test] + public void IsDerivedFrom_ClassFullyQualifiedNameDoesNotMatcheTypeNameBeingChecked_ReturnsFalse() + { + CreateProjectContent(); + CreateClass("TestClass"); + AddClassInheritanceTree("System.Object"); + CreateCodeType(); + + bool derivedFrom = codeType.IsDerivedFrom("System.Web.Mvc.ActionResult"); + + Assert.IsFalse(derivedFrom); + } + + [Test] + public void IsDerivedFrom_ClassBaseTypeFullyQualifiedNameMatchesTypeName_ReturnsTrue() + { + CreateProjectContent(); + CreateClass("CustomActionResult"); + helper.AddBaseTypeToClass("System.Web.Mvc.ActionResult"); + CreateCodeType(); + + bool derivedFrom = codeType.IsDerivedFrom("System.Web.Mvc.ActionResult"); + + Assert.IsTrue(derivedFrom); + } + + [Test] + public void IsDerivedFrom_ClassHasTypeInClassInheritanceTreeButNotImmediateBaseType_ReturnsTrue() + { + CreateProjectContent(); + CreateClass("CustomActionResult"); + AddClassInheritanceTree("CustomActionResultBase", "System.Web.Mvc.ActionResult"); + CreateCodeType(); + + bool derivedFrom = codeType.IsDerivedFrom("System.Web.Mvc.ActionResult"); + + Assert.IsTrue(derivedFrom); + } + + [Test] + public void IsDerivedFrom_ClassHasClassInInheritanceTreeButNotImmediateParentAndClassBaseTypePropertyIsNotNull_ReturnsTrue() + { + CreateProjectContent(); + CreateClass("CustomActionResult"); + helper.AddBaseTypeToClass("CustomActionResultBase"); + AddClassInheritanceTree("CustomActionResultBase", "System.Web.Mvc.ActionResult"); + CreateCodeType(); + + bool derivedFrom = codeType.IsDerivedFrom("System.Web.Mvc.ActionResult"); + + Assert.IsTrue(derivedFrom); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/DocumentTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/DocumentTests.cs new file mode 100644 index 0000000000..0e85ea4dc0 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/DocumentTests.cs @@ -0,0 +1,59 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.PackageManagement.EnvDTE; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Gui; +using NUnit.Framework; +using Rhino.Mocks; + +namespace PackageManagement.Tests.EnvDTE +{ + [TestFixture] + public class DocumentTests + { + IViewContent view; + Document document; + OpenedFile openedFile; + + [SetUp] + public void Init() + { + openedFile = MockRepository.GenerateStub(); + view = MockRepository.GenerateStub(); + view.Stub(v => v.PrimaryFile).Return(openedFile); + } + + void CreateDocument(string fileName) + { + document = new Document(fileName, view); + } + + void OpenFileIsDirty() + { + openedFile.IsDirty = true; + } + + [Test] + public void Saved_SetToTrue_OpenFileIsDirtySetToFalse() + { + CreateDocument(@"d:\projects\MyProject\program.cs"); + OpenFileIsDirty(); + + document.Saved = true; + + Assert.IsFalse(openedFile.IsDirty); + } + + [Test] + public void Saved_SetToFalse_OpenFileIsDirtySetToTrue() + { + CreateDocument(@"d:\projects\MyProject\program.cs"); + + document.Saved = false; + + Assert.IsTrue(openedFile.IsDirty); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/EditPointTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/EditPointTests.cs index 83a02b3348..1cf28aa08b 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/EditPointTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/EditPointTests.cs @@ -69,7 +69,7 @@ namespace PackageManagement.Tests.EnvDTE void CreateMethodEditPoint() { - var codeFunction = new CodeFunction(methodHelper.Method, documentLoader); + var codeFunction = new CodeFunction(methodHelper.Method, documentLoader, null); TextPoint startPoint = codeFunction.GetStartPoint(); endPoint = codeFunction.GetEndPoint(); editPoint = startPoint.CreateEditPoint(); diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/FileCodeModel2Tests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/FileCodeModel2Tests.cs index ec7dcb8d5a..8f78b1b84e 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/FileCodeModel2Tests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/FileCodeModel2Tests.cs @@ -56,6 +56,11 @@ namespace PackageManagement.Tests.EnvDTE return fileCodeModel.CodeElements.FirstCodeImportOrDefault(); } + CodeNamespace GetFirstCodeNamespaceFromCodeElements() + { + return fileCodeModel.CodeElements.FirstCodeNamespaceOrDefault(); + } + void AddNamespaceToCompilationUnit(string namespaceName) { compilationUnitHelper.AddNamespace(namespaceName); @@ -65,7 +70,21 @@ namespace PackageManagement.Tests.EnvDTE { compilationUnitHelper.AddNamespaceAlias(alias, namespaceName); } - + + void AddClassToCompilationUnit(string namespaceName, string className) + { + var classHelper = new ClassHelper(); + classHelper.CreatePublicClass(className); + classHelper.AddNamespaceUsingScopeToClass(namespaceName); + classHelper.AddClassNamespace(namespaceName); + compilationUnitHelper.AddClass(classHelper.Class); + } + + CodeNamespace GetLastCodeNamespaceFromCodeElements() + { + return fileCodeModel.CodeElements.LastCodeNamespaceOrDefault(); + } + [Test] public void CodeElements_OneNamespaceInFile_FileNameUsedToGetCompilationUnit() { @@ -116,5 +135,65 @@ namespace PackageManagement.Tests.EnvDTE namespaceCreator.AssertWasCalled(creator => creator.AddNamespace(compilationUnitHelper.CompilationUnit, "System.Xml")); } + + [Test] + public void CodeElements_OneClassInFileWithNamespace_ReturnsOneCodeNamespace() + { + CreateProjectWithOneFile(); + CreateCompilationUnitForFileProjectItem(); + AddClassToCompilationUnit("Test.CodeModel", "Test.CodeModel.Class1"); + CreateFileCodeModel(); + + CodeNamespace ns = GetFirstCodeNamespaceFromCodeElements(); + + Assert.AreEqual("Test.CodeModel", ns.Name); + } + + [Test] + public void CodeElements_OneClassInFileWithNamespace_ReturnsOneClassInsideCodeNamespace() + { + CreateProjectWithOneFile(); + CreateCompilationUnitForFileProjectItem(); + AddClassToCompilationUnit("Test.CodeModel", "Test.CodeModel.Class1"); + CreateFileCodeModel(); + + CodeNamespace ns = GetFirstCodeNamespaceFromCodeElements(); + CodeClass2 codeClass = ns.Members.FirstCodeClass2OrDefault(); + + Assert.AreEqual("Test.CodeModel.Class1", codeClass.FullName); + } + + [Test] + public void CodeElements_TwoClassesInFileWithNamespace_ReturnsTwoClassesInsideCodeNamespace() + { + CreateProjectWithOneFile(); + CreateCompilationUnitForFileProjectItem(); + AddClassToCompilationUnit("Test.CodeModel", "Test.CodeModel.Class1"); + AddClassToCompilationUnit("Test.CodeModel", "Test.CodeModel.Class2"); + CreateFileCodeModel(); + + CodeNamespace ns = GetFirstCodeNamespaceFromCodeElements(); + CodeClass2 codeClass1 = ns.Members.FirstCodeClass2OrDefault(); + CodeClass2 codeClass2 = ns.Members.LastCodeClass2OrDefault(); + + Assert.AreEqual("Test.CodeModel.Class1", codeClass1.FullName); + Assert.AreEqual("Test.CodeModel.Class2", codeClass2.FullName); + } + + [Test] + public void CodeElements_TwoClassesInFileEachWithDifferentNamespace_ReturnsTwoCodeNamespaces() + { + CreateProjectWithOneFile(); + CreateCompilationUnitForFileProjectItem(); + AddClassToCompilationUnit("Test.CodeModel1", "Test.CodeModel.Class1"); + AddClassToCompilationUnit("Test.CodeModel2", "Test.CodeModel.Class2"); + CreateFileCodeModel(); + + CodeNamespace ns1 = GetFirstCodeNamespaceFromCodeElements(); + CodeNamespace ns2 = GetLastCodeNamespaceFromCodeElements(); + + Assert.AreEqual("Test.CodeModel1", ns1.Name); + Assert.AreEqual("Test.CodeModel2", ns2.Name); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/FileProjectItemsTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/FileProjectItemsTests.cs new file mode 100644 index 0000000000..9d6dff0c76 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/FileProjectItemsTests.cs @@ -0,0 +1,108 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +using ICSharpCode.PackageManagement; +using ICSharpCode.PackageManagement.EnvDTE; +using ICSharpCode.SharpDevelop.Project; +using NUnit.Framework; +using PackageManagement.Tests.Helpers; +using Rhino.Mocks; +using DTE = ICSharpCode.PackageManagement.EnvDTE; + +namespace PackageManagement.Tests.EnvDTE +{ + [TestFixture] + public class FileProjectItemsTests + { + TestableDTEProject project; + FileProjectItems fileProjectItems; + TestableProject msbuildProject; + FakeFileService fakeFileService; + + void CreateProjectWithOneFileInProjectFolder( + string include, + string projectFileName = @"c:\projects\MyProject\MyProject.csproj") + { + project = new TestableDTEProject(); + msbuildProject = project.TestableProject; + fakeFileService = project.FakeFileService; + msbuildProject.FileName = projectFileName; + msbuildProject.AddFile(include); + } + + void CreateFileProjectItemsFromFileInProjectFolder(string include) + { + DTE.ProjectItem projectItem = project.ProjectItems.Item(include); + fileProjectItems = new DTE.FileProjectItems(projectItem, fakeFileService); + } + + IProjectBrowserUpdater CreateProjectBrowserUpdater() + { + IProjectBrowserUpdater projectBrowserUpdater = MockRepository.GenerateStub(); + project.FakeProjectService.ProjectBrowserUpdater = projectBrowserUpdater; + return projectBrowserUpdater; + } + + [Test] + public void AddFromFile_AddFromFileFromProjectItemsBelongingToFile_FileIsParsed() + { + string projectFileName = @"d:\projects\myproject\MyProject.csproj"; + CreateProjectWithOneFileInProjectFolder("MainForm.cs", projectFileName); + CreateFileProjectItemsFromFileInProjectFolder("MainForm.cs"); + string fileName = @"d:\projects\myproject\MainForm.Designer.cs"; + + fileProjectItems.AddFromFile(fileName); + + string parsedFileName = fakeFileService.FileNamePassedToParseFile; + Assert.AreEqual(fileName, parsedFileName); + } + + [Test] + public void AddFromFile_AddFromFileFromProjectItemsBelongingToFile_ReturnsProjectItemAdded() + { + string projectFileName = @"d:\projects\myproject\MyProject.csproj"; + CreateProjectWithOneFileInProjectFolder("MainForm.cs", projectFileName); + CreateFileProjectItemsFromFileInProjectFolder("MainForm.cs"); + string fileName = @"d:\projects\myproject\MainForm.Designer.cs"; + + DTE.ProjectItem itemAdded = fileProjectItems.AddFromFile(fileName); + + string fullPath = (string)itemAdded.Properties.Item("FullPath").Value; + Assert.AreEqual("MainForm.Designer.cs", itemAdded.Name); + Assert.AreEqual(fileName, fullPath); + } + + [Test] + public void AddFromFile_AddFromFileFromProjectItemsBelongingToFile_ProjectIsSaved() + { + string projectFileName = @"d:\projects\myproject\MyProject.csproj"; + CreateProjectWithOneFileInProjectFolder("MainForm.cs", projectFileName); + CreateFileProjectItemsFromFileInProjectFolder("MainForm.cs"); + string fileName = @"d:\projects\myproject\MainForm.Designer.cs"; + + fileProjectItems.AddFromFile(fileName); + + bool saved = msbuildProject.IsSaved; + Assert.IsTrue(saved); + } + + [Test] + public void AddFromFile_AddFromFileFromProjectItemsBelongingToFile_ProjectBrowserUpdaterIsDisposed() + { + string projectFileName = @"d:\projects\myproject\MyProject.csproj"; + CreateProjectWithOneFileInProjectFolder("MainForm.cs", projectFileName); + IProjectBrowserUpdater projectBrowserUpdater = CreateProjectBrowserUpdater(); + CreateFileProjectItemsFromFileInProjectFolder("MainForm.cs"); + string fileName = @"d:\projects\myproject\MainForm.Designer.cs"; + + fileProjectItems.AddFromFile(fileName); + + projectBrowserUpdater.AssertWasCalled(updater => updater.Dispose()); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs index aa2e32456a..801266f38a 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemTests.cs @@ -5,7 +5,9 @@ using System; using System.Collections; using System.Collections.Generic; using ICSharpCode.PackageManagement.EnvDTE; +using ICSharpCode.SharpDevelop.Gui; using DTE = ICSharpCode.PackageManagement.EnvDTE; +using Rhino.Mocks; using NUnit.Framework; using PackageManagement.Tests.Helpers; @@ -27,6 +29,23 @@ namespace PackageManagement.Tests.EnvDTE fakeFileService = project.FakeFileService; } + void OpenSavedFileInSharpDevelop(string fileName) + { + OpenFileInSharpDevelop(fileName, dirty: false); + } + + void OpenUnsavedFileInSharpDevelop(string fileName) + { + OpenFileInSharpDevelop(fileName, dirty: true); + } + + void OpenFileInSharpDevelop(string fileName, bool dirty) + { + IViewContent view = MockRepository.GenerateStub(); + view.Stub(v => v.IsDirty).Return(dirty); + fakeFileService.AddOpenView(view, fileName); + } + [Test] public void ProjectItems_ProjectHasOneFileInsideSrcDirectory_ReturnsOneFileForSrcDirectory() { @@ -106,7 +125,7 @@ namespace PackageManagement.Tests.EnvDTE string kind = directoryItem.Kind; - Assert.AreEqual(Constants.VsProjectItemKindPhysicalFolder, kind); + Assert.AreEqual(Constants.vsProjectItemKindPhysicalFolder, kind); } [Test] @@ -120,7 +139,7 @@ namespace PackageManagement.Tests.EnvDTE string kind = fileItem.Kind; - Assert.AreEqual(Constants.VsProjectItemKindPhysicalFile, kind); + Assert.AreEqual(Constants.vsProjectItemKindPhysicalFile, kind); } [Test] @@ -230,5 +249,115 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual(@"d:\projects\MyProject\src", fileName); } + + [Test] + public void Document_ProjectItemNotOpenInSharpDevelop_ReturnsNull() + { + CreateProjectItems(); + msbuildProject.FileName = @"d:\projects\MyProject\MyProject.csproj"; + msbuildProject.AddFile(@"program.cs"); + ProjectItem item = projectItems.Item("program.cs"); + + Document document = item.Document; + + Assert.IsNull(document); + } + + [Test] + public void Document_ProjectItemOpenInSharpDevelop_ReturnsOpenDocumentForFile() + { + CreateProjectItems(); + msbuildProject.FileName = @"d:\projects\MyProject\MyProject.csproj"; + msbuildProject.AddFile(@"program.cs"); + ProjectItem item = projectItems.Item("program.cs"); + string projectItemFileName = @"d:\projects\MyProject\program.cs"; + OpenSavedFileInSharpDevelop(projectItemFileName); + + Document document = item.Document; + + Assert.AreEqual(projectItemFileName, document.FullName); + } + + [Test] + public void Document_ProjectItemOpenInSharpDevelopAndIsSaved_ReturnsOpenDocumentThatIsSaved() + { + CreateProjectItems(); + msbuildProject.FileName = @"d:\projects\MyProject\MyProject.csproj"; + msbuildProject.AddFile(@"program.cs"); + ProjectItem item = projectItems.Item("program.cs"); + OpenSavedFileInSharpDevelop(@"d:\projects\MyProject\program.cs"); + + Document document = item.Document; + + Assert.IsTrue(document.Saved); + } + + [Test] + public void Document_ProjectItemOpenInSharpDevelopAndIsUnsaved_ReturnsOpenDocumentThatIsNotSaved() + { + CreateProjectItems(); + msbuildProject.FileName = @"d:\projects\MyProject\MyProject.csproj"; + msbuildProject.AddFile(@"program.cs"); + ProjectItem item = projectItems.Item("program.cs"); + OpenUnsavedFileInSharpDevelop(@"d:\projects\MyProject\program.cs"); + + Document document = item.Document; + + Assert.IsFalse(document.Saved); + } + + [Test] + public void Open_ViewKindIsCode_OpensFile() + { + CreateProjectItems(); + msbuildProject.FileName = @"d:\projects\MyProject\MyProject.csproj"; + msbuildProject.AddFile(@"program.cs"); + ProjectItem item = projectItems.Item("program.cs"); + + Window window = item.Open(Constants.vsViewKindCode); + + Assert.AreEqual(@"d:\projects\MyProject\program.cs", fakeFileService.FileNamePassedToOpenFile); + } + + [Test] + public void ProjectItems_ProjectItemHasDependentFile_DependentFileNotAvailableFromProjectItems() + { + CreateProjectItems(); + msbuildProject.AddFile("MainForm.cs"); + msbuildProject.AddDependentFile("MainForm.Designer.cs", "MainForm.cs"); + + ProjectItems projectItems = project.ProjectItems; + + string[] expectedFiles = new string[] { + "MainForm.cs" + }; + ProjectItemCollectionAssert.AreEqual(expectedFiles, projectItems); + } + + [Test] + public void ProjectItems_ProjectItemHasDependentFile_DependentFileNotAvailableFromProject() + { + CreateProjectItems(); + msbuildProject.AddFile("MainForm.cs"); + msbuildProject.AddDependentFile("MainForm.Designer.cs", "MainForm.cs"); + + Assert.Throws(() => project.ProjectItems.Item("MainForm.Designer.cs")); + } + + [Test] + public void ProjectItems_ProjectItemHasDependentFile_ReturnsDependentFile() + { + CreateProjectItems(); + msbuildProject.AddFile("MainForm.cs"); + msbuildProject.AddDependentFile("MainForm.Designer.cs", "MainForm.cs"); + ProjectItem mainFormItem = project.ProjectItems.Item("MainForm.cs"); + + ProjectItems mainFormProjectItems = mainFormItem.ProjectItems; + + string[] expectedFiles = new string[] { + "MainForm.Designer.cs" + }; + ProjectItemCollectionAssert.AreEqual(expectedFiles, mainFormProjectItems); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs index 5ed756c676..e53150ff99 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectItemsTests.cs @@ -527,7 +527,7 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual("tools", name); Assert.AreEqual(project, item.ContainingProject); - Assert.AreEqual(Constants.VsProjectItemKindPhysicalFolder, item.Kind); + Assert.AreEqual(Constants.vsProjectItemKindPhysicalFolder, item.Kind); } [Test] @@ -592,7 +592,7 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual("tools", name); Assert.AreEqual(project, item.ContainingProject); - Assert.AreEqual(Constants.VsProjectItemKindPhysicalFolder, item.Kind); + Assert.AreEqual(Constants.vsProjectItemKindPhysicalFolder, item.Kind); } [Test] @@ -610,9 +610,9 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual("tools", name); Assert.AreEqual(project, item.ContainingProject); - Assert.AreEqual(Constants.VsProjectItemKindPhysicalFolder, item.Kind); + Assert.AreEqual(Constants.vsProjectItemKindPhysicalFolder, item.Kind); Assert.AreEqual(1, item.ProjectItems.Count); - Assert.AreEqual(Constants.VsProjectItemKindPhysicalFolder, childItem.Kind); + Assert.AreEqual(Constants.vsProjectItemKindPhysicalFolder, childItem.Kind); } [Test] @@ -667,7 +667,7 @@ namespace PackageManagement.Tests.EnvDTE projectBrowserUpdater.AssertWasCalled(updater => updater.Dispose()); } - + [Test] public void AddFromDirectory_EmptyDirectoryInsideProject_ProjectBrowserUpdaterIsDisposed() { @@ -815,5 +815,51 @@ namespace PackageManagement.Tests.EnvDTE Assert.IsTrue(fileItem.IsLink); Assert.AreEqual("test.cs", linkName); } + + [Test] + public void Item_GetItemFromControllersFolderProjectItemsWhenProjectHasTwoFilesOneInRootAndOneInControllersFolder_ReturnsFileFromControllersFolder() + { + CreateProjectItems(); + msbuildProject.FileName = @"d:\projects\MyProject\MyProject.csproj"; + msbuildProject.AddFile(@"AccountController.generated.cs"); + msbuildProject.AddFile(@"Controllers\AccountController.cs"); + + DTE.ProjectItem projectItem = projectItems + .Item("Controllers") + .ProjectItems + .Item(1); + + Assert.AreEqual("AccountController.cs", projectItem.Name); + } + + [Test] + public void Item_UnknownProjectItemName_ThrowsException() + { + CreateProjectItems(); + msbuildProject.AddFile("Program.cs"); + + Assert.Throws(() => projectItems.Item("unknown.cs")); + } + + [Test] + public void AddFromFile_AddFromFileFromProjectItemsBelongingToFile_FileIsAddedAsDependentFile() + { + CreateProjectItems(); + msbuildProject.FileName = @"d:\projects\myproject\myproject.csproj"; + msbuildProject.AddFile("MainForm.cs"); + string fileName = @"d:\projects\myproject\MainForm.Designer.cs"; + msbuildProject.ItemTypeToReturnFromGetDefaultItemType = ItemType.Page; + projectItems = project.ProjectItems.Item("MainForm.cs").ProjectItems; + + projectItems.AddFromFile(fileName); + + FileProjectItem fileItem = msbuildProject.FindFile(fileName); + + Assert.AreEqual("MainForm.Designer.cs", fileItem.Include); + Assert.AreEqual(fileName, fileItem.FileName); + Assert.AreEqual(ItemType.Page, fileItem.ItemType); + Assert.AreEqual(msbuildProject, fileItem.Project); + Assert.AreEqual("MainForm.cs", fileItem.DependentUpon); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectsTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectsTests.cs new file mode 100644 index 0000000000..5a51e64ded --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/ProjectsTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.PackageManagement.EnvDTE; +using NUnit.Framework; +using PackageManagement.Tests.Helpers; + +namespace PackageManagement.Tests.EnvDTE +{ + [TestFixture] + public class ProjectsTests + { + Projects projects; + SolutionHelper solutionHelper; + + void CreateSolutionWithSingleProject(string projectName) + { + solutionHelper = new SolutionHelper(); + solutionHelper.AddProjectToSolution(projectName); + projects = solutionHelper.Solution.Projects; + } + + void CreateSolutionWithTwoProjects(string projectName1, string projectName2) + { + solutionHelper = new SolutionHelper(); + solutionHelper.AddProjectToSolution(projectName1); + solutionHelper.AddProjectToSolution(projectName2); + projects = solutionHelper.Solution.Projects; + } + + [Test] + public void Item_OneProjectAndFirstItemRequested_ReturnsProject() + { + CreateSolutionWithSingleProject("MyProject"); + + Project project = projects.Item(1); + + Assert.AreEqual("MyProject", project.Name); + } + + [Test] + public void Item_TwoProjectsAndSecondItemRequested_ReturnsSecondProject() + { + CreateSolutionWithTwoProjects("MyProject1", "MyProject2"); + + Project project = projects.Item(2); + + Assert.AreEqual("MyProject2", project.Name); + } + + [Test] + public void Count_OneProject_ReturnsOne() + { + CreateSolutionWithSingleProject("MyProject"); + + int count = projects.Count; + + Assert.AreEqual(1, count); + } + + [Test] + public void Count_TwoProjects_ReturnsTwo() + { + CreateSolutionWithTwoProjects("MyProject1", "MyProject2"); + + int count = projects.Count; + + Assert.AreEqual(2, count); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/SolutionTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/SolutionTests.cs index 5878c1fb16..be2a20d467 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/SolutionTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/EnvDTE/SolutionTests.cs @@ -38,6 +38,21 @@ namespace PackageManagement.Tests.EnvDTE solutionHelper.AddProjectToSolution(projectName); } + void AddProjectToSolutionWithFileName(string projectName, string fileName) + { + solutionHelper.AddProjectToSolutionWithFileName(projectName, fileName); + } + + void AddFileToFirstProjectInSolution(string fileName) + { + solutionHelper.AddFileToFirstProjectInSolution(fileName); + } + + void AddFileToSecondProjectInSolution(string fileName) + { + solutionHelper.AddFileToSecondProjectInSolution(fileName); + } + [Test] public void IsOpen_NoOpenSolution_ReturnsFalse() { @@ -90,5 +105,56 @@ namespace PackageManagement.Tests.EnvDTE Assert.AreEqual("MyProject", project.Name); } + + [Test] + public void FindProjectItem_SolutionHasOneProjectWithNoItems_ReturnsNull() + { + CreateSolution(); + AddProjectToSolution("MyProject"); + + ProjectItem item = solution.FindProjectItem(@"c:\projects\MyProject\test.cs"); + + Assert.IsNull(item); + } + + [Test] + public void FindProjectItem_SolutionHasOneProjectWithOneItemMatchingFileNamePassedToFindProjectItem_ReturnsProjectItem() + { + CreateSolution(); + AddProjectToSolutionWithFileName("MyProject", @"c:\projects\MyProject\MyProject.csproj"); + AddFileToFirstProjectInSolution(@"src\test.cs"); + string fileName = @"c:\projects\MyProject\src\test.cs"; + + ProjectItem item = solution.FindProjectItem(fileName); + + Assert.AreEqual("test.cs", item.Name); + } + + [Test] + public void FindProjectItem_SolutionHasOneProjectWithOneItemMatchingFileNamePassedToFindProjectItem_ProjectItemHasNonNullContainingProject() + { + CreateSolution(); + AddProjectToSolutionWithFileName("MyProject", @"c:\projects\MyProject\MyProject.csproj"); + AddFileToFirstProjectInSolution(@"src\test.cs"); + string fileName = @"c:\projects\MyProject\src\test.cs"; + + ProjectItem item = solution.FindProjectItem(fileName); + + Assert.AreEqual(@"c:\projects\MyProject\MyProject.csproj", item.ContainingProject.FileName); + } + + [Test] + public void FindProjectItem_SolutionHasTwoProjectsWithOneItemMatchingFileNameInSecondProject_ReturnsProjectItem() + { + CreateSolution(); + AddProjectToSolutionWithFileName("MyProject1", @"c:\projects\MyProject1\MyProject.csproj"); + AddProjectToSolutionWithFileName("MyProject2", @"c:\projects\MyProject2\MyProject.csproj"); + AddFileToSecondProjectInSolution(@"src\test.cs"); + string fileName = @"c:\projects\MyProject2\src\test.cs"; + + ProjectItem item = solution.FindProjectItem(fileName); + + Assert.AreEqual("test.cs", item.Name); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/AttributeHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/AttributeHelper.cs index 0f68b2e0aa..1f0fbde93b 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/AttributeHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/AttributeHelper.cs @@ -43,11 +43,25 @@ namespace PackageManagement.Tests.Helpers NamedArguments.Add(name, value); } - public void AddAttributeToClass(IClass @class) + public void AddAttributeToClass(IClass c) { var attributes = new List(); attributes.Add(Attribute); - @class.Stub(c => c.Attributes).Return(attributes); + c.Stub(item => item.Attributes).Return(attributes); + } + + public void AddAttributeToMethod(IMethod method) + { + var attributes = new List(); + attributes.Add(Attribute); + method.Stub(m => m.Attributes).Return(attributes); + } + + public void AddAttributeToParameter(IParameter parameter) + { + var attributes = new List(); + attributes.Add(Attribute); + parameter.Stub(p => p.Attributes).Return(attributes); } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs index 0db7f57b60..04ff3afe03 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ClassHelper.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using ICSharpCode.SharpDevelop.Dom; using Rhino.Mocks; @@ -32,10 +33,10 @@ namespace PackageManagement.Tests.Helpers Class.Stub(c => c.CompilationUnit).Return(CompilationUnitHelper.CompilationUnit); } - public void AddAttributeToClass(string name) + public void AddAttributeToClass(string attributeTypeName) { var attributeHelper = new AttributeHelper(); - attributeHelper.CreateAttribute(name); + attributeHelper.CreateAttribute(attributeTypeName); attributeHelper.AddAttributeToClass(Class); } @@ -66,13 +67,18 @@ namespace PackageManagement.Tests.Helpers Class.Stub(c => c.BaseTypes).Return(baseTypes); } - IReturnType CreateBaseType(IClass baseTypeClass, string baseTypeFullName, string baseTypeDotNetName) + ReturnTypeHelper CreateBaseTypeHelper(IClass baseTypeClass, string baseTypeFullName, string baseTypeDotNetName) { var returnTypeHelper = new ReturnTypeHelper(); returnTypeHelper.CreateReturnType(baseTypeFullName); returnTypeHelper.AddUnderlyingClass(baseTypeClass); returnTypeHelper.AddDotNetName(baseTypeDotNetName); - return returnTypeHelper.ReturnType; + return returnTypeHelper; + } + + IReturnType CreateBaseType(IClass baseTypeClass, string baseTypeFullName, string baseTypeDotNetName) + { + return CreateBaseTypeHelper(baseTypeClass, baseTypeFullName, baseTypeDotNetName).ReturnType; } public void AddClassToClassBaseTypes(string fullName) @@ -162,5 +168,61 @@ namespace PackageManagement.Tests.Helpers { ProjectContentHelper.SetProjectForProjectContent(project); } + + public void MakeClassAbstract() + { + Class.Stub(c => c.IsAbstract).Return(true); + } + + public void MakeClassPartial() + { + Class.Stub(c => c.IsPartial).Return(true); + } + + public void AddNamespaceUsingScopeToClass(string namespaceName) + { + var usingScopeHelper = new UsingScopeHelper(); + usingScopeHelper.SetNamespaceName(namespaceName); + + Class.Stub(c => c.UsingScope).Return(usingScopeHelper.UsingScope); + } + + public void SetDotNetName(string className) + { + Class.Stub(c => c.DotNetName).Return(className); + } + + /// + /// Classes at the end of the array are at the top of the inheritance tree. + /// + public void AddClassInheritanceTreeClassesOnly(params string[] classNames) + { + List classes = CreateClassInheritanceTree(classNames); + Class.Stub(c => c.ClassInheritanceTreeClassesOnly).Return(classes); + } + + List CreateClassInheritanceTree(string[] classNames) + { + return classNames + .Select(name => CreateClassHelperWithPublicClass(name).Class) + .ToList(); + } + + ClassHelper CreateClassHelperWithPublicClass(string name) + { + var classHelper = new ClassHelper(); + classHelper.CreatePublicClass(name); + return classHelper; + } + + public void SetRegionBeginLine(int line) + { + SetRegion(new DomRegion(line, 1)); + } + + public void SetRegion(DomRegion region) + { + Class.Stub(c => c.Region).Return(region); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CodeElementsExtensions.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CodeElementsExtensions.cs index e55fa0c2d9..a7d0eec627 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CodeElementsExtensions.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CodeElementsExtensions.cs @@ -24,9 +24,9 @@ namespace PackageManagement.Tests.Helpers return ToList(codeElements).FirstOrDefault(); } - public static CodeFunction FirstCodeFunctionOrDefault(this CodeElements codeElements) + public static CodeFunction2 FirstCodeFunction2OrDefault(this CodeElements codeElements) { - return codeElements.FirstOrDefault() as CodeFunction; + return codeElements.FirstOrDefault() as CodeFunction2; } public static CodeClass2 FirstCodeClass2OrDefault(this CodeElements codeElements) @@ -79,9 +79,19 @@ namespace PackageManagement.Tests.Helpers return codeElements.FirstOrDefault() as CodeParameter; } + public static CodeParameter2 FirstCodeParameter2OrDefault(this CodeElements codeElements) + { + return codeElements.FirstOrDefault() as CodeParameter2; + } + public static CodeImport FirstCodeImportOrDefault(this CodeElements codeElements) { return codeElements.FirstOrDefault() as CodeImport; } + + public static CodeClass2 LastCodeClass2OrDefault(this CodeElements codeElements) + { + return codeElements.LastOrDefault() as CodeClass2; + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CompilationUnitHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CompilationUnitHelper.cs index 3ff65181f7..73c4284b78 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CompilationUnitHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/CompilationUnitHelper.cs @@ -14,6 +14,7 @@ namespace PackageManagement.Tests.Helpers public FakeCodeGenerator FakeCodeGenerator = new FakeCodeGenerator(); public List Classes = new List(); public UsingScopeHelper UsingScopeHelper = new UsingScopeHelper(); + public ProjectContentHelper ProjectContentHelper = new ProjectContentHelper(); public CompilationUnitHelper() { @@ -23,6 +24,7 @@ namespace PackageManagement.Tests.Helpers CompilationUnit.Stub(unit => unit.Language).Return(language); CompilationUnit.Stub(unit => unit.Classes).Return(Classes); CompilationUnit.Stub(unit => unit.UsingScope).Return(UsingScopeHelper.UsingScope); + CompilationUnit.Stub(unit => unit.ProjectContent).Return(ProjectContentHelper.ProjectContent); } public void SetFileName(string fileName) diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeFileService.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeFileService.cs index 0eb42f8e12..13dd5ef64a 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeFileService.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeFileService.cs @@ -5,8 +5,10 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; + using ICSharpCode.PackageManagement; using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Project; namespace PackageManagement.Tests.Helpers @@ -123,5 +125,20 @@ namespace PackageManagement.Tests.Helpers FileNamePassedToGetCompilationUnit = fileName; return CompilationUnitToReturnFromGetCompilationUnit; } + + Dictionary openViews = new Dictionary(); + + public void AddOpenView(IViewContent view, string fileName) + { + openViews.Add(fileName, view); + } + + public IViewContent GetOpenFile(string fileName) + { + if (openViews.ContainsKey(fileName)) { + return openViews[fileName]; + } + return null; + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs index f5960c5a66..59e502e6ff 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/MethodHelper.cs @@ -2,6 +2,7 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.Collections.Generic; using ICSharpCode.SharpDevelop.Dom; using Rhino.Mocks; @@ -29,6 +30,12 @@ namespace PackageManagement.Tests.Helpers Method.Stub(m => m.IsPublic).Return(true); } + public void CreatePublicConstructor(string name) + { + CreatePublicMethod(name); + Method.Stub(m => m.IsConstructor).Return(true); + } + public void CreatePrivateMethod(string name) { CreateMethod(name); @@ -112,5 +119,64 @@ namespace PackageManagement.Tests.Helpers Method.Stub(m => m.ReturnType).Return(returnTypeHelper.ReturnType); } + + public void MakeMethodStatic() + { + Method.Stub(m => m.IsStatic).Return(true); + } + + public void MakeMethodAbstract() + { + Method.Stub(m => m.IsAbstract).Return(true); + } + + public void MakeMethodVirtual() + { + Method.Stub(m => m.IsVirtual).Return(true); + } + + public void AddAttributeToMethod(string attributeTypeName) + { + var attributeHelper = new AttributeHelper(); + attributeHelper.CreateAttribute(attributeTypeName); + attributeHelper.AddAttributeToMethod(Method); + } + + public void MakeMethodOverride() + { + Method.Stub(m => m.IsOverride).Return(true); + } + + public void MakeMethodSealed() + { + Method.Stub(m => m.IsSealed).Return(true); + } + + public void MakeMethodNewOverride() + { + Method.Stub(m => m.IsNew).Return(true); + } + + public void MakeMethodOverridable() + { + Method.Stub(m => m.IsOverridable).Return(true); + } + + public void AddTypeParameter(string name) + { + var typeParameterHelper = new TypeParameterHelper(); + typeParameterHelper.SetName(name); + AddTypeParameters(typeParameterHelper.TypeParameterToList()); + } + + public void AddTypeParameters(List typeParameters) + { + Method.Stub(m => m.TypeParameters).Return(typeParameters); + } + + public void NoTypeParameters() + { + AddTypeParameters(new List()); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ParameterHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ParameterHelper.cs new file mode 100644 index 0000000000..85efb03c0d --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ParameterHelper.cs @@ -0,0 +1,51 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.SharpDevelop.Dom; +using Rhino.Mocks; + +namespace PackageManagement.Tests.Helpers +{ + public class ParameterHelper + { + public IParameter Parameter; + + public ParameterHelper() + { + Parameter = MockRepository.GenerateStub(); + } + + public void MakeOptionalParameter() + { + Parameter.Stub(p => p.IsOptional).Return(true); + } + + public void MakeOutParameter() + { + Parameter.Stub(p => p.IsOut).Return(true); + } + + public void MakeRefParameter() + { + Parameter.Stub(p => p.IsRef).Return(true); + } + + public void MakeParamArrayParameter() + { + Parameter.Stub(p => p.IsParams).Return(true); + } + + public void MakeInParameter() + { + Parameter.Stub(p => p.Modifiers).Return(ParameterModifiers.In); + } + + public void AddAttributeToParameter(string attributeTypeName) + { + var attributeHelper = new AttributeHelper(); + attributeHelper.CreateAttribute(attributeTypeName); + attributeHelper.AddAttributeToParameter(Parameter); + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ReturnTypeHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ReturnTypeHelper.cs index cc2e60c826..8999819495 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ReturnTypeHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/ReturnTypeHelper.cs @@ -32,5 +32,10 @@ namespace PackageManagement.Tests.Helpers { ReturnType.Stub(t => t.GetUnderlyingClass()).Return(c); } + + public void MakeReferenceType() + { + ReturnType.Stub(t => t.IsReferenceType).Return(true); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/SolutionHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/SolutionHelper.cs index 90767db0ef..4a0d5fb2f0 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/SolutionHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/SolutionHelper.cs @@ -49,8 +49,14 @@ namespace PackageManagement.Tests.Helpers } public void AddProjectToSolution(string projectName) + { + AddProjectToSolutionWithFileName(projectName, @"c:\projects\MyProject\MyProject.csproj"); + } + + public void AddProjectToSolutionWithFileName(string projectName, string fileName) { TestableProject project = ProjectHelper.CreateTestProject(projectName); + project.FileName = fileName; FakeProjectService.AddFakeProject(project); } @@ -85,5 +91,24 @@ namespace PackageManagement.Tests.Helpers { Assert.IsNull(FakeProjectService.SavedSolution); } + + public SD.FileProjectItem AddFileToFirstProjectInSolution(string include) + { + TestableProject project = FakeProjectService + .FakeOpenProjects + .Select(p => p as TestableProject) + .First(); + return project.AddFile(include); + } + + public SD.FileProjectItem AddFileToSecondProjectInSolution(string include) + { + TestableProject project = FakeProjectService + .FakeOpenProjects + .Select(p => p as TestableProject) + .Skip(1) + .First(); + return project.AddFile(include); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/TestableProject.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/TestableProject.cs index 17d60fea25..5b53e4d7ce 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/TestableProject.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/TestableProject.cs @@ -68,7 +68,7 @@ namespace PackageManagement.Tests.Helpers { var fileProjectItem = new FileProjectItem(this, ItemType.Folder, include); ProjectService.AddProjectItem(this, fileProjectItem); - return fileProjectItem; + return fileProjectItem; } public override string AssemblyName { @@ -80,5 +80,12 @@ namespace PackageManagement.Tests.Helpers get { return rootNamespace; } set { rootNamespace = value; } } + + public FileProjectItem AddDependentFile(string include, string dependentUpon) + { + FileProjectItem dependentFile = AddFile(include); + dependentFile.DependentUpon = dependentUpon; + return dependentFile; + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/TypeParameterHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/TypeParameterHelper.cs new file mode 100644 index 0000000000..f76f34f8e5 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/TypeParameterHelper.cs @@ -0,0 +1,32 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using ICSharpCode.SharpDevelop.Dom; +using Rhino.Mocks; + +namespace PackageManagement.Tests.Helpers +{ + public class TypeParameterHelper + { + public ITypeParameter TypeParameter; + + public TypeParameterHelper() + { + TypeParameter = MockRepository.GenerateMock(); + } + + public void SetName(string name) + { + TypeParameter.Stub(tp => tp.Name); + } + + public List TypeParameterToList() + { + var parameters = new List(); + parameters.Add(TypeParameter); + return parameters; + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/UsingScopeHelper.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/UsingScopeHelper.cs index b6674a563d..be4cf51948 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/UsingScopeHelper.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/UsingScopeHelper.cs @@ -37,5 +37,10 @@ namespace PackageManagement.Tests.Helpers usingHelper.AddNamespaceAlias(alias, namespaceName); Usings.Add(usingHelper.Using); } + + public void SetNamespaceName(string namespaceName) + { + UsingScope.Stub(u => u.NamespaceName).Return(namespaceName); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/ProjectBrowserUpdaterTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/ProjectBrowserUpdaterTests.cs index 3341a49b7a..d56d4dac73 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/ProjectBrowserUpdaterTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/ProjectBrowserUpdaterTests.cs @@ -131,6 +131,15 @@ namespace PackageManagement.Tests AddProjectItemToProject(fileProjectItem); } + void AddDependentFileToProject(string fileName, string dependentUpon) + { + var fileProjectItem = new FileProjectItem(project, ItemType.Compile) { + FileName = fileName, + DependentUpon = dependentUpon + }; + AddProjectItemToProject(fileProjectItem); + } + void AddReferenceToProject(string name) { var reference = new ReferenceProjectItem(project, name); @@ -585,5 +594,150 @@ namespace PackageManagement.Tests AssertChildFileNodesCountAreEqual(1, subfolderNode); } + + [Test] + public void Constructor_NewDependentFileAddedWhenParentFileHasNoChildren_DependentFileAddedToParentFile() + { + string projectFileName = @"d:\projects\MyProject\MyProject.csproj"; + string fileName = @"d:\projects\MyProject\MainForm.cs"; + CreateProjectNodeWithOneFileInRootDirectoryExpanded(projectFileName, fileName); + string newFileName = @"d:\projects\MyProject\MainForm.Designer.cs"; + + AddDependentFileToProject(newFileName, "MainForm.cs"); + + FileNode mainFormFileNode = GetFirstFileChildNode(projectNode); + FileNode mainFormDesignerFileNode = GetFirstFileChildNode(mainFormFileNode); + Assert.AreEqual(newFileName, mainFormDesignerFileNode.FileName); + Assert.AreEqual(FileNodeStatus.BehindFile, mainFormDesignerFileNode.FileNodeStatus); + } + + [Test] + public void Constructor_NewDependentFileAddedWhenParentFileHasNoChildren_FileNotAddedToSameDirectoryAsParentFile() + { + string projectFileName = @"d:\projects\MyProject\MyProject.csproj"; + string fileName = @"d:\projects\MyProject\MainForm.cs"; + CreateProjectNodeWithOneFileInRootDirectoryExpanded(projectFileName, fileName); + string newFileName = @"d:\projects\MyProject\MainForm.Designer.cs"; + + AddDependentFileToProject(newFileName, "MainForm.cs"); + + // Should be only two project child nodes. + // References + MainForm.cs + Assert.AreEqual(2, projectNode.Nodes.Count); + } + + [Test] + public void Constructor_ProjectHasFileInProjectAndInSubdirectoryAndNewFileAddedInSubdirectory_NewFileNotAddedAsChildToExistingFile() + { + CreateExpandedProjectNodeWithFiles( + @"d:\projects\MyProject\MyProject.csproj", + @"d:\projects\MyProject\a.cs", + @"d:\projects\MyProject\src\b.cs"); + DirectoryNode srcDirectoryNode = GetFirstDirectoryChildNode(projectNode); + srcDirectoryNode.Expanding(); + + AddFileToProject(@"d:\projects\MyProject\src\c.cs"); + + FileNode firstFileNode = GetFirstFileChildNode(projectNode); + Assert.AreEqual(0, firstFileNode.Nodes.Count); + } + + [Test] + public void Constructor_ProjectHasThreeFilesAndDependentFileAddedToSecondFile_DependentFileAddedToSecondFile() + { + CreateExpandedProjectNodeWithFiles( + @"d:\projects\MyProject\MyProject.csproj", + @"d:\projects\MyProject\A.cs", + @"d:\projects\MyProject\MainForm.cs", + @"d:\projects\MyProject\Z.cs"); + + AddDependentFileToProject(@"d:\projects\MyProject\MainForm.Designer.cs", "MainForm.cs"); + + FileNode mainFormFileNode = GetFirstChildNode(projectNode, n => n.Text == "MainForm.cs") as FileNode; + FileNode mainFormDesignerFileNode = GetFirstFileChildNode(mainFormFileNode); + Assert.AreEqual(@"d:\projects\MyProject\MainForm.Designer.cs", mainFormDesignerFileNode.FileName); + } + + [Test] + public void Constructor_ProjectHasThreeFilesAndDependentFileAddedToSecondFile_DependentFileNotAddedToFirst() + { + CreateExpandedProjectNodeWithFiles( + @"d:\projects\MyProject\MyProject.csproj", + @"d:\projects\MyProject\A.cs", + @"d:\projects\MyProject\MainForm.cs", + @"d:\projects\MyProject\Z.cs"); + + AddDependentFileToProject(@"d:\projects\MyProject\MainForm.Designer.cs", "MainForm.cs"); + + FileNode fileNode = GetFirstFileChildNode(projectNode); + Assert.AreEqual(0, fileNode.Nodes.Count); + } + + [Test] + public void Constructor_ProjectHasOneFileAndDependentFileAddedWithDifferentCaseToParentFile_DependentFileAddedToParentFile() + { + CreateExpandedProjectNodeWithFiles( + @"d:\projects\MyProject\MyProject.csproj", + @"d:\projects\MyProject\MainForm.cs"); + + AddDependentFileToProject(@"d:\projects\MyProject\MainForm.Designer.cs", "MAINFORM.CS"); + + FileNode mainFormFileNode = GetFirstFileChildNode(projectNode); + FileNode mainFormDesignerFileNode = GetFirstFileChildNode(mainFormFileNode); + Assert.AreEqual(@"d:\projects\MyProject\MainForm.Designer.cs", mainFormDesignerFileNode.FileName); + } + + [Test] + public void Constructor_DependentFileAddedWhenProjectHasTwoFilesWithSameParentNameButInDifferentFolders_DependentFileNotAddedToFileInDifferentDirectoryWithSameDependentName() + { + CreateExpandedProjectNodeWithFiles( + @"d:\projects\MyProject\MyProject.csproj", + @"d:\projects\MyProject\a.cs", + @"d:\projects\MyProject\src\a.cs", + @"d:\projects\MyProject\src\b.cs"); + DirectoryNode srcDirectoryNode = GetFirstDirectoryChildNode(projectNode); + srcDirectoryNode.Expanding(); + + AddDependentFileToProject(@"d:\projects\MyProject\src\c.cs", "a.cs"); + + FileNode firstFileNode = GetFirstFileChildNode(projectNode); + Assert.AreEqual(0, firstFileNode.Nodes.Count); + } + + [Test] + public void Constructor_DependentFileAddedWhenProjectHasTwoFilesWithSameParentNameButInDifferentFolders_DependentFileAddedToFileInSameDirectory() + { + CreateExpandedProjectNodeWithFiles( + @"d:\projects\MyProject\MyProject.csproj", + @"d:\projects\MyProject\a.cs", + @"d:\projects\MyProject\src\a.cs", + @"d:\projects\MyProject\src\b.cs"); + DirectoryNode srcDirectoryNode = GetFirstDirectoryChildNode(projectNode); + srcDirectoryNode.Expanding(); + + AddDependentFileToProject(@"d:\projects\MyProject\src\c.cs", "a.cs"); + + FileNode fileNode = GetFirstFileChildNode(srcDirectoryNode); + FileNode childNode = GetFirstFileChildNode(fileNode); + Assert.AreEqual(@"d:\projects\MyProject\src\c.cs", childNode.FileName); + } + + [Test] + public void Constructor_DependentFileAddedWhenProjectHasTwoFilesWithSameParentNameButInDifferentFoldersAndFolderCasingDifferent_DependentFileAddedToFileInSameDirectory() + { + CreateExpandedProjectNodeWithFiles( + @"d:\projects\MyProject\MyProject.csproj", + @"d:\projects\MyProject\a.cs", + @"d:\projects\MYPROJECT\SRC\a.cs", + @"d:\projects\MyProject\src\b.cs"); + DirectoryNode srcDirectoryNode = GetFirstDirectoryChildNode(projectNode); + srcDirectoryNode.Expanding(); + + AddDependentFileToProject(@"d:\projects\MyProject\src\c.cs", "a.cs"); + + FileNode fileNode = GetFirstFileChildNode(srcDirectoryNode); + FileNode childNode = GetFirstFileChildNode(fileNode); + Assert.AreEqual(@"d:\projects\MyProject\src\c.cs", childNode.FileName); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/SharpDevelopProjectSystemTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/SharpDevelopProjectSystemTests.cs index 40cf671840..ed040be096 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/SharpDevelopProjectSystemTests.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/SharpDevelopProjectSystemTests.cs @@ -38,7 +38,12 @@ namespace PackageManagement.Tests { ProjectHelper.AddFile(project, fileName); } - + + void AddDefaultCustomToolForFileName(string fileName, string customTool) + { + projectSystem.FakeProjectService.AddDefaultCustomToolForFileName(fileName, customTool); + } + [Test] public void Root_NewInstanceCreated_ReturnsProjectDirectory() { @@ -721,5 +726,37 @@ namespace PackageManagement.Tests Assert.AreEqual(expectedPath, path); } + + [Test] + public void AddFile_NewTextTemplateFileWithAssociatedDefaultCustomTool_AddsFileToProjectWithDefaultCustomTool() + { + CreateTestProject(); + CreateProjectSystem(project); + string path = @"d:\temp\abc.tt"; + AddDefaultCustomToolForFileName(path, "TextTemplatingFileGenerator"); + Stream stream = new MemoryStream(); + + projectSystem.AddFile(path, stream); + + FileProjectItem fileItem = ProjectHelper.GetFile(project, path); + string customTool = fileItem.CustomTool; + Assert.AreEqual("TextTemplatingFileGenerator", customTool); + } + + [Test] + public void AddFile_NewFileWithNoAssociatedDefaultCustomTool_AddsFileToProjectWithNoDefaultCustomTool() + { + CreateTestProject(); + CreateProjectSystem(project); + string path = @"d:\temp\abc.tt"; + AddDefaultCustomToolForFileName(path, null); + Stream stream = new MemoryStream(); + + projectSystem.AddFile(path, stream); + + FileProjectItem fileItem = ProjectHelper.GetFile(project, path); + string customTool = fileItem.CustomTool; + Assert.AreEqual(String.Empty, customTool); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/VirtualMethodUpdaterTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/VirtualMethodUpdaterTests.cs new file mode 100644 index 0000000000..01c222887e --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/VirtualMethodUpdaterTests.cs @@ -0,0 +1,151 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.PackageManagement; +using ICSharpCode.SharpDevelop.Dom.Refactoring; +using NUnit.Framework; +using PackageManagement.Tests.Helpers; +using Rhino.Mocks; + +namespace PackageManagement.Tests +{ + [TestFixture] + public class VirtualMethodUpdaterTests + { + VirtualMethodUpdater updater; + MethodHelper methodHelper; + IRefactoringDocument document; + IDocumentLoader documentLoader; + + [SetUp] + public void Init() + { + methodHelper = new MethodHelper(); + document = MockRepository.GenerateStub(); + documentLoader = MockRepository.GenerateStub(); + } + + void CreatePublicCSharpFunction() + { + methodHelper.CreatePublicMethod("MyMethod"); + methodHelper.ProjectContentHelper.ProjectContentIsForCSharpProject(); + } + + void CreatePublicVisualBasicFunction() + { + methodHelper.CreatePublicMethod("MyMethod"); + methodHelper.ProjectContentHelper.ProjectContentIsForVisualBasicProject(); + } + + void SetDocumentFileName(string fileName) + { + documentLoader.Stub(loader => loader.LoadRefactoringDocument(fileName)).Return(document); + } + + void CreateVirtualMethodUpdater() + { + updater = new VirtualMethodUpdater(methodHelper.Method, documentLoader); + } + + void SetFileNameForMethod(string fileName) + { + methodHelper.SetCompilationUnitFileName(fileName); + SetDocumentFileName(fileName); + } + + void SetMethodDeclarationLineWithOffset(int line, string text, int offset) + { + methodHelper.FunctionStartsAtLine(line); + SetDocumentLineText(line, text, offset); + } + + void SetMethodDeclarationLine(int line, string text) + { + SetMethodDeclarationLineWithOffset(line, text, 0); + } + + void SetDocumentLineText(int lineNumber, string text, int offset) + { + IRefactoringDocumentLine documentLine = MockRepository.GenerateStub(); + documentLine.Stub(line => line.Text).Return(text); + documentLine.Stub(line => line.Offset).Return(offset); + document.Stub(doc => doc.GetLine(lineNumber)).Return(documentLine); + } + + [Test] + public void MakeMethodVirtual_PublicCSharpClassWithNoOtherModifiers_AddsVirtualKeywordToMethodDefinition() + { + CreatePublicCSharpFunction(); + CreateVirtualMethodUpdater(); + SetFileNameForMethod(@"d:\projects\MyProject\MyClass.cs"); + SetMethodDeclarationLine(1, "public void MyMethod()"); + + updater.MakeMethodVirtual(); + + document.AssertWasCalled(doc => doc.Insert(7, "virtual ")); + } + + [Test] + public void MakeMethodVirtual_MethodAlreadyVirtual_MethodDefinitionIsNotChanged() + { + CreatePublicCSharpFunction(); + CreateVirtualMethodUpdater(); + methodHelper.MakeMethodVirtual(); + SetFileNameForMethod(@"d:\projects\MyProject\MyClass.cs"); + SetMethodDeclarationLine(1, "public void MyMethod()"); + + updater.MakeMethodVirtual(); + + document.AssertWasNotCalled(doc => doc.Insert(Arg.Is.Anything, Arg.Is.Anything)); + } + + [Test] + public void MakeMethodVirtual_PublicVisualBasicClassWithNoOtherModifiers_AddsOverridableKeywordToMethodDefinition() + { + CreatePublicVisualBasicFunction(); + CreateVirtualMethodUpdater(); + SetFileNameForMethod(@"d:\projects\MyProject\MyClass.vb"); + SetMethodDeclarationLine(1, "Public Sub MyMethod"); + + updater.MakeMethodVirtual(); + + document.AssertWasCalled(doc => doc.Insert(7, "Overridable ")); + } + + [Test] + public void MakeMethodVirtual_NoPublicKeywordInClassDeclarationLine_ExceptionIsThrown() + { + CreatePublicCSharpFunction(); + CreateVirtualMethodUpdater(); + SetFileNameForMethod(@"d:\projects\MyProject\MyClass.cs"); + SetMethodDeclarationLine(1, "void test()"); + + Assert.Throws(() => updater.MakeMethodVirtual()); + } + + [Test] + public void MakeMethodVirtual_NoPublicKeywordButMethodNameIncludesPublicKeyword_ExceptionIsThrown() + { + CreatePublicCSharpFunction(); + CreateVirtualMethodUpdater(); + SetFileNameForMethod(@"d:\projects\MyProject\MyClass.cs"); + SetMethodDeclarationLine(1, "void publicmethod()"); + + Assert.Throws(() => updater.MakeMethodVirtual()); + } + + [Test] + public void MakeMethodVirtual_PublicCSharpMethodNotOnFirstLine_AddsVirtualKeywordToMethodDefinitionAtCorrectOffset() + { + CreatePublicCSharpFunction(); + CreateVirtualMethodUpdater(); + SetFileNameForMethod(@"d:\projects\MyProject\MyClass.cs"); + SetMethodDeclarationLineWithOffset(1, "public void MyMethod()", offset: 10); + + updater.MakeMethodVirtual(); + + document.AssertWasCalled(doc => doc.Insert(17, "virtual ")); + } + } +} diff --git a/src/Libraries/AvalonDock/AvalonDock/DockingManager.cs b/src/Libraries/AvalonDock/AvalonDock/DockingManager.cs index b65cdc147d..4af71ae898 100644 --- a/src/Libraries/AvalonDock/AvalonDock/DockingManager.cs +++ b/src/Libraries/AvalonDock/AvalonDock/DockingManager.cs @@ -3752,7 +3752,7 @@ namespace AvalonDock /// /// True while is restoring a layout /// - protected bool RestoringLayout { get; private set; } + protected internal bool RestoringLayout { get; private set; } /// /// Internal main restore layout method diff --git a/src/Libraries/AvalonDock/AvalonDock/FloatingWindow.cs b/src/Libraries/AvalonDock/AvalonDock/FloatingWindow.cs index d43ad44dcb..37acfae08c 100644 --- a/src/Libraries/AvalonDock/AvalonDock/FloatingWindow.cs +++ b/src/Libraries/AvalonDock/AvalonDock/FloatingWindow.cs @@ -340,7 +340,7 @@ namespace AvalonDock protected override void OnDeactivated(EventArgs e) { - if (Manager != null && lastActiveContent != null) + if (Manager != null && !Manager.RestoringLayout && lastActiveContent != null) { Manager.ActiveContent = lastActiveContent; } diff --git a/src/Libraries/AvalonDock/AvalonDock/ManagedContent.cs b/src/Libraries/AvalonDock/AvalonDock/ManagedContent.cs index 1259179fe0..501ac136bd 100644 --- a/src/Libraries/AvalonDock/AvalonDock/ManagedContent.cs +++ b/src/Libraries/AvalonDock/AvalonDock/ManagedContent.cs @@ -337,7 +337,9 @@ namespace AvalonDock protected virtual void OnDragMouseLeave(object sender, MouseEventArgs e) { - if (!e.Handled && isMouseDown && e.LeftButton == MouseButtonState.Pressed && Manager != null) + // The MouseLeave event can occur if the managed content was closed while the user held the left mouse button pressed. + // In that case, this.IsLoaded will be false and we won't handle the event + if (!e.Handled && isMouseDown && e.LeftButton == MouseButtonState.Pressed && Manager != null && this.IsLoaded) { if (!IsMouseCaptured) { diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.addin b/src/Main/Base/Project/ICSharpCode.SharpDevelop.addin index 881619ee29..bc6756df0f 100755 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.addin +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.addin @@ -2262,6 +2262,9 @@ + diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index 0476f61dba..5c92ac387b 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -281,6 +281,10 @@ + + ProjectCustomToolOptionsPanel.xaml + Code + ReferencePaths.xaml @@ -376,6 +380,9 @@ + + + @@ -418,6 +425,7 @@ + @@ -822,6 +830,7 @@ + ProjectOptionPanel.cs diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/ProjectOptions/ProjectCustomToolOptionsPanel.xaml b/src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/ProjectOptions/ProjectCustomToolOptionsPanel.xaml new file mode 100644 index 0000000000..ebc9aa76a9 --- /dev/null +++ b/src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/ProjectOptions/ProjectCustomToolOptionsPanel.xaml @@ -0,0 +1,33 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/ProjectOptions/ProjectCustomToolOptionsPanel.xaml.cs b/src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/ProjectOptions/ProjectCustomToolOptionsPanel.xaml.cs new file mode 100644 index 0000000000..31ec9ebdca --- /dev/null +++ b/src/Main/Base/Project/Src/Gui/Dialogs/OptionPanels/ProjectOptions/ProjectCustomToolOptionsPanel.xaml.cs @@ -0,0 +1,107 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.ComponentModel; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Project; + +namespace ICSharpCode.SharpDevelop.Gui.OptionPanels +{ + public partial class ProjectCustomToolOptionsPanel : INotifyPropertyChanged, ICanBeDirty + { + ProjectCustomToolOptions customToolsOptions; + bool runCustomToolOnBuild; + string fileNames; + bool isDirty; + + public ProjectCustomToolOptionsPanel() + { + this.DataContext = this; + InitializeComponent(); + } + + public bool RunCustomToolOnBuild { + get { return runCustomToolOnBuild; } + set { + runCustomToolOnBuild = value; + OnChanged(); + } + } + + public string FileNames { + get { return fileNames; } + set { + fileNames = value; + OnChanged(); + } + } + + void OnChanged() + { + IsDirty = OptionsHaveChanged(); + } + + bool OptionsHaveChanged() + { + return + (runCustomToolOnBuild != customToolsOptions.RunCustomToolOnBuild) || + (fileNames != customToolsOptions.FileNames); + } + + public override void LoadOptions() + { + var project = Owner as IProject; + + customToolsOptions = new ProjectCustomToolOptions(project); + RunCustomToolOnBuild = customToolsOptions.RunCustomToolOnBuild; + FileNames = customToolsOptions.FileNames; + + OnPropertyChanged(); + } + + public override bool SaveOptions() + { + if (OptionsHaveChanged()) { + customToolsOptions.RunCustomToolOnBuild = runCustomToolOnBuild; + customToolsOptions.FileNames = fileNames; + } + IsDirty = false; + return true; + } + + public event PropertyChangedEventHandler PropertyChanged; + + void OnPropertyChanged() + { + OnPropertyChanged(null); + } + + void OnPropertyChanged(string propertyName) + { + if (PropertyChanged != null) { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } + + public event EventHandler IsDirtyChanged; + + void OnIsDirtyChanged() + { + if (IsDirtyChanged != null) { + IsDirtyChanged(this, new EventArgs()); + } + } + + public bool IsDirty { + get { return isDirty; } + + private set { + if (isDirty != value) { + isDirty = value; + OnIsDirtyChanged(); + } + } + } + } +} \ No newline at end of file diff --git a/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolFileNameFilter.cs b/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolFileNameFilter.cs new file mode 100644 index 0000000000..f94bc9796e --- /dev/null +++ b/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolFileNameFilter.cs @@ -0,0 +1,36 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace ICSharpCode.SharpDevelop.Project +{ + public class BeforeBuildCustomToolFileNameFilter + { + List fileNames; + + public BeforeBuildCustomToolFileNameFilter(IProject project) + { + var customToolOptions = new ProjectCustomToolOptions(project); + if (customToolOptions.RunCustomToolOnBuild) { + fileNames = customToolOptions.SplitFileNames().ToList(); + } else { + fileNames = new List(); + } + } + + public bool IsMatch(string fullPath) + { + string fileNameToMatch = Path.GetFileName(fullPath); + return fileNames.Any(fileName => String.Equals(fileName, fileNameToMatch, StringComparison.OrdinalIgnoreCase)); + } + + public bool Any() + { + return fileNames.Any(); + } + } +} diff --git a/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolProjectItems.cs b/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolProjectItems.cs new file mode 100644 index 0000000000..b710b670e0 --- /dev/null +++ b/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolProjectItems.cs @@ -0,0 +1,55 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Linq; +using ICSharpCode.SharpDevelop.Project; + +namespace ICSharpCode.SharpDevelop.Project +{ + public class BeforeBuildCustomToolProjectItems + { + IBuildable buildable; + + public BeforeBuildCustomToolProjectItems(IBuildable buildable) + { + this.buildable = buildable; + } + + public IEnumerable GetProjectItems() + { + return GetProjects() + .SelectMany(p => GetConfiguredCustomToolProjectItems(p)) + .ToList(); + } + + IEnumerable GetProjects() + { + IProject project = buildable as IProject; + if (project != null) { + return new IProject[] { project }; + } + + var solution = buildable as Solution; + if (solution != null) { + return solution.Projects; + } + + return new IProject[0]; + } + + IEnumerable GetConfiguredCustomToolProjectItems(IProject project) + { + var fileNameFilter = new BeforeBuildCustomToolFileNameFilter(project); + if (!fileNameFilter.Any()) { + return new FileProjectItem[0]; + } + + return project + .Items + .OfType() + .Where(item => fileNameFilter.IsMatch(item.Include)); + } + } +} diff --git a/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolRunner.cs b/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolRunner.cs new file mode 100644 index 0000000000..3532490e7c --- /dev/null +++ b/src/Main/Base/Project/Src/Project/BeforeBuildCustomToolRunner.cs @@ -0,0 +1,30 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace ICSharpCode.SharpDevelop.Project +{ + public class BeforeBuildCustomToolRunner + { + public BeforeBuildCustomToolRunner() + { + ProjectService.BuildStarted += ProjectBuildStarted; + } + + void ProjectBuildStarted(object sender, BuildEventArgs e) + { + var projectItems = new BeforeBuildCustomToolProjectItems(e.Buildable); + RunCustomTool(projectItems.GetProjectItems()); + } + + void RunCustomTool(IEnumerable projectItems) + { + foreach (FileProjectItem projectItem in projectItems) { + CustomToolsService.RunCustomTool(projectItem, false); + } + } + } +} diff --git a/src/Main/Base/Project/Src/Project/CustomTool.cs b/src/Main/Base/Project/Src/Project/CustomTool.cs index 3d92f211ce..98ba0b1fef 100644 --- a/src/Main/Base/Project/Src/Project/CustomTool.cs +++ b/src/Main/Base/Project/Src/Project/CustomTool.cs @@ -340,6 +340,7 @@ namespace ICSharpCode.SharpDevelop.Project static Dictionary toolDict; static List customToolList; static CustomToolRun activeToolRun; + static BeforeBuildCustomToolRunner beforeBuildCustomToolRunner; internal static void Initialize() { @@ -353,6 +354,8 @@ namespace ICSharpCode.SharpDevelop.Project initialized = true; FileUtility.FileSaved += OnFileSaved; } + + beforeBuildCustomToolRunner = new BeforeBuildCustomToolRunner(); } static void OnFileSaved(object sender, FileNameEventArgs e) diff --git a/src/Main/Base/Project/Src/Project/IProject.cs b/src/Main/Base/Project/Src/Project/IProject.cs index 30058708c1..e7b14f3f78 100644 --- a/src/Main/Base/Project/Src/Project/IProject.cs +++ b/src/Main/Base/Project/Src/Project/IProject.cs @@ -194,12 +194,12 @@ namespace ICSharpCode.SharpDevelop.Project #endregion /// - /// Saves the project using it's current file name. + /// Saves the project using its current file name. /// void Save(); /// - /// Returns true, if a specific file (given by it's name) is inside this project. + /// Returns true, if a specific file (given by its name) is inside this project. /// This member is thread-safe. /// /// The fully qualified file name of the file @@ -219,7 +219,9 @@ namespace ICSharpCode.SharpDevelop.Project /// /// Gets project specific properties. + /// These are saved in as part of the SharpDevelop configuration in the AppData folder. /// + /// This property never returns null. Properties ProjectSpecificProperties { get; } /// diff --git a/src/Main/Base/Project/Src/Project/ProjectCustomToolOptions.cs b/src/Main/Base/Project/Src/Project/ProjectCustomToolOptions.cs new file mode 100644 index 0000000000..82a0fc7ec5 --- /dev/null +++ b/src/Main/Base/Project/Src/Project/ProjectCustomToolOptions.cs @@ -0,0 +1,41 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Linq; +using ICSharpCode.Core; + +namespace ICSharpCode.SharpDevelop.Project +{ + public class ProjectCustomToolOptions + { + Properties properties; + + public ProjectCustomToolOptions(IProject project) + { + properties = project.ProjectSpecificProperties.NestedProperties("customTool"); + } + + public bool RunCustomToolOnBuild { + get { return properties.Get("runOnBuild", false); } + set { properties.Set("runOnBuild", value); } + } + + public string FileNames { + get { return properties.Get("fileNames", String.Empty); } + set { properties.Set("fileNames", value); } + } + + public IList SplitFileNames() + { + return + FileNames + .Replace("\r\n", ";") + .Split(';', ',') + .Select(fileName => fileName.Trim()) + .Where(fileName => !String.IsNullOrEmpty(fileName)) + .ToList(); + } + } +} diff --git a/src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs b/src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs index 66f95e1d10..a40edeab40 100644 --- a/src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs +++ b/src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; + using System.Windows.Input; using ICSharpCode.Core; diff --git a/src/Main/Base/Test/ICSharpCode.SharpDevelop.Tests.csproj b/src/Main/Base/Test/ICSharpCode.SharpDevelop.Tests.csproj index c516858e55..e75c412c8d 100644 --- a/src/Main/Base/Test/ICSharpCode.SharpDevelop.Tests.csproj +++ b/src/Main/Base/Test/ICSharpCode.SharpDevelop.Tests.csproj @@ -90,6 +90,8 @@ + + @@ -124,6 +126,7 @@ + @@ -192,8 +195,5 @@ - - - \ No newline at end of file diff --git a/src/Main/Base/Test/Project/BeforeBuildCustomToolProjectItemsTests.cs b/src/Main/Base/Test/Project/BeforeBuildCustomToolProjectItemsTests.cs new file mode 100644 index 0000000000..0dc200d491 --- /dev/null +++ b/src/Main/Base/Test/Project/BeforeBuildCustomToolProjectItemsTests.cs @@ -0,0 +1,304 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; + +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Project; +using ICSharpCode.SharpDevelop.Tests.Utils; +using NUnit.Framework; +using Rhino.Mocks; + +namespace ICSharpCode.SharpDevelop.Tests.Project +{ + [TestFixture] + public class BeforeBuildCustomToolProjectItemsTests + { + ProjectHelper projectHelper; + BeforeBuildCustomToolProjectItems beforeBuildCustomToolProjectItems; + Solution solution; + + class UnknownBuildable : IBuildable + { + public string Name { get; set; } + + public Solution ParentSolution { get; set; } + + public ICollection GetBuildDependencies(ProjectBuildOptions buildOptions) + { + return new IBuildable[0]; + } + + public void StartBuild(ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink) + { + } + + public ProjectBuildOptions CreateProjectBuildOptions(BuildOptions options, bool isRootBuildable) + { + return new ProjectBuildOptions(BuildTarget.Build); + } + } + + IProject CreateProject(string fileName = @"d:\MyProject\MyProject.csproj") + { + projectHelper = new ProjectHelper(fileName); + return projectHelper.Project; + } + + void CreateSolution(params IProject[] projects) + { + IProjectChangeWatcher watcher = MockRepository.GenerateStub(); + solution = new Solution(watcher); + projects.ForEach(p => solution.Folders.Add(p)); + } + + void ConfigureCustomToolFileNamesForProject(string fileNames) + { + var customToolOptions = new ProjectCustomToolOptions(projectHelper.Project); + customToolOptions.FileNames = fileNames; + } + + void EnableCustomToolRunForProject() + { + SetCustomToolRunForProject(true); + } + + void SetCustomToolRunForProject(bool enabled) + { + var customToolOptions = new ProjectCustomToolOptions(projectHelper.Project); + customToolOptions.RunCustomToolOnBuild = enabled; + } + + void DisableCustomToolRunForProject() + { + SetCustomToolRunForProject(false); + } + + List GetProjectItems() + { + return beforeBuildCustomToolProjectItems.GetProjectItems().ToList(); + } + + void CreateBeforeBuildCustomToolProjectItems() + { + CreateBeforeBuildCustomToolProjectItems(projectHelper.Project as IBuildable); + } + + void CreateBeforeBuildCustomToolProjectItems(IBuildable buildable) + { + beforeBuildCustomToolProjectItems = new BeforeBuildCustomToolProjectItems(buildable); + } + + void CreateBeforeBuildCustomToolProjectItemsUsingSolution() + { + CreateBeforeBuildCustomToolProjectItems(solution as IBuildable); + } + + FileProjectItem AddFileToProject(string include) + { + var projectItem = new FileProjectItem(projectHelper.Project, ItemType.Compile, include); + projectHelper.AddProjectItem(projectItem); + return projectItem; + } + + void CreateBeforeBuildCustomToolProjectItemsWithUnknownIBuildableDerivedClass() + { + var unknownBuildable = new UnknownBuildable(); + CreateBeforeBuildCustomToolProjectItems(unknownBuildable); + } + + [Test] + public void GetProjectItems_BuildSingleProjectNotConfiguredToRunCustomToolsOnBuild_ReturnsNoItems() + { + CreateProject(); + CreateBeforeBuildCustomToolProjectItems(); + + List projectItems = GetProjectItems(); + + Assert.AreEqual(0, projectItems.Count); + } + + [Test] + public void GetProjectItems_BuildSingleProjectWithOneFileMatchingCustomToolRunConfiguration_OneProjectItemReturned() + { + CreateProject(@"d:\MyProject\MyProject.csproj"); + FileProjectItem projectItem = AddFileToProject("template.tt"); + EnableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("template.tt"); + CreateBeforeBuildCustomToolProjectItems(); + + List projectItems = GetProjectItems(); + + FileProjectItem[] expectedProjectItems = new FileProjectItem[] { + projectItem + }; + CollectionAssert.AreEqual(expectedProjectItems, projectItems); + } + + [Test] + public void GetProjectItems_BuildSingleProjectWithOneFileMatchingCustomToolFileNamesConfigured_NoProjectItemsReturnedWhenRunCustomToolIsDisabledForProject() + { + CreateProject(@"d:\MyProject\MyProject.csproj"); + AddFileToProject("template.tt"); + DisableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("template.tt"); + CreateBeforeBuildCustomToolProjectItems(); + + List projectItems = GetProjectItems(); + + Assert.AreEqual(0, projectItems.Count); + } + + [Test] + public void GetProjectItems_BuildSingleProjectWithOneFileMatchingCustomToolRunConfiguration_OtherNonMatchingProjectItemsNotReturned() + { + CreateProject(@"d:\MyProject\MyProject.csproj"); + FileProjectItem projectItem = AddFileToProject("template.t4"); + AddFileToProject("test.cs"); + EnableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("template.t4"); + CreateBeforeBuildCustomToolProjectItems(); + + List projectItems = GetProjectItems(); + + FileProjectItem[] expectedProjectItems = new FileProjectItem[] { + projectItem + }; + CollectionAssert.AreEqual(expectedProjectItems, projectItems); + } + + [Test] + public void GetProjectItems_BuildSingleProjectWithOneFileMatchingCustomToolRunConfiguration_ProjectItemInSubdirectoryReturned() + { + CreateProject(@"d:\MyProject\MyProject.csproj"); + FileProjectItem projectItem = AddFileToProject(@"Model\template.tt"); + EnableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("template.tt"); + CreateBeforeBuildCustomToolProjectItems(); + + List projectItems = GetProjectItems(); + + FileProjectItem[] expectedProjectItems = new FileProjectItem[] { + projectItem + }; + CollectionAssert.AreEqual(expectedProjectItems, projectItems); + } + + [Test] + public void GetProjectItems_BuildSingleProjectWithOneFileMatchingCustomToolRunConfiguration_ProjectItemReturnedWhenFileNameCaseIsDifferent() + { + CreateProject(@"d:\MyProject\MyProject.csproj"); + FileProjectItem projectItem = AddFileToProject("template.tt"); + EnableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("TEMPLATE.TT"); + CreateBeforeBuildCustomToolProjectItems(); + + List projectItems = GetProjectItems(); + + FileProjectItem[] expectedProjectItems = new FileProjectItem[] { + projectItem + }; + CollectionAssert.AreEqual(expectedProjectItems, projectItems); + } + + [Test] + public void GetProjectItems_SolutionContainingOneProjectWithMatchingCustomToolFileName_ReturnsOneProjectItem() + { + IProject project = CreateProject(@"d:\MyProject\MyProject.csproj"); + FileProjectItem projectItem = AddFileToProject("template.tt"); + EnableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("TEMPLATE.TT"); + CreateSolution(project); + CreateBeforeBuildCustomToolProjectItemsUsingSolution(); + + List projectItems = GetProjectItems(); + + FileProjectItem[] expectedProjectItems = new FileProjectItem[] { + projectItem + }; + CollectionAssert.AreEqual(expectedProjectItems, projectItems); + } + + [Test] + public void GetProjectItems_SolutionWithNoProjects_ReturnsNoProjectItems() + { + CreateSolution(); + CreateBeforeBuildCustomToolProjectItemsUsingSolution(); + + List projectItems = GetProjectItems(); + + Assert.AreEqual(0, projectItems.Count); + } + + [Test] + public void GetProjectItems_SolutionContainingTwoProjectsWithMatchingCustomToolFileNameInSecondProject_ReturnsOneProjectItem() + { + IProject project1 = CreateProject(@"d:\MyProject\FirstProject.csproj"); + IProject project2 = CreateProject(@"d:\MyProject\SecondProject.csproj"); + FileProjectItem projectItem = AddFileToProject("template.tt"); + EnableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("TEMPLATE.TT"); + CreateSolution(project1, project2); + CreateBeforeBuildCustomToolProjectItemsUsingSolution(); + + List projectItems = GetProjectItems(); + + FileProjectItem[] expectedProjectItems = new FileProjectItem[] { + projectItem + }; + CollectionAssert.AreEqual(expectedProjectItems, projectItems); + } + + [Test] + public void GetProjectItems_SolutionContainingTwoProjectsWithMatchingCustomToolFileNameInFirstProject_ReturnsOneProjectItem() + { + IProject project1 = CreateProject(@"d:\MyProject\FirstProject.csproj"); + FileProjectItem projectItem = AddFileToProject("template.tt"); + EnableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("TEMPLATE.TT"); + IProject project2 = CreateProject(@"d:\MyProject\SecondProject.csproj"); + CreateSolution(project1, project2); + CreateBeforeBuildCustomToolProjectItemsUsingSolution(); + + List projectItems = GetProjectItems(); + + FileProjectItem[] expectedProjectItems = new FileProjectItem[] { + projectItem + }; + CollectionAssert.AreEqual(expectedProjectItems, projectItems); + } + + [Test] + public void GetProjectItems_SolutionContainingTwoProjectsBothWithFilesAndMatchingCustomToolFileNameInFirstProject_ReturnsOneProjectItem() + { + IProject project1 = CreateProject(@"d:\MyProject\FirstProject.csproj"); + FileProjectItem projectItem = AddFileToProject("template.tt"); + EnableCustomToolRunForProject(); + ConfigureCustomToolFileNamesForProject("TEMPLATE.TT"); + IProject project2 = CreateProject(@"d:\MyProject\SecondProject.csproj"); + AddFileToProject("test.cs"); + CreateSolution(project1, project2); + CreateBeforeBuildCustomToolProjectItemsUsingSolution(); + + List projectItems = GetProjectItems(); + + FileProjectItem[] expectedProjectItems = new FileProjectItem[] { + projectItem + }; + CollectionAssert.AreEqual(expectedProjectItems, projectItems); + } + + [Test] + public void GetProjectItems_UnknownIBuildableDerivedClass_NullReferenceExceptionIsNotThrown() + { + CreateBeforeBuildCustomToolProjectItemsWithUnknownIBuildableDerivedClass(); + + List projectItems = GetProjectItems(); + + Assert.AreEqual(0, projectItems.Count); + } + } +} diff --git a/src/Main/Base/Test/Project/ProjectCustomToolOptionsTests.cs b/src/Main/Base/Test/Project/ProjectCustomToolOptionsTests.cs new file mode 100644 index 0000000000..fd25b30bbe --- /dev/null +++ b/src/Main/Base/Test/Project/ProjectCustomToolOptionsTests.cs @@ -0,0 +1,212 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Project; +using NUnit.Framework; +using Rhino.Mocks; + +namespace ICSharpCode.SharpDevelop.Tests.Project +{ + [TestFixture] + public class ProjectCustomToolOptionsTests + { + IProject project; + Properties projectSpecificProperties; + ProjectCustomToolOptions projectCustomToolOptions; + Properties properties; + + void CreateProject() + { + projectSpecificProperties = new Properties(); + project = MockRepository.GenerateStub(); + project.Stub(p => p.ProjectSpecificProperties).Return(projectSpecificProperties); + } + + void CreateProjectWithExistingCustomToolProperties(string fileNames) + { + CreateProjectWithExistingCustomToolProperties(false, fileNames); + } + + void CreateProjectWithExistingCustomToolProperties(bool runOnBuild, string fileNames = "") + { + CreateProject(); + properties = new Properties(); + properties.Set("runOnBuild", runOnBuild); + properties.Set("fileNames", fileNames); + projectSpecificProperties.SetNestedProperties("customTool", properties); + } + + void CreateProjectCustomToolsOptions() + { + projectCustomToolOptions = new ProjectCustomToolOptions(project); + } + + [Test] + public void RunCustomToolOnBuild_ProjectHasNoExistingProjectCustomToolProperties_ReturnsFalse() + { + CreateProject(); + CreateProjectCustomToolsOptions(); + + bool run = projectCustomToolOptions.RunCustomToolOnBuild; + + Assert.IsFalse(run); + } + + [Test] + public void FileNames_ProjectHasNoExistingProjectCustomToolProperties_ReturnsEmptyString() + { + CreateProject(); + CreateProjectCustomToolsOptions(); + + string fileNames = projectCustomToolOptions.FileNames; + + Assert.AreEqual(String.Empty, fileNames); + } + + [Test] + public void RunCustomToolOnBuild_ProjectPropertyRunCustomToolOnBuildIsTrue_ReturnsTrue() + { + CreateProjectWithExistingCustomToolProperties(runOnBuild: true); + CreateProjectCustomToolsOptions(); + + bool run = projectCustomToolOptions.RunCustomToolOnBuild; + + Assert.IsTrue(run); + } + + [Test] + public void FileNames_ProjectPropertyFileNamesIsNotEmptyString_ReturnsFileName() + { + CreateProjectWithExistingCustomToolProperties(fileNames: "T4MVC.tt"); + CreateProjectCustomToolsOptions(); + + string fileNames = projectCustomToolOptions.FileNames; + + Assert.AreEqual("T4MVC.tt", fileNames); + } + + [Test] + public void RunCustomToolOnBuild_ChangeRunCustomToolOnBuildToTrue_StoredInProjectProperties() + { + CreateProjectWithExistingCustomToolProperties(runOnBuild: false); + CreateProjectCustomToolsOptions(); + + projectCustomToolOptions.RunCustomToolOnBuild = true; + + CreateProjectCustomToolsOptions(); + bool run = projectCustomToolOptions.RunCustomToolOnBuild; + Assert.IsTrue(run); + } + + [Test] + public void RunCustomToolOnBuild_ChangeRunCustomToolOnBuildToFalse_StoredInProjectProperties() + { + CreateProjectWithExistingCustomToolProperties(runOnBuild: true); + CreateProjectCustomToolsOptions(); + + projectCustomToolOptions.RunCustomToolOnBuild = false; + + CreateProjectCustomToolsOptions(); + bool run = projectCustomToolOptions.RunCustomToolOnBuild; + Assert.IsFalse(run); + } + + [Test] + public void FileNames_ChangeFileNamesFromEmptyStringToFileName_StoredInProjectProperties() + { + CreateProjectWithExistingCustomToolProperties(fileNames: String.Empty); + CreateProjectCustomToolsOptions(); + + projectCustomToolOptions.FileNames = "abc.tt"; + + CreateProjectCustomToolsOptions(); + string fileNames = projectCustomToolOptions.FileNames; + Assert.AreEqual("abc.tt", fileNames); + } + + [Test] + public void SplitFileNames_FileNamesIsSemiColonSeparatedOfTwoFiles_ReturnsTwoFiles() + { + CreateProjectWithExistingCustomToolProperties("a.t4;b.t4"); + CreateProjectCustomToolsOptions(); + + IList fileNames = projectCustomToolOptions.SplitFileNames(); + + string[] expectedFileNames = new string[] { + "a.t4", + "b.t4" + }; + CollectionAssert.AreEqual(expectedFileNames, fileNames); + } + + [Test] + public void SplitFileNames_FileNamesIsCommaSeparatedOfTwoFiles_ReturnsTwoFiles() + { + CreateProjectWithExistingCustomToolProperties("a.t4,b.t4"); + CreateProjectCustomToolsOptions(); + + IList fileNames = projectCustomToolOptions.SplitFileNames(); + + string[] expectedFileNames = new string[] { + "a.t4", + "b.t4" + }; + CollectionAssert.AreEqual(expectedFileNames, fileNames); + } + + [Test] + public void SplitFileNames_FileNamesIsSemiColonSeparatedOfTwoFilesWithWhitespace_ReturnsTwoFilesWithWhitespaceRemoved() + { + CreateProjectWithExistingCustomToolProperties(" a.t4 ; b.t4 "); + CreateProjectCustomToolsOptions(); + + IList fileNames = projectCustomToolOptions.SplitFileNames(); + + string[] expectedFileNames = new string[] { + "a.t4", + "b.t4" + }; + CollectionAssert.AreEqual(expectedFileNames, fileNames); + } + + [Test] + public void SplitFileNames_FileNamesIsTwoFilesEachOnSeparateLine_ReturnsTwoFiles() + { + string text = + "a.t4\r\n" + + "b.t4"; + CreateProjectWithExistingCustomToolProperties(text); + CreateProjectCustomToolsOptions(); + + IList fileNames = projectCustomToolOptions.SplitFileNames(); + + string[] expectedFileNames = new string[] { + "a.t4", + "b.t4" + }; + CollectionAssert.AreEqual(expectedFileNames, fileNames); + } + + [Test] + public void SplitFileNames_FileNamesIsTwoFilesEachOnSeparateLineWithEmptyLineBetweenThemAndOneAtEnd_ReturnsTwoFiles() + { + string text = + "a.t4\r\n" + + "\r\n" + + "b.t4\r\n"; + CreateProjectWithExistingCustomToolProperties(text); + CreateProjectCustomToolsOptions(); + + IList fileNames = projectCustomToolOptions.SplitFileNames(); + + string[] expectedFileNames = new string[] { + "a.t4", + "b.t4" + }; + CollectionAssert.AreEqual(expectedFileNames, fileNames); + } + } +} diff --git a/src/Main/Base/Test/Utils/ProjectHelper.cs b/src/Main/Base/Test/Utils/ProjectHelper.cs new file mode 100644 index 0000000000..e6c5eb4e13 --- /dev/null +++ b/src/Main/Base/Test/Utils/ProjectHelper.cs @@ -0,0 +1,37 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Project; +using Rhino.Mocks; + +namespace ICSharpCode.SharpDevelop.Tests.Utils +{ + public class ProjectHelper + { + public IProject Project = MockRepository.GenerateMock(); + public List ProjectItems = new List(); + + public ProjectHelper(string fileName) + { + Project.Stub(p => p.FileName).Return(fileName); + + Project + .Stub(p => p.Items) + .Return(null) + .WhenCalled(mi => mi.ReturnValue = new ReadOnlyCollection(ProjectItems)); + + Project.Stub(p => p.ProjectSpecificProperties).Return(new Properties()); + + Project.Stub(p => p.SyncRoot).Return(new Object()); + } + + public void AddProjectItem(ProjectItem projectItem) + { + ProjectItems.Add(projectItem); + } + } +}