using Codelyzer.Analysis; using Codelyzer.Analysis.Analyzer; using CTA.Rules.Config; using CTA.Rules.Models; using CTA.Rules.PortCore; using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; namespace CTA.Rules.Test { public class AwsRulesBaseTest { private string tstPath; private string srcPath; public static string CopyFolder = nameof(CopyFolder); protected void Setup(System.Type type) { this.tstPath = GetTstPath(type); this.srcPath = GetSrcPath(type); } private string GetTstPath(System.Type type) { // The path will get normalized inside the .GetProject() call below string projectPath = Path.GetFullPath( Path.Combine( Path.GetDirectoryName(type.Assembly.Location), Path.Combine(new string[] { "..", "..", "..", ".." }))); return projectPath; } private string GetSrcPath(System.Type type) { // The path will get normalized inside the .GetProject() call below string projectPath = Path.GetFullPath( Path.Combine( Path.GetDirectoryName(type.Assembly.Location), Path.Combine(new string[] { "..", "..", "..", "..", "..", "src" }))); return projectPath; } public string GetTstPath(string path) { return Path.Combine(tstPath, path); } public string GetSrcPath(string path) { return Path.Combine(srcPath, path); } /// /// Finds a solution within the designated directory and copies it to a unique, /// temporary directory where it can be ported in isolation. /// /// /// /// /// Results of the CTA analysis/port public TestSolutionAnalysis CopySolutionToUniqueTempDirAndAnalyze( string solutionName, string searchDir, string targetFrameworkVersion) { var solutionPath = CopySolutionDirToUniqueTempDir(solutionName, searchDir); return AnalyzeSolution(solutionPath, targetFrameworkVersion); } public TestSolutionAnalysis AnalyzeSolution( string solutionName, string tempDir, string downloadLocation, string version, Dictionary> metaReferences = null, bool skipCopy = false, bool portCode = true, bool portProject = true) { string solutionPath = Directory.EnumerateFiles(tempDir, solutionName, SearchOption.AllDirectories).FirstOrDefault(); if (!skipCopy) { solutionPath = CopySolutionDirToUniqueTempDir(solutionName, downloadLocation); } return AnalyzeSolution(solutionPath, version, metaReferences, portCode, portProject); } public TestSolutionAnalysis AnalyzeSolution( string solutionPath, string version, Dictionary> metaReferences = null, //bool skipCopy = false, bool portCode = true, bool portProject = true) { TestSolutionAnalysis result = new TestSolutionAnalysis(); if (solutionPath != null && solutionPath.Length > 0) { List solutionPortConfiguration = new List(); IEnumerable projectFiles = Utils.GetProjectPaths(solutionPath); if (projectFiles != null && projectFiles.Any()) { foreach (string projectFile in projectFiles) { Dictionary> packages = new Dictionary> { { "Newtonsoft.Json", new Tuple("9.0.0", "*") } }; PortCoreConfiguration projectConfiguration = new PortCoreConfiguration() { SolutionPath = solutionPath, ProjectPath = projectFile, UseDefaultRules = true, TargetVersions = new List { version }, PackageReferences = packages, PortCode = portCode, PortProject = portProject }; if (metaReferences != null) { projectConfiguration.MetaReferences = metaReferences.ContainsKey(projectFile) ? metaReferences[projectFile] : null; } solutionPortConfiguration.Add(projectConfiguration); result.ProjectResults.Add(new ProjectResult() { CsProjectPath = projectFile, ProjectDirectory = Directory.GetParent(projectFile).FullName }); } // SolutionPort should remove this extra config because it does not have a matching analyzer result. // Otherwise will hit KeyNotFoundException solutionPortConfiguration.Add(new PortCoreConfiguration { SolutionPath = solutionPath, ProjectPath = "fakeproject.csproj", UseDefaultRules = true, }); SolutionPort solutionPort = new SolutionPort(solutionPath, solutionPortConfiguration); CopyTestRules(); CopyTestTemplates(); CopyTestTagConfigs(); var analysisRunResult = solutionPort.AnalysisRun(); StringBuilder str = new StringBuilder(); foreach (var projectResult in analysisRunResult.ProjectResults) { Assert.IsTrue(projectResult.ProjectActions.ToSummaryString()?.Length > 0); StringBuilder projectResults = new StringBuilder(); projectResults.AppendLine(projectResult.ProjectFile); projectResults.AppendLine(projectResult.ProjectActions.ToString()); result.ProjectResults.Where(p => p.CsProjectPath == projectResult.ProjectFile).FirstOrDefault().ProjectAnalysisResult = projectResults.ToString(); str.Append(projectResults); } result.SolutionAnalysisResult = str.ToString(); var runResult = solutionPort.Run(); foreach (var projectFile in result.ProjectResults) { projectFile.CsProjectContent = File.ReadAllText(projectFile.CsProjectPath); } result.SolutionRunResult = runResult; } } return result; } internal TestSolutionAnalysis GenerateSolutionResult(string solutionPath, SolutionResult analysisRunResult, PortSolutionResult solutionRunResult) { var result = new TestSolutionAnalysis(); var projectFiles = Utils.GetProjectPaths(solutionPath).ToList(); projectFiles.ForEach(projectFile => { result.ProjectResults.Add(new ProjectResult() { CsProjectPath = projectFile, ProjectDirectory = Directory.GetParent(projectFile).FullName, CsProjectContent = File.ReadAllText(projectFile) }); }); StringBuilder str = new StringBuilder(); foreach (var projectResult in analysisRunResult.ProjectResults) { StringBuilder projectResults = new StringBuilder(); projectResults.AppendLine(projectResult.ProjectFile); projectResults.AppendLine(projectResult.ProjectActions.ToString()); result.ProjectResults.Where(p => p.CsProjectPath == projectResult.ProjectFile).FirstOrDefault().ProjectAnalysisResult = projectResults.ToString(); str.Append(projectResults); } result.SolutionAnalysisResult = str.ToString(); result.SolutionRunResult = solutionRunResult; return result; } protected void CopyTestRules() { // Project configured to copy TempRules folder to output directory // so no extra action necessary here var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var tempRulesDir = Path.Combine(assemblyDir, "TempRules"); if (Directory.Exists(tempRulesDir)) { var files = Directory.EnumerateFiles(tempRulesDir, "*.json"); foreach (var file in files) { string targetFile = Path.Combine(Constants.RulesDefaultPath, Path.GetFileName(file)); File.Copy(file, targetFile, true); } } } private void CopyTestTemplates() { // Project configured to copy TempTemplates folder to output directory // so no extra action necessary here var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var tempTemplatesDir = Path.Combine(assemblyDir, "TempTemplates"); if (Directory.Exists(tempTemplatesDir)) { var files = Directory.EnumerateFiles(tempTemplatesDir, "*", SearchOption.AllDirectories); foreach (var file in files) { var relativePath = Path.GetRelativePath(tempTemplatesDir, file); var targetFile = Path.Combine(Constants.ResourcesExtractedPath, relativePath); var targetFileDir = Path.GetDirectoryName(targetFile); Directory.CreateDirectory(targetFileDir); File.Copy(file, targetFile, true); } } } private void CopyTestTagConfigs() { // Project configured to copy TempTagConfigs folder to output directory // so no extra action necessary here var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var tempTemplatesDir = Path.Combine(assemblyDir, "TempTagConfigs"); if (Directory.Exists(tempTemplatesDir)) { var files = Directory.EnumerateFiles(tempTemplatesDir, "*", SearchOption.AllDirectories); foreach (var file in files) { var relativePath = Path.GetRelativePath(tempTemplatesDir, file); var targetFile = Path.Combine(Rules.Config.Constants.TagConfigsExtractedPath, relativePath); var targetFileDir = Path.GetDirectoryName(targetFile); Directory.CreateDirectory(targetFileDir); File.Copy(file, targetFile, true); } } } protected void CopyDirectory(DirectoryInfo source, DirectoryInfo target) { if (!Directory.Exists(target.FullName)) { Directory.CreateDirectory(target.FullName); } var files = source.GetFiles(); foreach (var file in files) { file.CopyTo(Path.Combine(target.FullName, file.Name),true); } var dirs = source.GetDirectories(); foreach (var dir in dirs) { DirectoryInfo destinationSub = new DirectoryInfo(Path.Combine(target.FullName, dir.Name)); CopyDirectory(dir, destinationSub); } } protected string CopySolutionDirToUniqueTempDir(string solutionName, string searchDir) { var solutionPath = Directory.EnumerateFiles(searchDir, solutionName, SearchOption.AllDirectories).FirstOrDefault(s => !s.Contains(string.Concat(Path.DirectorySeparatorChar, CopyFolder, Path.DirectorySeparatorChar))); var solutionDir = Directory.GetParent(solutionPath).FullName; var newTempDir = Path.Combine(GetTstPath(this.GetType()), CopyFolder, Guid.NewGuid().ToString()); if (solutionPath.Contains(".sln") && File.Exists(solutionPath)) { IEnumerable projects = Utils.GetProjectPaths(solutionPath); newTempDir = BuildRelativeFolderStructureToIncludeAllExternalProjects(projects, newTempDir, solutionDir); CopyDirectory(new DirectoryInfo(solutionDir), new DirectoryInfo(newTempDir)); FindAndCopyProjectsOutsideSolutionPath(projects, solutionDir, newTempDir); } else { CopyDirectory(new DirectoryInfo(solutionDir), new DirectoryInfo(newTempDir)); } var newSolutionPath = Directory.EnumerateFiles(newTempDir, solutionName, SearchOption.AllDirectories).FirstOrDefault(); return newSolutionPath; } private string BuildRelativeFolderStructureToIncludeAllExternalProjects(IEnumerable projects, string newTempDir, string solutionDir) { int folderCount = 1; int depths = projects.ToList().Max(p => Regex.Matches(Path.GetRelativePath(solutionDir, p), Regex.Escape("..")).Count); for (int i = 0; i < depths; i++) { newTempDir += "\\Folder" + folderCount++; } return newTempDir; } private void FindAndCopyProjectsOutsideSolutionPath(IEnumerable projects, string solutionDir, string newTempDir) { foreach (string project in projects) { string projPath = Directory.GetParent(project).FullName; if (!Utils.IsSubPathOf(solutionDir, projPath)) { string relativeSrc = Path.GetRelativePath(solutionDir, projPath); string projName = Path.GetFileName(project); string newRelDir = Path.Combine(newTempDir, relativeSrc); Utils.CopyFolderToTemp(projName, projPath, newRelDir); } } } protected List GetSolutionBuildErrors(string solutionPath) { var result = GetBuildResults(solutionPath); var allErrors = new List(); result.ForEach(r => allErrors.AddRange(r.ProjectBuildResult.BuildErrors)); return allErrors; } protected List GetBuildResults(string solutionPath) { AnalyzerConfiguration configuration = new AnalyzerConfiguration(LanguageOptions.CSharp) { ExportSettings = { GenerateJsonOutput = false, OutputPath = @"/tmp/UnitTests" }, MetaDataSettings = { LiteralExpressions = true, MethodInvocations = true, Annotations = true, DeclarationNodes = true, LocationData = false, ReferenceData = true, LoadBuildData = true, ElementAccess = true, MemberAccess = true } }; //CodeAnalyzer analyzer = CodeAnalyzerFactory.GetAnalyzer(configuration, NullLogger.Instance); CodeAnalyzerByLanguage analyzer = new CodeAnalyzerByLanguage(configuration, NullLogger.Instance); var result = analyzer.AnalyzeSolution(solutionPath).Result; return result; } protected List GenerateSolutionAnalysis(string solutionPath) { AnalyzerConfiguration configuration = new AnalyzerConfiguration(LanguageOptions.CSharp) { ExportSettings = { GenerateJsonOutput = false, OutputPath = @"/tmp/UnitTests" }, MetaDataSettings = { LiteralExpressions = true, MethodInvocations = true, Annotations = true, DeclarationNodes = true, LocationData = false, ReferenceData = true, LoadBuildData = true, ElementAccess = true, MemberAccess = true } }; //CodeAnalyzer analyzer = CodeAnalyzerFactory.GetAnalyzer(configuration, NullLogger.Instance); CodeAnalyzerByLanguage analyzer = new CodeAnalyzerByLanguage(configuration, NullLogger.Instance); var result = analyzer.AnalyzeSolution(solutionPath).Result; return result; } } }