Beispiel #1
0
    static XUnitSettings BuildXUnitSettings(ParsedProject projectUnderTest, AnyUnitTestSettings settings,
                                            DirectoryPath outputDir)
    {
        var outputFile = outputDir.CombineWithFilePath(projectUnderTest.Project.AssemblyName + ".xunit.xml");

        var traitArgs = new List <KeyValuePair <string, string> >();

        AddTraits(traitArgs, "/-trait", settings.ExcludedTraits);
        AddTraits(traitArgs, "/trait", settings.IncludedTraits);

        var s = new XUnitSettings();

        XBuildHelper.ApplyToolSettings(s, NUnitToolArgs);
        s.ShadowCopy            = settings.ShadowCopyAssemblies;
        s.ArgumentCustomization = args =>
        {
            foreach (var traitArg in traitArgs)
            {
                args.Append(traitArg.Key);
                args.AppendQuoted(traitArg.Value);
            }

            args.Append("/xml");
            args.AppendQuoted(outputFile.MakeAbsolute(Context.Environment).FullPath);
            return(args);
        };
        return(s);
    }
Beispiel #2
0
    static ProjectFile FindMetaDataFile(ParsedProject p)
    {
        var projectFiles = p.Project.Files;

        return
            (projectFiles.FirstOrDefault(
                 f => f.Compile && f.RelativePath.EndsWith(BuildConfig.GeneratedAssemblyMetaDataReference)));
    }
Beispiel #3
0
 public static DirectoryPath ComputeOutputPath(string type, ParsedProject project)
 {
     return(Context.Directory(string.Format("{0}/{4}/{1}/{2}/{3}",
                                            TargetDirectory,
                                            project.Platform,
                                            Config.Configuration,
                                            project.Project.AssemblyName,
                                            type)));
 }
Beispiel #4
0
    public static void SalvageBuildResults(ParsedProject project)
    {
        var relativeProjectFile = Context.Environment.WorkingDirectory.GetRelativePath(project.ProjectFile);

        Context.Log.Verbose(string.Format("Salvaging build result for {0} with platform {1}", relativeProjectFile,
                                          project.Platform));

        var outputDir = project.ProjectFile.GetDirectory().Combine(project.Project.OutputPath);
        var targetDir = ComputeProjectBinPath(project);

        Context.CopyDirectory(outputDir, targetDir);
    }
Beispiel #5
0
    static FilePath ComputeTargetFile(ParsedProject project)
    {
        string extension;

        if ("Exe".Equals(project.Project.OutputType, StringComparison.InvariantCultureIgnoreCase) ||
            "Winexe".Equals(project.Project.OutputType, StringComparison.InvariantCultureIgnoreCase))
        {
            extension = ".exe";
        }
        else
        {
            extension = ".dll";
        }
        return(project.Project.AssemblyName + extension);
    }
Beispiel #6
0
    static NUnitSettings BuildNUnitSettings(ParsedProject projectUnderTest, AnyUnitTestSettings settings,
                                            DirectoryPath outputDir)
    {
        var s = new NUnitSettings();

        XBuildHelper.ApplyToolSettings(s, NUnitToolArgs);

        if (settings.ExcludedCategories.Count > 0)
        {
            s.Exclude = string.Join(",", settings.ExcludedCategories);
        }
        if (settings.IncludedCategories.Count > 0)
        {
            s.Include = string.Join(",", settings.IncludedCategories);
        }
        s.ShadowCopy = settings.ShadowCopyAssemblies;
        s.UseSingleThreadedApartment = settings.UseSingleThreadedApartment;
        s.X86         = settings.ForceX86 || projectUnderTest.Platform == PlatformTarget.x86;
        s.ResultsFile = outputDir.CombineWithFilePath(projectUnderTest.Project.AssemblyName + ".nunit2.xml");
        return(s);
    }
Beispiel #7
0
    public static ParseResult ParseProjects(ICakeContext context,
                                            string configuration,
                                            List <PlatformTarget> platforms,
                                            List <FilePath> effectiveProjects)
    {
        var c = new ParseResult();

        foreach (var platform in platforms)
        {
            var projects = effectiveProjects
                           .Select(p => ParsedProject.Parse(context, p, configuration, platform))
                           .Where(IsValidProjectForPlatform(context))
                           .ToList();

            if (projects.Count > 0)
            {
                c.ProjectsByPlatform[platform] = projects;
                c.PlatformBuildOrder.Add(platform);
            }
        }
        return(c);
    }
