コード例 #1
0
ファイル: FileLogger_Tests.cs プロジェクト: Nirmal4G/msbuild
        public void LogVerbosityMessage(LoggerVerbosity loggerVerbosity, bool shouldContain)
        {
            using (var testEnvironment = TestEnvironment.Create())
            {
                var fileLogger = new FileLogger
                {
                    Verbosity = loggerVerbosity
                };

                var logFile = testEnvironment.CreateFile(".log");
                fileLogger.Parameters = "logfile=" + logFile.Path;

                Project project = ObjectModelHelpers.CreateInMemoryProject(@"
                <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
                    <Target Name=`Build` />
                </Project>
                ");

                project.Build(fileLogger);
                project.ProjectCollection.UnregisterAllLoggers();

                string log     = File.ReadAllText(logFile.Path);
                var    message = ResourceUtilities.FormatResourceStringStripCodeAndKeyword("LogLoggerVerbosity", loggerVerbosity);
                if (shouldContain)
                {
                    Assert.Contains(message, log);
                }
                else
                {
                    Assert.DoesNotContain(message, log);
                }
            }
        }
コード例 #2
0
ファイル: FileLogger_Tests.cs プロジェクト: zhuweijia/msbuild
        public void Basic()
        {
            FileLogger fileLogger = new FileLogger();
            string     logFile    = FileUtilities.GetTemporaryFile();

            fileLogger.Parameters = "verbosity=Normal;logfile=" + logFile;

            Project project = ObjectModelHelpers.CreateInMemoryProject(@"
                <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
                    <Target Name=`Build`>
                        <Message Text=`Hello world from the FileLogger`/>
                    </Target>
                </Project>
                ");

            project.Build(fileLogger);

            project.ProjectCollection.UnregisterAllLoggers();

            string log = File.ReadAllText(logFile);

            Assert.IsTrue(log.Contains("Hello world from the FileLogger"), "Log should have contained message");

            File.Delete(logFile);
        }
コード例 #3
0
        public static ActionsModule CreateFromProject(string projectFile, string outputFile, LightningDevelopmentHandle lightningDevelopmentHandle)
        {
            var engine = new Microsoft.Build.Evaluation.Project(projectFile);
            engine.Build();

            return CreateFromDll(outputFile, lightningDevelopmentHandle);
        }
コード例 #4
0
ファイル: FileLogger_Tests.cs プロジェクト: Nirmal4G/msbuild
        public void EmptyErrorLogUsingWarningsErrorsOnly(string loggerOption)
        {
            using (var env = TestEnvironment.Create())
            {
                var logFile = env.CreateFile(".log").Path;

                // Note: Only the ParallelConsoleLogger supports this scenario (log file empty on no error/warn). We
                // need to explicitly enable it here with the 'ENABLEMPLOGGING' flag.
                FileLogger fileLogger = new FileLogger {
                    Parameters = $"{loggerOption};logfile={logFile};ENABLEMPLOGGING"
                };

                Project project = ObjectModelHelpers.CreateInMemoryProject(@"
                <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
                    <Target Name=`Build`>
                        <Message Text=`Hello world from the FileLogger`/>
                    </Target>
                </Project>");

                project.Build(fileLogger);
                project.ProjectCollection.UnregisterAllLoggers();

                // File should exist and be 0 length (no summary information, etc.)
                var result = new FileInfo(logFile);
                Assert.True(result.Exists);
                Assert.Equal(0, new FileInfo(logFile).Length);
            }
        }
コード例 #5
0
        public static void MsBuild(System.Xml.XmlReader xmlProj)
        {
            var msbuild = new Microsoft.Build.Evaluation.Project(xmlProj);

            msbuild.Build();
            xmlProj.Close();
        }
コード例 #6
0
        public void ExecuteWithHost()
        {
            ScannerTask target = new ScannerTask();

            // Create the term tables and target files.
            string termFile1 = Utilities.CreateTempFile(CreateTermTableXml("countries", 2, "Geopolitical", "comment"));
            string termFile2 = Utilities.CreateTempFile(CreateTermTableXml("shoot", 3, "Profanity", "comment"));

            string scanFile1 = Utilities.CreateTempTxtFile("the word 'countries' should produce a hit");
            string scanFile2 = Utilities.CreateTempTxtFile("the word 'shoot' should produce a hit");

            // Create the project that will execute the task.
            Microsoft.Build.Evaluation.Project project = Utilities.SetupMSBuildProject(new string[] { scanFile1, scanFile2 }, new string[] { termFile1, termFile2 });

            // Set up a custom logger to capture the output.
            MockLogger logger = new MockLogger();

            project.ProjectCollection.RegisterLogger(logger);
            int errors   = 0;
            int warnings = 0;
            int messages = 0;

            logger.OnError += delegate(object sender, BuildErrorEventArgs args)
            {
                ++errors;
            };
            logger.OnWarning += delegate(object sender, BuildWarningEventArgs args)
            {
                ++warnings;
            };
            logger.OnMessage += delegate(object sender, BuildMessageEventArgs args)
            {
                ++messages;
            };

            Microsoft.Build.Construction.ProjectTaskElement task = Utilities.GetScannerTask(project);

            // Set the host object for the task.
            int            hostUpdates = 0;
            MockHostObject host        = new MockHostObject();

            host.OnAddResult += delegate(object sender, MockHostObject.AddResultArgs args)
            {
                ++hostUpdates;
            };
            logger.OnBuildStart += delegate(object sender, BuildStartedEventArgs args)
            {
                project.ProjectCollection.HostServices.RegisterHostObject(project.FullPath, "AfterBuild", "ScannerTask", host);
            };

            project.Build("AfterBuild");

            Assert.AreEqual(0, errors, "Build did not log expected number of errors.");
            Assert.AreEqual(0, warnings, "Build did not log expected number of warnings.");
            Assert.AreEqual(4, messages, "Build did not log expected number of messages.");
            Assert.AreEqual(2, hostUpdates, "Build did not send expected number of results to host.");
        }
コード例 #7
0
        public void AddNewErrorWarningMessageElement()
        {
            MockLogger logger = new MockLogger();

            /**
             * <Project DefaultTargets=`Build` ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
             *   <Target Name=`Build`>
             *   </Target>
             * </Project
             */

            ProjectRootElement projectXml = ProjectRootElement.Create();
            ProjectTargetElement target = projectXml.AddTarget("Build");
            projectXml.DefaultTargets = "Build";
            projectXml.ToolsVersion = ObjectModelHelpers.MSBuildDefaultToolsVersion;

            SolutionProjectGenerator.AddErrorWarningMessageElement(target, XMakeElements.message, true, "SolutionVenusProjectNoClean");
            SolutionProjectGenerator.AddErrorWarningMessageElement(target, XMakeElements.warning, true, "SolutionParseUnknownProjectType", "proj1.csproj");
            SolutionProjectGenerator.AddErrorWarningMessageElement(target, XMakeElements.error, true, "SolutionInvalidSolutionConfiguration");

            Project project = new Project(projectXml);

            project.Build(logger);

            string code = null;
            string keyword = null;
            string text = ResourceUtilities.FormatResourceString(out code, out keyword, "SolutionParseUnknownProjectType", "proj1.csproj");

            // check the error event
            Assert.AreEqual(1, logger.Warnings.Count);
            BuildWarningEventArgs warning = logger.Warnings[0];

            Assert.AreEqual(text, warning.Message);
            Assert.AreEqual(code, warning.Code);
            Assert.AreEqual(keyword, warning.HelpKeyword);

            code = null;
            keyword = null;
            text = ResourceUtilities.FormatResourceString(out code, out keyword, "SolutionInvalidSolutionConfiguration");

            // check the warning event
            Assert.AreEqual(1, logger.Errors.Count);
            BuildErrorEventArgs error = logger.Errors[0];

            Assert.AreEqual(text, error.Message);
            Assert.AreEqual(code, error.Code);
            Assert.AreEqual(keyword, error.HelpKeyword);

            code = null;
            keyword = null;
            text = ResourceUtilities.FormatResourceString(out code, out keyword, "SolutionVenusProjectNoClean");

            // check the message event
            Assert.IsTrue(logger.FullLog.Contains(text), "Log should contain the regular message");
        }
コード例 #8
0
ファイル: Project.cs プロジェクト: slpsys/BuildSniffer
 /// <summary>
 /// Builds this project, using the default targets and the given loggers.
 /// </summary>
 /// <param name="loggers">An enumerator over all loggers to be used during the build.</param>
 /// <returns>
 /// Returns true on success; false otherwise.
 /// </returns>
 public bool Build(IEnumerable<ILogger> loggers)
 {
     var result = false;
     this.SwapMSBuildTasks();
     using (var reader = this.Document.CreateReader())
     {
         reader.MoveToContent();
         var innerProject = new Microsoft.Build.Evaluation.Project(reader);
         result = innerProject.Build(loggers.Prepend(this.Logger));
         reader.Close();
     }
     return result;
 }
コード例 #9
0
        /// <summary>
        /// Builds this project, using the default targets and the given loggers.
        /// </summary>
        /// <param name="loggers">An enumerator over all loggers to be used during the build.</param>
        /// <returns>
        /// Returns true on success; false otherwise.
        /// </returns>
        public bool Build(IEnumerable <ILogger> loggers)
        {
            var result = false;

            this.SwapMSBuildTasks();
            using (var reader = this.Document.CreateReader())
            {
                reader.MoveToContent();
                var innerProject = new Microsoft.Build.Evaluation.Project(reader);
                result = innerProject.Build(loggers.Prepend(this.Logger));
                reader.Close();
            }
            return(result);
        }
コード例 #10
0
        public void ExecuteWithoutHost()
        {
            ScannerTask target = new ScannerTask();

            // Create the term tables and target files.
            string termFile1 = Utilities.CreateTempFile(CreateTermTableXml("countries", 2, "Geopolitical", "comment"));
            string termFile2 = Utilities.CreateTempFile(CreateTermTableXml("shoot", 3, "Profanity", "comment"));

            string scanFile1 = Utilities.CreateTempTxtFile("the word 'countries' should produce a hit");
            string scanFile2 = Utilities.CreateTempTxtFile("the word 'shoot' should produce a hit");

            // Create the project that will execute the task.
            Microsoft.Build.Evaluation.Project project = Utilities.SetupMSBuildProject(new string[] { scanFile1, scanFile2 }, new string[] { termFile1, termFile2 });

            // Set up a custom logger to capture the output.
            MockLogger logger = new MockLogger();

            project.ProjectCollection.RegisterLogger(logger);
            int errors   = 0;
            int warnings = 0;
            int messages = 0;

            logger.OnError += delegate(object sender, BuildErrorEventArgs args)
            {
                ++errors;
            };
            logger.OnWarning += delegate(object sender, BuildWarningEventArgs args)
            {
                ++warnings;
            };
            logger.OnMessage += delegate(object sender, BuildMessageEventArgs args)
            {
                ++messages;
            };

            project.Build("AfterBuild");

            Assert.AreEqual(0, errors, "Build did not log expected number of errors.");
            Assert.AreEqual(2, warnings, "Build did not log expected number of warnings.");
            Assert.AreEqual(2, messages, "Build did not log expected number of messages.");
        }
コード例 #11
0
        public void SolutionConfigurationWithDependenciesRelaysItsOutputs()
        {
            #region Large strings representing solution & projects
            const string solutionFileContents =
                @"
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 11
Project(`{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}`) = `B`, `B.csproj`, `{881C1674-4ECA-451D-85B6-D7C59B7F16FA}`
	ProjectSection(ProjectDependencies) = postProject
		{4A727FF8-65F2-401E-95AD-7C8BBFBE3167} = {4A727FF8-65F2-401E-95AD-7C8BBFBE3167}
	EndProjectSection
EndProject
Project(`{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}`) = `C`, `C.csproj`, `{4A727FF8-65F2-401E-95AD-7C8BBFBE3167}`
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Release|Any CPU = Release|Any CPU
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = preSolution
		{4A727FF8-65F2-401E-95AD-7C8BBFBE3167}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{4A727FF8-65F2-401E-95AD-7C8BBFBE3167}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{4A727FF8-65F2-401E-95AD-7C8BBFBE3167}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{4A727FF8-65F2-401E-95AD-7C8BBFBE3167}.Release|Any CPU.Build.0 = Release|Any CPU
		{881C1674-4ECA-451D-85B6-D7C59B7F16FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{881C1674-4ECA-451D-85B6-D7C59B7F16FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{881C1674-4ECA-451D-85B6-D7C59B7F16FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{881C1674-4ECA-451D-85B6-D7C59B7F16FA}.Release|Any CPU.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
EndGlobal
";
            const string projectBravoFileContents =
                    @"
                        <Project ToolsVersion='msbuilddefaulttoolsversion' DefaultTargets='Build' xmlns='msbuildnamespace'>
                            <Target Name='Build' Outputs='@(ComputedQuestion)'>
                                <ItemGroup>
                                    <ComputedQuestion Include='What do you get if you multiply six by nine' />
                                </ItemGroup>
                            </Target>
                        </Project>
                    ";
            const string projectCharlieFileContents =
                    @"
                        <Project ToolsVersion='msbuilddefaulttoolsversion' DefaultTargets='Build' xmlns='msbuildnamespace'>
                            <Target Name='Build' Outputs='@(ComputedAnswer)'>
                                <ItemGroup>
                                    <ComputedAnswer Include='42' />
                                </ItemGroup>
                            </Target>
                        </Project>
                    ";
            const string automaticProjectFileContents = @"
<Project ToolsVersion='msbuilddefaulttoolsversion' DefaultTargets='compile' xmlns='msbuildnamespace'>
	<Target Name='compile'>
		<MSBuild Projects='B.csproj' Targets='Build'>
			<Output
				TaskParameter='TargetOutputs'
				ItemName='BravoProjectOutputs' />
		</MSBuild>
		<Message Importance='high' Text='BravoProjectOutputs: @(BravoProjectOutputs)' />
		<MSBuild Projects='C.csproj' Targets='Build'>
			<Output
				TaskParameter='TargetOutputs'
				ItemName='CharlieProjectOutputs' />
		</MSBuild>
		<Message Importance='high' Text='CharlieProjectOutputs: @(CharlieProjectOutputs)' />
		<MSBuild Projects='B.csproj.metaproj' Targets='Build'>
			<Output
				TaskParameter='TargetOutputs'
				ItemName='BravoMetaProjectOutputs' />
		</MSBuild>
		<Message Importance='high' Text='BravoMetaProjectOutputs: @(BravoMetaProjectOutputs)' />
		<Error Condition=` '@(CharlieProjectOutputs);@(BravoProjectOutputs)' != '@(BravoMetaProjectOutputs)' ` Text='Metaproj must relay outputs' />
	</Target>
</Project>";
            #endregion
            // arrange
            var logger = new MockLogger();
            var loggers = new List<ILogger>(1) {logger};
            var solutionFile = ObjectModelHelpers.CreateFileInTempProjectDirectory("MSBuildIssue.sln", solutionFileContents);
            ObjectModelHelpers.CreateFileInTempProjectDirectory("B.csproj", projectBravoFileContents);
            ObjectModelHelpers.CreateFileInTempProjectDirectory("C.csproj", projectCharlieFileContents);
            var solution = new SolutionFile {FullPath = solutionFile};
            solution.ParseSolutionFile();

            // act
            var instances = SolutionProjectGenerator.Generate(solution, null, null, new BuildEventContext(0, 0, 0, 0), null);

            // assert
            var projectBravoMetaProject = instances[1];
            Assert.IsFalse(projectBravoMetaProject.Targets.Any(kvp => kvp.Value.Outputs.Equals("@()")), "The outputItem parameter can be null; the Target element should not have an Outputs attribute in that case.");
            // saves the in-memory metaproj to disk
            projectBravoMetaProject.ToProjectRootElement().Save(projectBravoMetaProject.FullPath);
            var automaticProjectFile = ObjectModelHelpers.CreateFileInTempProjectDirectory("automatic.msbuild", automaticProjectFileContents);
            var automaticProject = new Project(automaticProjectFile);
            var buildResult = automaticProject.Build(loggers);
            Assert.AreEqual(true, buildResult, String.Join(Environment.NewLine, logger.Errors.Select(beea => beea.Message)));
        }
コード例 #12
0
ファイル: Program.cs プロジェクト: missdiog/SharpPack
        static void Main(string[] args)
        {
            try
            {
                //SharpCradle command modules
                if (args.Length <= 0 || args[0] == "help" || args[0] == "?")
                {
                    help();
                }
                else if (args[0] == "-f")
                {
                    string   domain             = ".\\";
                    string   uname              = "anonymous";
                    string   password           = "";
                    string   folderPathToBinary = args[1];
                    object[] cmd = args.Skip(2).ToArray();

                    if (args[0] == "-f" & args[1] == "-c")
                    {
                        domain             = args[2];
                        uname              = args[3];
                        password           = args[4];
                        folderPathToBinary = args[5];
                        cmd = args.Skip(6).ToArray();
                    }
                    using (new Impersonation(domain, uname, password))
                    {
                        //Access folder and read the bytes from the binary file
                        FileStream   fs  = new FileStream(folderPathToBinary, FileMode.Open);
                        BinaryReader br  = new BinaryReader(fs);
                        byte[]       bin = br.ReadBytes(Convert.ToInt32(fs.Length));
                        fs.Close();
                        br.Close();
                        loadAssembly(bin, cmd);
                    }
                }//End if -f
                else if (args[0] == "-w")
                {
                    object[]     cmd = args.Skip(2).ToArray();
                    MemoryStream ms  = new MemoryStream();
                    using (WebClient client = new WebClient())
                    {
                        //Access web and read the bytes from the binary file
                        System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls | System.Net.SecurityProtocolType.Tls11 | System.Net.SecurityProtocolType.Tls12;
                        ms = new MemoryStream(client.DownloadData(args[1]));
                        BinaryReader br  = new BinaryReader(ms);
                        byte[]       bin = br.ReadBytes(Convert.ToInt32(ms.Length));
                        ms.Close();
                        br.Close();
                        loadAssembly(bin, cmd);
                    }
                }//End if -w
                else if (args[0] == "-p")
                {
                    //Access web to capture, build, and execute inline CS project file
                    var proj    = System.Xml.XmlReader.Create(args[1]);
                    var msbuild = new Microsoft.Build.Evaluation.Project(proj);
                    msbuild.Build();
                    proj.Close();
                } //End if -p
            }     //End try
            catch
            {
                Console.WriteLine("Something went wrong! Check parameters and make sure binary uses managed code");
            } //End catch
        }     //End Main
コード例 #13
0
        public void SolutionConfigurationWithDependenciesRelaysItsOutputs()
        {
            #region Large strings representing solution & projects
            const string solutionFileContents =
                @"
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 11
Project(`{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}`) = `B`, `B.csproj`, `{881C1674-4ECA-451D-85B6-D7C59B7F16FA}`
	ProjectSection(ProjectDependencies) = postProject
		{4A727FF8-65F2-401E-95AD-7C8BBFBE3167} = {4A727FF8-65F2-401E-95AD-7C8BBFBE3167}
	EndProjectSection
EndProject
Project(`{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}`) = `C`, `C.csproj`, `{4A727FF8-65F2-401E-95AD-7C8BBFBE3167}`
EndProject
Project(`{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}`) = `D`, `D.csproj`, `{B6E7E06F-FC0B-48F1-911A-55E0E1566F00}`
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = preSolution
		{4A727FF8-65F2-401E-95AD-7C8BBFBE3167}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{4A727FF8-65F2-401E-95AD-7C8BBFBE3167}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{881C1674-4ECA-451D-85B6-D7C59B7F16FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{881C1674-4ECA-451D-85B6-D7C59B7F16FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{B6E7E06F-FC0B-48F1-911A-55E0E1566F00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{B6E7E06F-FC0B-48F1-911A-55E0E1566F00}.Debug|Any CPU.Build.0 = Debug|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
EndGlobal
";
            const string projectBravoFileContents =
                    @"
                        <Project ToolsVersion='msbuilddefaulttoolsversion' DefaultTargets='Build' xmlns='msbuildnamespace'>
                            <Target Name='Build' Outputs='@(ComputedQuestion)'>
                                <ItemGroup>
                                    <ComputedQuestion Include='What do you get if you multiply six by nine' />
                                </ItemGroup>
                            </Target>
                            <ItemGroup>
                                <ProjectReference Include='D.csproj'>
                                    <Project>{B6E7E06F-FC0B-48F1-911A-55E0E1566F00}</Project>
                                    <Name>D</Name>
                                </ProjectReference>
                            </ItemGroup>
                        </Project>
                    ";
            const string projectCharlieFileContents =
                    @"
                        <Project ToolsVersion='msbuilddefaulttoolsversion' DefaultTargets='Build' xmlns='msbuildnamespace'>
                            <Target Name='Build' Outputs='@(ComputedAnswer)'>
                                <ItemGroup>
                                    <ComputedAnswer Include='42' />
                                </ItemGroup>
                            </Target>
                        </Project>
                    ";
            const string projectDeltaFileContents =
                    @"
                        <Project ToolsVersion='msbuilddefaulttoolsversion' DefaultTargets='Build' xmlns='msbuildnamespace'>
                            <PropertyGroup>
                                <ProjectGuid>{B6E7E06F-FC0B-48F1-911A-55E0E1566F00}</ProjectGuid>
                            </PropertyGroup>
                            <Target Name='Build' Outputs='@(ComputedPunctuation)'>
                                <ItemGroup>
                                    <ComputedPunctuation Include='!!!' />
                                </ItemGroup>
                            </Target>
                        </Project>
                    ";
            const string automaticProjectFileContents = @"
<Project ToolsVersion='msbuilddefaulttoolsversion' DefaultTargets='compile' xmlns='msbuildnamespace'>
    <Target Name='compile'>
        <!-- Build projects to get a baseline for their output -->
        <MSBuild Projects='B.csproj' Targets='Build'>
            <Output
                TaskParameter='TargetOutputs'
                ItemName='BravoProjectOutputs' />
        </MSBuild>
        <Message Importance='high' Text='BravoProjectOutputs: @(BravoProjectOutputs)' />

        <MSBuild Projects='C.csproj' Targets='Build'>
            <Output
                TaskParameter='TargetOutputs'
                ItemName='CharlieProjectOutputs' />
        </MSBuild>
        <Message Importance='high' Text='CharlieProjectOutputs: @(CharlieProjectOutputs)' />

        <MSBuild Projects='D.csproj' Targets='Build'>
            <Output
                TaskParameter='TargetOutputs'
                ItemName='DeltaProjectOutputs' />
        </MSBuild>
        <Message Importance='high' Text='DeltaProjectOutputs: @(DeltaProjectOutputs)' />

        <PropertyGroup>
            <StringifiedBravoProjectOutputs>@(BravoProjectOutputs)</StringifiedBravoProjectOutputs>
            <StringifiedCharlieProjectOutputs>@(CharlieProjectOutputs)</StringifiedCharlieProjectOutputs>
            <StringifiedDeltaProjectOutputs>@(DeltaProjectOutputs)</StringifiedDeltaProjectOutputs>
        </PropertyGroup>

        <!-- Explicitly build the metaproject generated for B -->
        <MSBuild Projects='B.csproj.metaproj' Targets='Build'>
            <Output
                TaskParameter='TargetOutputs'
                ItemName='BravoMetaProjectOutputs' />
        </MSBuild>
        <Message Importance='high' Text='BravoMetaProjectOutputs: @(BravoMetaProjectOutputs)' />
        <Error Condition=` '@(BravoProjectOutputs)' != '@(BravoMetaProjectOutputs)' ` Text='Metaproj outputs must match outputs of normal project build.' />

        <!-- Build the solution as a whole (which will build the metaproj and return overall outputs) -->
        <MSBuild Projects='MSBuildIssue.sln'>
            <Output
                TaskParameter='TargetOutputs'
                ItemName='SolutionProjectOutputs' />
        </MSBuild>
        <Message Importance='high' Text='SolutionProjectOutputs: @(SolutionProjectOutputs)' />
        <Error Condition=` '@(SolutionProjectOutputs->Count())' != '3' ` Text='Overall sln outputs must include outputs of each referenced project (there should be 3).' />
        <Error Condition=` '@(SolutionProjectOutputs->AnyHaveMetadataValue('Identity', '$(StringifiedBravoProjectOutputs)'))' != 'true'` Text='Overall sln outputs must include outputs of normal project build of project B.' />
        <Error Condition=` '@(SolutionProjectOutputs->AnyHaveMetadataValue('Identity', '$(StringifiedCharlieProjectOutputs)'))' != 'true' ` Text='Overall sln outputs must include outputs of normal project build of project C.' />
        <Error Condition=` '@(SolutionProjectOutputs->AnyHaveMetadataValue('Identity', '$(StringifiedDeltaProjectOutputs)'))' != 'true' ` Text='Overall sln outputs must include outputs of normal project build of project D.' />
    </Target>
</Project>";
            #endregion

            var logger = new MockLogger();
            var loggers = new List<ILogger>(1) { logger };
            var solutionFile = ObjectModelHelpers.CreateFileInTempProjectDirectory("MSBuildIssue.sln", solutionFileContents);
            ObjectModelHelpers.CreateFileInTempProjectDirectory("B.csproj", projectBravoFileContents);
            ObjectModelHelpers.CreateFileInTempProjectDirectory("C.csproj", projectCharlieFileContents);
            ObjectModelHelpers.CreateFileInTempProjectDirectory("D.csproj", projectDeltaFileContents);
            var solution = new SolutionFile { FullPath = solutionFile };
            solution.ParseSolutionFile();

            var instances = SolutionProjectGenerator.Generate(solution, null, null, new BuildEventContext(0, 0, 0, 0), null);

            var projectBravoMetaProject = instances[1];
            Assert.False(projectBravoMetaProject.Targets.Any(kvp => kvp.Value.Outputs.Equals("@()"))); // "The outputItem parameter can be null; the Target element should not have an Outputs attribute in that case."
            // saves the in-memory metaproj to disk
            projectBravoMetaProject.ToProjectRootElement().Save(projectBravoMetaProject.FullPath);
            var automaticProjectFile = ObjectModelHelpers.CreateFileInTempProjectDirectory("automatic.msbuild", automaticProjectFileContents);
            var automaticProject = new Project(automaticProjectFile);
            var buildResult = automaticProject.Build(loggers);

            // NOTE: most of the actual assertions for this test are embedded in automaticProjectFileContents as <Error>s
            Assert.True(buildResult, String.Join(Environment.NewLine, logger.Errors.Select(beea => beea.Message)));
        }