public void ImportFromExtensionsPathNotFound()
        {
            string extnDir1 = null;
            string mainProjectPath = null;

            try {
                extnDir1 = GetNewExtensionsPathAndCreateFile("extensions1", Path.Combine("foo", "extn.proj"), GetExtensionTargetsFileContent1());
                mainProjectPath = ObjectModelHelpers.CreateFileInTempProjectDirectory("main.proj", GetMainTargetFileContent());

                var projColln = new ProjectCollection();
                projColln.ResetToolsetsForTests(WriteConfigFileAndGetReader("MSBuildExtensionsPath", extnDir1, Path.Combine("tmp", "nonexistant")));
                var logger = new MockLogger();
                projColln.RegisterLogger(logger);

                Assert.Throws<InvalidProjectFileException>(() => projColln.LoadProject(mainProjectPath));

                logger.AssertLogContains("MSB4226");
            } finally {
                if (mainProjectPath != null)
                {
                    FileUtilities.DeleteNoThrow(mainProjectPath);
                }
                if (extnDir1 != null)
                {
                    FileUtilities.DeleteDirectoryNoThrow(extnDir1, recursive: true);
                }
            }
        }
        void CreateAndBuildProjectForImportFromExtensionsPath(string mainProjectPath, string extnPathPropertyName, string[] extnDirs, Action<string[]> setExtensionsPath,
                Action<Project, MockLogger> action)
        {
            try {
                var projColln = new ProjectCollection();
                projColln.ResetToolsetsForTests(WriteConfigFileAndGetReader(extnPathPropertyName, extnDirs));
                var logger = new MockLogger();
                projColln.RegisterLogger(logger);
                var project = projColln.LoadProject(mainProjectPath);

                action(project, logger);
            } finally {
                if (mainProjectPath != null)
                {
                    FileUtilities.DeleteNoThrow(mainProjectPath);
                }

                if (extnDirs != null)
                {
                    foreach (var extnDir in extnDirs)
                    {
                        FileUtilities.DeleteDirectoryNoThrow(extnDir, recursive: true);
                    }
                }
            }
        }
        public void FallbackImportWithUndefinedProperty()
        {
            string mainTargetsFileContent = @"
               <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                   <Import Project='$(UndefinedProperty)\file.props' Condition=""Exists('$(UndefinedProperty)\file.props')"" />
                   <Target Name='Main' DependsOnTargets='FromExtn' />
               </Project>";

            string extnTargetsFileContentTemplate = @"
               <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                   <Target Name='FromExtn'>
                       <Message Text='Running FromExtn'/>
                   </Target>
               </Project>";

            var configFileContents = @"
                <configuration>
                  <configSections>
                    <section name=""msbuildToolsets"" type=""Microsoft.Build.Evaluation.ToolsetConfigurationSection, Microsoft.Build"" />
                  </configSections>
                  <msbuildToolsets default=""14.1"">
                    <toolset toolsVersion=""14.1"">
                      <property name=""MSBuildToolsPath"" value="".""/>
                      <property name=""MSBuildBinPath"" value="".""/>
                      <projectImportSearchPaths>
                        <searchPaths os=""" + NativeMethodsShared.GetOSNameForExtensionsPath() + @""">
                          <property name=""UndefinedProperty"" value=""$(FallbackExpandDir1)"" />
                        </searchPaths>
                      </projectImportSearchPaths>
                     </toolset>
                  </msbuildToolsets>
                </configuration>";

            string extnDir1 = null;
            string mainProjectPath = null;

            try
            {
                extnDir1 = GetNewExtensionsPathAndCreateFile("extensions1", Path.Combine("file.props"),
                    extnTargetsFileContentTemplate);

                mainProjectPath = ObjectModelHelpers.CreateFileInTempProjectDirectory("main.proj", mainTargetsFileContent);

                ToolsetConfigurationReaderTestHelper.WriteConfigFile(configFileContents);
                var reader = GetStandardConfigurationReader();

                var projectCollection = new ProjectCollection(new Dictionary<string, string> { ["FallbackExpandDir1"] = extnDir1 });

                projectCollection.ResetToolsetsForTests(reader);
                var logger = new MockLogger();
                projectCollection.RegisterLogger(logger);

                var project = projectCollection.LoadProject(mainProjectPath);
                Assert.True(project.Build("Main"));
                logger.AssertLogContains("Running FromExtn");
            }
            finally
            {
                FileUtilities.DeleteNoThrow(mainProjectPath);
                FileUtilities.DeleteDirectoryNoThrow(extnDir1, true);
            }
        }
        public void ExpandExtensionsPathFallbackInErrorMessage()
        {
            string extnTargetsFileContentTemplate = @"
                <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                    <Target Name='FromExtn'>
                        <Message Text='Running FromExtn'/>
                    </Target>
                    <Import Project='$(MSBuildExtensionsPath)\\foo\\extn2.proj' Condition=""Exists('$(MSBuildExtensionsPath)\foo\extn.proj')"" />
                </Project>";

            var configFileContents = @"
                 <configuration>
                   <configSections>
                     <section name=""msbuildToolsets"" type=""Microsoft.Build.Evaluation.ToolsetConfigurationSection, Microsoft.Build"" />
                   </configSections>
                   <msbuildToolsets default=""14.1"">
                     <toolset toolsVersion=""14.1"">
                       <property name=""MSBuildToolsPath"" value="".""/>
                       <property name=""MSBuildBinPath"" value="".""/>
                       <projectImportSearchPaths>
                         <searchPaths os=""" + NativeMethodsShared.GetOSNameForExtensionsPath() + @""">
                           <property name=""MSBuildExtensionsPath"" value=""$(FallbackExpandDir1)"" />
                         </searchPaths>
                       </projectImportSearchPaths>
                      </toolset>
                   </msbuildToolsets>
                 </configuration>";

            string extnDir1 = null;
            string mainProjectPath = null;

            try
            {
                extnDir1 = GetNewExtensionsPathAndCreateFile("extensions1", Path.Combine("foo", "extn.proj"),
                    extnTargetsFileContentTemplate);

                mainProjectPath = ObjectModelHelpers.CreateFileInTempProjectDirectory("main.proj",
                    GetMainTargetFileContent());

                ToolsetConfigurationReaderTestHelper.WriteConfigFile(configFileContents);
                var reader = GetStandardConfigurationReader();

                var projectCollection = new ProjectCollection(new Dictionary<string, string> { ["FallbackExpandDir1"] = extnDir1 });

                projectCollection.ResetToolsetsForTests(reader);
                var logger = new MockLogger();
                projectCollection.RegisterLogger(logger);

                Assert.Throws<InvalidProjectFileException>(() => projectCollection.LoadProject(mainProjectPath));

                // Expanded $(FallbackExpandDir) will appear in quotes in the log
                logger.AssertLogContains("\"" + extnDir1 + "\"");
            }
            finally
            {
                FileUtilities.DeleteNoThrow(mainProjectPath);
                FileUtilities.DeleteDirectoryNoThrow(extnDir1, true);
            }
        }
        public void ImportFromExtensionsPathAnd32And64()
        {
            string extnTargetsFileContentTemplate = @"
                <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                    <Target Name='FromExtn{0}' DependsOnTargets='{1}'>
                        <Message Text='Running FromExtn{0}'/>
                    </Target>
                    {2}
                </Project>
                ";

            var configFileContents = @"
                 <configuration>
                   <configSections>
                     <section name=""msbuildToolsets"" type=""Microsoft.Build.Evaluation.ToolsetConfigurationSection, Microsoft.Build"" />
                   </configSections>
                   <msbuildToolsets default=""14.1"">
                     <toolset toolsVersion=""14.1"">
                       <property name=""MSBuildToolsPath"" value="".""/>
                       <property name=""MSBuildBinPath"" value=""" + /*v4Folder*/"." + @"""/>
                       <projectImportSearchPaths>
                         <searchPaths os=""" + NativeMethodsShared.GetOSNameForExtensionsPath() + @""">
                           <property name=""MSBuildExtensionsPath"" value=""{0}"" />
                           <property name=""MSBuildExtensionsPath32"" value=""{1}"" />
                           <property name=""MSBuildExtensionsPath64"" value=""{2}"" />
                         </searchPaths>
                       </projectImportSearchPaths>
                      </toolset>
                   </msbuildToolsets>
                 </configuration>";

            string extnDir1 = null, extnDir2 = null, extnDir3 = null;
            string mainProjectPath = null;

            try {
                extnDir1 = GetNewExtensionsPathAndCreateFile("extensions1", Path.Combine("foo", "extn.proj"),
                                String.Format(extnTargetsFileContentTemplate, String.Empty, "FromExtn2", "<Import Project='$(MSBuildExtensionsPath32)\\bar\\extn2.proj' />"));
                extnDir2 = GetNewExtensionsPathAndCreateFile("extensions2", Path.Combine("bar", "extn2.proj"),
                                String.Format(extnTargetsFileContentTemplate, 2, "FromExtn3", "<Import Project='$(MSBuildExtensionsPath64)\\xyz\\extn3.proj' />"));
                extnDir3 = GetNewExtensionsPathAndCreateFile("extensions3", Path.Combine("xyz", "extn3.proj"),
                                String.Format(extnTargetsFileContentTemplate, 3, String.Empty, String.Empty));

                mainProjectPath = ObjectModelHelpers.CreateFileInTempProjectDirectory("main.proj", GetMainTargetFileContent());

                var configFilePath = ToolsetConfigurationReaderTestHelper.WriteConfigFile(String.Format(configFileContents, extnDir1, extnDir2, extnDir3));
                var reader = GetStandardConfigurationReader();

                var projColln = new ProjectCollection();
                projColln.ResetToolsetsForTests(reader);
                var logger = new MockLogger();
                projColln.RegisterLogger(logger);

                var project = projColln.LoadProject(mainProjectPath);
                Assert.True(project.Build("Main"));
                logger.AssertLogContains("Running FromExtn3");
                logger.AssertLogContains("Running FromExtn2");
                logger.AssertLogContains("Running FromExtn");
            } finally {
                if (mainProjectPath != null)
                {
                    FileUtilities.DeleteNoThrow(mainProjectPath);
                }
                if (extnDir1 != null)
                {
                    FileUtilities.DeleteDirectoryNoThrow(extnDir1, recursive: true);
                }
                if (extnDir2 != null)
                {
                    FileUtilities.DeleteDirectoryNoThrow(extnDir2, recursive: true);
                }
                if (extnDir3 != null)
                {
                    FileUtilities.DeleteDirectoryNoThrow(extnDir3, recursive: true);
                }
            }
        }
        public void ImportFromExtensionsPathSearchOrder2()
        {
            string extnTargetsFileContent1 = @"
                <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                    <PropertyGroup>
                        <PropertyFromExtn1>FromFirstFile</PropertyFromExtn1>
                    </PropertyGroup>

                    <Target Name='FromExtn'>
                        <Message Text='Running FromExtn'/>
                    </Target>
                </Project>
                ";

            string extnTargetsFileContent2 = @"
                <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                    <PropertyGroup>
                        <PropertyFromExtn1>FromSecondFile</PropertyFromExtn1>
                    </PropertyGroup>

                    <Target Name='FromExtn'>
                        <Message Text='Running FromExtn'/>
                    </Target>
                </Project>
                ";

            // File with the same name available in two different extension paths, but the one from the first
            // directory in MSBuildExtensionsPath environment variable should get loaded
            string extnDir1 = GetNewExtensionsPathAndCreateFile("extensions1", Path.Combine("foo", "extn.proj"), extnTargetsFileContent1);
            string extnDir2 = GetNewExtensionsPathAndCreateFile("extensions2", Path.Combine("foo", "extn.proj"), extnTargetsFileContent2);
            string mainProjectPath = ObjectModelHelpers.CreateFileInTempProjectDirectory("main.proj", GetMainTargetFileContent());

            // MSBuildExtensionsPath* property value has highest priority for the lookups
            try {
                var projColln = new ProjectCollection();
                projColln.ResetToolsetsForTests(WriteConfigFileAndGetReader("MSBuildExtensionsPath", Path.Combine("tmp", "non-existstant"), extnDir1));
                var logger = new MockLogger();
                projColln.RegisterLogger(logger);
                var project = projColln.LoadProject(mainProjectPath);

                project.SetProperty("MSBuildExtensionsPath", extnDir2);
                project.ReevaluateIfNecessary();
                Assert.True(project.Build());

                logger.AssertLogContains("Running FromExtn");
                logger.AssertLogContains("PropertyFromExtn1: FromSecondFile");
            } finally {
                if (mainProjectPath != null)
                {
                    FileUtilities.DeleteNoThrow(mainProjectPath);
                }
                if (extnDir1 != null)
                {
                    FileUtilities.DeleteDirectoryNoThrow(extnDir1, recursive: true);
                }
                if (extnDir2 != null)
                {
                    FileUtilities.DeleteDirectoryNoThrow(extnDir2, recursive: true);
                }
            }
        }