Beispiel #8
0
    static NUnit3Settings BuildNUnit3Settings(ParsedProject projectUnderTest, AnyUnitTestSettings settings,
                                              DirectoryPath outputDir)
    {
        var whereClause = BuildNUnit3WhereClause(settings);

        var s = new NUnit3Settings();

        XBuildHelper.ApplyToolSettings(s, NUnitToolArgs);

        s.ShadowCopy = settings.ShadowCopyAssemblies;
        s.X86        = settings.ForceX86 || projectUnderTest.Platform == PlatformTarget.x86;
        var path = outputDir.CombineWithFilePath(projectUnderTest.Project.AssemblyName + ".nunit3.xml");

        NUnit3Result rxx = new NUnit3Result();

        rxx.FileName  = path;
        rxx.Format    = "nunit3";
        rxx.Transform = null;
        s.Results     = new List <NUnit3Result>
        {
            rxx
        };
        s.ArgumentCustomization = args =>
        {
            if (whereClause != null)
            {
                args.Append("--where");
                args.AppendQuoted(whereClause);
            }
            // Additionally generate NUnit2 output.
            AppendNUnit3AlternativeOutput(args,
                                          outputDir.CombineWithFilePath(projectUnderTest.Project.AssemblyName + ".nunit2.xml"));
            return(args);
        };
        return(s);
    }
Beispiel #9
0
        private void AddEdgesFromProjectReferenceItems(Dictionary <ConfigurationMetadata, ParsedProject> allParsedProjects, GraphEdges edges)
        {
            Dictionary <ProjectGraphNode, HashSet <ProjectGraphNode> > transitiveReferenceCache = new(allParsedProjects.Count);

            foreach (var parsedProject in allParsedProjects)
            {
                var currentNode = parsedProject.Value.GraphNode;

                var requiresTransitiveProjectReferences = _projectInterpretation.RequiresTransitiveProjectReferences(currentNode.ProjectInstance);

                foreach (var referenceInfo in parsedProject.Value.ReferenceInfos)
                {
                    // Always add direct references.
                    currentNode.AddProjectReference(
                        allParsedProjects[referenceInfo.ReferenceConfiguration].GraphNode,
                        referenceInfo.ProjectReferenceItem,
                        edges);

                    // Add transitive references only if the project requires it.
                    if (requiresTransitiveProjectReferences)
                    {
                        foreach (var transitiveProjectReference in GetTransitiveProjectReferencesExcludingSelf(allParsedProjects[referenceInfo.ReferenceConfiguration]))
                        {
                            currentNode.AddProjectReference(
                                transitiveProjectReference,
                                new ProjectItemInstance(
                                    project: currentNode.ProjectInstance,
                                    itemType: ProjectInterpretation.TransitiveReferenceItemName,
                                    includeEscaped: referenceInfo.ReferenceConfiguration.ProjectFullPath,
                                    directMetadata: null,
                                    definingFileEscaped: currentNode.ProjectInstance.FullPath
                                    ),
                                edges);
                        }
                    }
                }
            }

            HashSet <ProjectGraphNode> GetTransitiveProjectReferencesExcludingSelf(ParsedProject parsedProject)
            {
                if (transitiveReferenceCache.TryGetValue(parsedProject.GraphNode, out HashSet <ProjectGraphNode> transitiveReferences))
                {
                    return(transitiveReferences);
                }

                transitiveReferences = new();

                // Add the results to the cache early, even though it'll be incomplete until the loop below finishes. This helps handle cycles by not allowing them to recurse infinitely.
                // Note that this makes transitive references incomplete in the case of a cycle, but direct dependencies are always added so a cycle will still be detected and an exception will still be thrown.
                transitiveReferenceCache[parsedProject.GraphNode] = transitiveReferences;

                foreach (ProjectInterpretation.ReferenceInfo referenceInfo in parsedProject.ReferenceInfos)
                {
                    ParsedProject reference = allParsedProjects[referenceInfo.ReferenceConfiguration];
                    transitiveReferences.Add(reference.GraphNode);

                    // Perf note: avoiding UnionWith to avoid boxing the HashSet enumerator.
                    foreach (ProjectGraphNode transitiveReference in GetTransitiveProjectReferencesExcludingSelf(reference))
                    {
                        transitiveReferences.Add(transitiveReference);
                    }
                }

                return(transitiveReferences);
            }
        }
Beispiel #10
0
    /// <summary>
    ///     Thanks to NuGet being an extension of VisualStudio instead of a proper standalone
    ///     tool (just look at the tight binding of 'nuget pack .xxproj' into MSBuild internals
    ///     and the massive amount of code just to manage that stuff), we cannot build NuGet
    ///     packages from existing binaries by just looking at the project and nuspec files.
    ///     Therefore we preemtively produce nuget packages as soon as the compiler finished
    ///     building the project (and before any testing has been done). We then copy the
    ///     NuGet package into a safe place before eventually pushing it to a server or achiving
    ///     the files by other means.
    /// </summary>
    /// <param name="project"></param>
    public static void ProduceNuGetPackage(ParsedProject project)
    {
        var nuspec = project.ProjectFile.ChangeExtension(".nuspec");

        if (!Context.FileExists(nuspec))
        {
            Context.Log.Verbose("Skipping package as there is no *.nuspec file for project "
                                + BuildConfig.AsRelativePath(project.ProjectFile));
            return;
        }

        var settings = new NuGetXPackSettings(PackSettings);

        if (PackSettingsCustomisation != null)
        {
            settings = PackSettingsCustomisation.Invoke(settings, project);
        }

        var nugetSettings = new NuGetPackSettings();

        XBuildHelper.ApplyToolSettings(nugetSettings, settings);
        nugetSettings.Verbosity = settings.Verbosity;
        nugetSettings.Symbols   = settings.Symbols.GetValueOrDefault();
        nugetSettings.IncludeReferencedProjects = settings.IncludeReferencedProjects.GetValueOrDefault();
        nugetSettings.Properties            = new Dictionary <string, string>(settings.Properties);
        nugetSettings.ArgumentCustomization = settings.ArgumentCustomization;

        if (NuGetPackSettingsCustomisation != null)
        {
            nugetSettings = NuGetPackSettingsCustomisation.Invoke(nugetSettings, project);
            if (nugetSettings.Properties == null)
            {
                nugetSettings.Properties = new Dictionary <string, string>();
            }
        }

        var targetPath = BuildConfig.ComputeOutputPath("packages", project);

        Context.CreateDirectory(targetPath);
        nugetSettings.WorkingDirectory            = targetPath;
        nugetSettings.Properties["Configuration"] = BuildConfig.Configuration;
        nugetSettings.Properties["Platform"]      = BuildConfig.ConvertPlatformTargetToString(project.Platform);
        if (!string.IsNullOrEmpty(Version))
        {
            Context.Log.Information("Publishing package as version " + Version);
            nugetSettings.Properties["version"] = Version;
            nugetSettings.Version = Version;
        }

        if (settings.Tool.GetValueOrDefault())
        {
            var argCustomization = nugetSettings.ArgumentCustomization;
            nugetSettings.ArgumentCustomization = args =>
            {
                if (argCustomization != null)
                {
                    args = argCustomization.Invoke(args);
                }
                args.Append("-Tool");
                return(args);
            };
        }

        Context.NuGetPack(project.ProjectFile, nugetSettings);

        var assembly = LoadZipAssembly();

        if (assembly != null)
        {
            Context.Log.Information("Unzipping nuget package: " + targetPath.FullPath + "/*.nupkg");
            foreach (var file in Context.Globber.GetFiles(targetPath.FullPath + "/*.nupkg"))
            {
                Context.Log.Information("Unzipping " + file);
                Unzip(file, targetPath, assembly);
            }
        }
    }
Beispiel #11
0
 static bool HasTestFramework(ParsedProject project, string id)
 {
     return(project.Project.References.Any(refs => refs.Include.StartsWith(id, true, CultureInfo.InvariantCulture)));
 }
Beispiel #12
0
 public static DirectoryPath ComputeProjectUnitTestPath(ParsedProject project)
 {
     return(BuildConfig.ComputeOutputPath("tests", project));
 }
Beispiel #13
0
    static void InvokeUnitTest(ParsedProject project, PlatformTarget platformTarget, AnyUnitTestSettings settings)
    {
        if (settings == null)
        {
            throw new ArgumentNullException("settings");
        }
        if (project == null)
        {
            throw new ArgumentNullException("project");
        }
        var path = project.ProjectFile;
        var relativeProjectFile = Context.Environment.WorkingDirectory.GetRelativePath(path);

        // parse referenced dependencies. We assume that if you reference a unit-test dll in your project, then that project
        // in fact contains tests. But there are always exceptions, and thus we allow you to exclude projects as well.
        if (ExcludeFromUnitTests.Contains(project.Project.AssemblyName) ||
            ExcludeFromUnitTests.Contains(project.Project.ProjectGuid) ||
            ExcludeFromUnitTests.Contains(relativeProjectFile.ToString()))
        {
            Context.Log.Verbose(string.Format("    Skipping project {0} as it was explicitly excluded from testing.",
                                              relativeProjectFile));
            return;
        }

        Context.Log.Information(string.Format("Searching for tests in {0} with platform {1}",
                                              relativeProjectFile,
                                              platformTarget));

        var binDir  = BuildActions.ComputeProjectBinPath(project);
        var testDir = ComputeProjectUnitTestPath(project);
        var testDll = binDir.CombineWithFilePath(ComputeTargetFile(project));

        if (HasTestFramework(project, NUnit2Reference))
        {
            Context.Log.Verbose(string.Format("    Testing with NUnit 2: {0}.", relativeProjectFile));

            Context.CreateDirectory(testDir);
            Context.NUnit(new[] { testDll }, BuildNUnitSettings(project, settings, testDir));
        }
        else if (HasTestFramework(project, NUnit3Reference))
        {
            Context.Log.Verbose(string.Format("    Testing with NUnit 3: {0}.", relativeProjectFile));

            Context.CreateDirectory(testDir);
            Context.NUnit3(new[] { testDll }, BuildNUnit3Settings(project, settings, testDir));
        }
        else if (HasTestFramework(project, Xunit2Reference))
        {
            Context.Log.Verbose(string.Format("    Testing with XUnit 2: {0}.", relativeProjectFile));

            Context.CreateDirectory(testDir);
            Context.XUnit2(new[] { testDll }, BuildXUnit2Settings(project, settings, testDir));

            var inputFile  = testDir.CombineWithFilePath(project.Project.AssemblyName + ".xunit2.xml");
            var outputFile = testDir.CombineWithFilePath(project.Project.AssemblyName + ".nunit2.xml");
            Context.XmlTransform(Context.File("tools/xunit.runner.console/tools/NUnitXml.xslt"), inputFile, outputFile);
        }
        else if (HasTestFramework(project, Xunit1Reference))
        {
            Context.Log.Verbose(string.Format("    Testing with XUnit 1: {0}.", relativeProjectFile));

            Context.CreateDirectory(testDir);
            var xunitSettings = BuildXUnitSettings(project, settings, testDir);
            var xunitRunner   = new FixedXUnitRunner(Context.FileSystem, Context.Environment, Context.ProcessRunner,
                                                     Context.Tools);
            xunitRunner.Run(testDll, xunitSettings, settings.ForceX86 || project.Platform == PlatformTarget.x86);

            var inputFile  = testDir.CombineWithFilePath(project.Project.AssemblyName + ".xunit.xml");
            var outputFile = testDir.CombineWithFilePath(project.Project.AssemblyName + ".nunit2.xml");
            Context.XmlTransform(Context.File("tools/xunit.runners/tools/NUnitXml.xslt"), inputFile, outputFile);
        }
        else
        {
            Context.Log.Verbose(
                string.Format("    Skipping project {0} as it does not reference a supported unit-testing framework.",
                              relativeProjectFile));
        }
    }
Beispiel #14
0
        private void AddEdgesFromProjectReferenceItems(Dictionary <ConfigurationMetadata, ParsedProject> allParsedProjects, GraphEdges edges)
        {
            var transitiveReferenceCache = new Dictionary <ProjectGraphNode, HashSet <ProjectGraphNode> >(allParsedProjects.Count);

            foreach (var parsedProject in allParsedProjects)
            {
                var currentNode = parsedProject.Value.GraphNode;

                var requiresTransitiveProjectReferences = _projectInterpretation.RequiresTransitiveProjectReferences(currentNode.ProjectInstance);

                foreach (var referenceInfo in parsedProject.Value.ReferenceInfos)
                {
                    // Always add direct references.
                    currentNode.AddProjectReference(
                        allParsedProjects[referenceInfo.ReferenceConfiguration].GraphNode,
                        referenceInfo.ProjectReferenceItem,
                        edges);

                    // Add transitive references only if the project requires it.
                    if (requiresTransitiveProjectReferences)
                    {
                        foreach (var transitiveProjectReference in GetTransitiveProjectReferencesExcludingSelf(allParsedProjects[referenceInfo.ReferenceConfiguration]))
                        {
                            currentNode.AddProjectReference(
                                transitiveProjectReference,
                                new ProjectItemInstance(
                                    project: currentNode.ProjectInstance,
                                    itemType: ProjectInterpretation.TransitiveReferenceItemName,
                                    includeEscaped: referenceInfo.ReferenceConfiguration.ProjectFullPath,
                                    directMetadata: null,
                                    definingFileEscaped: currentNode.ProjectInstance.FullPath
                                    ),
                                edges);
                        }
                    }
                }
            }

            HashSet <ProjectGraphNode> GetTransitiveProjectReferencesExcludingSelf(ParsedProject parsedProject)
            {
                HashSet <ProjectGraphNode> references = new();

                GetTransitiveProjectReferencesExcludingSelfHelper(parsedProject, references, null);
                return(references);
            }

            // transitiveReferences contains all of the references we've found so far from the initial GetTransitiveProjectReferencesExcludingSelf call.
            // referencesFromHere is essentially "reset" at each level of the recursion.
            // The first is important because if we find a cycle at some point, we need to know not to keep recursing. We wouldn't have added to transitiveReferenceCache yet, since we haven't finished
            // finding all the transitive references yet.
            // On the other hand, the second is important to help us fill that cache afterwards. The cache is from a particular node to all of its references, including transitive references
            // but not including itself, which means we can't include parents as we would if we used transitiveReferences. You can see that for any particular call, it creates a new "toCache"
            // HashSet that we fill with direct references and pass as referencesFromHere in recursive calls to fill it with transitive references. It is then used to populate the cache.
            // Meanwhile, we avoid going into the recursive step at all if transitiveReferences already includes a particular node to avoid a StackOverflowException if there's a loop.
            void GetTransitiveProjectReferencesExcludingSelfHelper(ParsedProject parsedProject, HashSet <ProjectGraphNode> traversedReferences, HashSet <ProjectGraphNode> incompleteReferencesOfDirectlyReferencingNode)
            {
                if (transitiveReferenceCache.TryGetValue(parsedProject.GraphNode, out HashSet <ProjectGraphNode> cachedTransitiveReferences))
                {
                    traversedReferences.UnionWith(cachedTransitiveReferences);
                }
                else
                {
                    HashSet <ProjectGraphNode> referencesFromThisNode = new();
                    foreach (ProjectInterpretation.ReferenceInfo referenceInfo in parsedProject.ReferenceInfos)
                    {
                        ParsedProject reference = allParsedProjects[referenceInfo.ReferenceConfiguration];
                        if (traversedReferences.Add(reference.GraphNode))
                        {
                            GetTransitiveProjectReferencesExcludingSelfHelper(reference, traversedReferences, referencesFromThisNode);
                        }
                        else if (transitiveReferenceCache.TryGetValue(reference.GraphNode, out cachedTransitiveReferences))
                        {
                            referencesFromThisNode.UnionWith(cachedTransitiveReferences);
                        }
                        referencesFromThisNode.Add(reference.GraphNode);
                    }

                    // We've returned from recursing through all transitive references
                    // of this node, so add that set to the cache
                    transitiveReferenceCache[parsedProject.GraphNode] = referencesFromThisNode;
                    if (incompleteReferencesOfDirectlyReferencingNode is not null)
                    {
                        // Also add it to the set of transitive dependencies of
                        // the referencing node (which are probably still incomplete)
                        incompleteReferencesOfDirectlyReferencingNode.UnionWith(referencesFromThisNode);
                    }
                }
            }
        }
 public ProjectReference(ParsedProject project, string unevaluatedInclude)
 {
     this.Project            = project;
     this.UnevaluatedInclude = unevaluatedInclude;
 }
Beispiel #16
0
 internal static DirectoryPath ComputeProjectBinPath(ParsedProject project)
 {
     return(BuildConfig.ComputeOutputPath("compiled", project));
 }