<|start_filename|>src/Tasks/FileIO/VerifyFileHash.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared.FileSystem;

namespace Microsoft.Build.Tasks
{
    /// <summary>
    /// Verifies that a file matches the expected file hash.
    /// </summary>
    public sealed class VerifyFileHash : TaskExtension
    {
        /// <summary>
        /// The file path.
        /// </summary>
        [Required]
        public string File { get; set; }

        /// <summary>
        /// The expected hash of the file.
        /// </summary>
        [Required]
        public string Hash { get; set; }

        /// <summary>
        /// The encoding format of <see cref="Hash"/>. Defaults to "hex".
        /// </summary>
        public string HashEncoding { get; set; } = GetFileHash._hashEncodingHex;

        /// <summary>
        /// The hashing algorithm to use. Allowed values: SHA256, SHA384, SHA512. Default = SHA256.
        /// </summary>
        public string Algorithm { get; set; } = GetFileHash._defaultFileHashAlgorithm;

        public override bool Execute()
        {
            if (!FileSystems.Default.FileExists(File))
            {
                Log.LogErrorWithCodeFromResources("FileHash.FileNotFound", File);
                return false;
            }

            if (!GetFileHash.SupportedAlgorithms.TryGetValue(Algorithm, out var algorithmFactory))
            {
                Log.LogErrorWithCodeFromResources("FileHash.UnrecognizedHashAlgorithm", Algorithm);
                return false;
            }

            if (!GetFileHash.TryParseHashEncoding(HashEncoding, out var encoding))
            {
                Log.LogErrorWithCodeFromResources("FileHash.UnrecognizedHashEncoding", HashEncoding);
                return false;
            }

            byte[] hash = GetFileHash.ComputeHash(algorithmFactory, File);
            string actualHash = GetFileHash.EncodeHash(encoding, hash);
            var comparison = encoding == Tasks.HashEncoding.Hex
                ? StringComparison.OrdinalIgnoreCase
                : StringComparison.Ordinal;
            if (!string.Equals(actualHash, Hash, comparison))
            {
                Log.LogErrorWithCodeFromResources("VerifyFileHash.HashMismatch", File, Algorithm, Hash, actualHash);
                return false;
            }

            return !Log.HasLoggedErrors;
        }
    }
}


<|start_filename|>src/Shared/Modifiers.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.IO;
using System.Diagnostics.CodeAnalysis;
using System.Collections.Generic;
using Microsoft.Build.Shared.FileSystem;

namespace Microsoft.Build.Shared
{
    /// <summary>
    /// This class contains utility methods for file IO.
    /// </summary>
    /// <comment>
    /// Partial class in order to reduce the amount of sharing into different assemblies
    /// </comment>
    static internal partial class FileUtilities
    {
        /// <summary>
        /// Encapsulates the definitions of the item-spec modifiers a.k.a. reserved item metadata.
        /// </summary>
        static internal class ItemSpecModifiers
        {
#if DEBUG
            /// <summary>
            /// Whether to dump when a modifier is in the "wrong" (slow) casing
            /// </summary>       
            private static readonly bool s_traceModifierCasing = (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("MSBUILDTRACEMODIFIERCASING")));
#endif

            // NOTE: If you add an item here that starts with a new letter, you need to update the case 
            // statements in IsItemSpecModifier and IsDerivableItemSpecModifier.
            internal const string FullPath = "FullPath";
            internal const string RootDir = "RootDir";
            internal const string Filename = "Filename";
            internal const string Extension = "Extension";
            internal const string RelativeDir = "RelativeDir";
            internal const string Directory = "Directory";
            internal const string RecursiveDir = "RecursiveDir";
            internal const string Identity = "Identity";
            internal const string ModifiedTime = "ModifiedTime";
            internal const string CreatedTime = "CreatedTime";
            internal const string AccessedTime = "AccessedTime";
            internal const string DefiningProjectFullPath = "DefiningProjectFullPath";
            internal const string DefiningProjectDirectory = "DefiningProjectDirectory";
            internal const string DefiningProjectName = "DefiningProjectName";
            internal const string DefiningProjectExtension = "DefiningProjectExtension";

            // These are all the well-known attributes.
            internal static readonly string[] All =
                {
                    FullPath,
                    RootDir,
                    Filename,
                    Extension,
                    RelativeDir,
                    Directory,
                    RecursiveDir,    // <-- Not derivable.
                    Identity,
                    ModifiedTime,
                    CreatedTime,
                    AccessedTime,
                    DefiningProjectFullPath,
                    DefiningProjectDirectory,
                    DefiningProjectName,
                    DefiningProjectExtension
                };

            private static HashSet<string> s_tableOfItemSpecModifiers = new HashSet<string>(All, StringComparer.OrdinalIgnoreCase);

            /// <summary>
            /// Indicates if the given name is reserved for an item-spec modifier.
            /// </summary>
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Performance")]
            internal static bool IsItemSpecModifier(string name)
            {
                if (name == null)
                {
                    return false;
                }


                /* 
                 * What follows requires some explanation.
                 * 
                 * This function is called many times and slowness here will be amplified 
                 * in critical performance scenarios.
                 * 
                 * The following switch statement attempts to identify item spec modifiers that
                 * have the exact case that our constants in ItemSpecModifiers have. This is the 
                 * 99% case.
                 * 
                 * Further, the switch statement can identify certain cases in which there is
                 * definitely no chance that 'name' is an item spec modifier. For example, a
                 * 7 letter 'name' that doesn't start with 'r' or 'R' can't be RootDir and
                 * therefore is not an item spec modifier.
                 * 
                 */
                switch (name.Length)
                {
                    case 7: // RootDir
                        switch (name[0])
                        {
                            default:
                                return false;
                            case 'R': // RootDir
                                if (name == FileUtilities.ItemSpecModifiers.RootDir)
                                {
                                    return true;
                                }
                                break;
                            case 'r':
                                break;
                        }
                        break;
                    case 8: // FullPath, Filename, Identity

                        switch (name[0])
                        {
                            default:
                                return false;
                            case 'F': // Filename, FullPath
                                if (name == FileUtilities.ItemSpecModifiers.FullPath)
                                {
                                    return true;
                                }
                                if (name == FileUtilities.ItemSpecModifiers.Filename)
                                {
                                    return true;
                                }
                                break;
                            case 'f':
                                break;
                            case 'I': // Identity
                                if (name == FileUtilities.ItemSpecModifiers.Identity)
                                {
                                    return true;
                                }
                                break;
                            case 'i':
                                break;
                        }
                        break;
                    case 9: // Extension, Directory
                        switch (name[0])
                        {
                            default:
                                return false;
                            case 'D': // Directory
                                if (name == FileUtilities.ItemSpecModifiers.Directory)
                                {
                                    return true;
                                }
                                break;
                            case 'd':
                                break;
                            case 'E': // Extension
                                if (name == FileUtilities.ItemSpecModifiers.Extension)
                                {
                                    return true;
                                }
                                break;
                            case 'e':
                                break;
                        }
                        break;
                    case 11: // RelativeDir, CreatedTime
                        switch (name[0])
                        {
                            default:
                                return false;
                            case 'C': // CreatedTime
                                if (name == FileUtilities.ItemSpecModifiers.CreatedTime)
                                {
                                    return true;
                                }
                                break;
                            case 'c':
                                break;
                            case 'R': // RelativeDir
                                if (name == FileUtilities.ItemSpecModifiers.RelativeDir)
                                {
                                    return true;
                                }
                                break;
                            case 'r':
                                break;
                        }
                        break;
                    case 12: // RecursiveDir, ModifiedTime, AccessedTime

                        switch (name[0])
                        {
                            default:
                                return false;
                            case 'A': // AccessedTime
                                if (name == FileUtilities.ItemSpecModifiers.AccessedTime)
                                {
                                    return true;
                                }
                                break;
                            case 'a':
                                break;
                            case 'M': // ModifiedTime
                                if (name == FileUtilities.ItemSpecModifiers.ModifiedTime)
                                {
                                    return true;
                                }
                                break;
                            case 'm':
                                break;
                            case 'R': // RecursiveDir
                                if (name == FileUtilities.ItemSpecModifiers.RecursiveDir)
                                {
                                    return true;
                                }
                                break;
                            case 'r':
                                break;
                        }
                        break;
                    case 19:
                    case 23:
                    case 24:
                        return IsDefiningProjectModifier(name);
                    default:
                        // Not the right length for a match.
                        return false;
                }

                // Could still be a case-insensitive match.
                bool result = s_tableOfItemSpecModifiers.Contains(name);

#if DEBUG
                if (result && s_traceModifierCasing)
                {
                    Console.WriteLine("'{0}' is a non-standard casing. Replace the use with the standard casing like 'RecursiveDir' or 'FullPath' for a small performance improvement.", name);
                }
#endif

                return result;
            }

            /// <summary>
            /// Indicates if the given name is reserved for one of the specific subset of itemspec 
            /// modifiers to do with the defining project of the item. 
            /// </summary>
            internal static bool IsDefiningProjectModifier(string name)
            {
                switch (name.Length)
                {
                    case 19: // DefiningProjectName
                        if (name == FileUtilities.ItemSpecModifiers.DefiningProjectName)
                        {
                            return true;
                        }
                        break;
                    case 23: // DefiningProjectFullPath
                        if (name == FileUtilities.ItemSpecModifiers.DefiningProjectFullPath)
                        {
                            return true;
                        }
                        break;
                    case 24: // DefiningProjectDirectory, DefiningProjectExtension

                        switch (name[15])
                        {
                            default:
                                return false;
                            case 'D': // DefiningProjectDirectory
                                if (name == FileUtilities.ItemSpecModifiers.DefiningProjectDirectory)
                                {
                                    return true;
                                }
                                break;
                            case 'd':
                                break;
                            case 'E': // DefiningProjectExtension
                                if (name == FileUtilities.ItemSpecModifiers.DefiningProjectExtension)
                                {
                                    return true;
                                }
                                break;
                            case 'e':
                                break;
                        }
                        break;
                    default:
                        return false;
                }

                // Could still be a case-insensitive match.
                bool result = s_tableOfItemSpecModifiers.Contains(name);

#if DEBUG
                if (result && s_traceModifierCasing)
                {
                    Console.WriteLine("'{0}' is a non-standard casing. Replace the use with the standard casing like 'RecursiveDir' or 'FullPath' for a small performance improvement.", name);
                }
#endif

                return result;
            }

            /// <summary>
            /// Indicates if the given name is reserved for a derivable item-spec modifier.
            /// Derivable means it can be computed given a file name.
            /// </summary>
            /// <param name="name">Name to check.</param>
            /// <returns>true, if name of a derivable modifier</returns>
            internal static bool IsDerivableItemSpecModifier(string name)
            {
                bool isItemSpecModifier = IsItemSpecModifier(name);

                if (isItemSpecModifier)
                {
                    if (name.Length == 12)
                    {
                        if (name[0] == 'R' || name[0] == 'r')
                        {
                            // The only 12 letter ItemSpecModifier that starts with 'R' is 'RecursiveDir' 
                            return false;
                        }
                    }
                }

                return isItemSpecModifier;
            }

            /// <summary>
            /// Performs path manipulations on the given item-spec as directed.
            /// Does not cache the result.
            /// </summary>
            internal static string GetItemSpecModifier(string currentDirectory, string itemSpec, string definingProjectEscaped, string modifier)
            {
                string dummy = null;
                return GetItemSpecModifier(currentDirectory, itemSpec, definingProjectEscaped, modifier, ref dummy);
            }

            /// <summary>
            /// Performs path manipulations on the given item-spec as directed.
            /// 
            /// Supported modifiers:
            ///     %(FullPath)         = full path of item
            ///     %(RootDir)          = root directory of item
            ///     %(Filename)         = item filename without extension
            ///     %(Extension)        = item filename extension
            ///     %(RelativeDir)      = item directory as given in item-spec
            ///     %(Directory)        = full path of item directory relative to root
            ///     %(RecursiveDir)     = portion of item path that matched a recursive wildcard
            ///     %(Identity)         = item-spec as given
            ///     %(ModifiedTime)     = last write time of item
            ///     %(CreatedTime)      = creation time of item
            ///     %(AccessedTime)     = last access time of item
            /// 
            /// NOTES:
            /// 1) This method always returns an empty string for the %(RecursiveDir) modifier because it does not have enough
            ///    information to compute it -- only the BuildItem class can compute this modifier.
            /// 2) All but the file time modifiers could be cached, but it's not worth the space. Only full path is cached, as the others are just string manipulations.
            /// </summary>
            /// <remarks>
            /// Methods of the Path class "normalize" slashes and periods. For example:
            /// 1) successive slashes are combined into 1 slash
            /// 2) trailing periods are discarded
            /// 3) forward slashes are changed to back-slashes
            /// 
            /// As a result, we cannot rely on any file-spec that has passed through a Path method to remain the same. We will
            /// therefore not bother preserving slashes and periods when file-specs are transformed.
            /// 
            /// Never returns null.
            /// </remarks>
            /// <param name="currentDirectory">The root directory for relative item-specs. When called on the Engine thread, this is the project directory. When called as part of building a task, it is null, indicating that the current directory should be used.</param>
            /// <param name="itemSpec">The item-spec to modify.</param>
            /// <param name="definingProjectEscaped">The path to the project that defined this item (may be null).</param>
            /// <param name="modifier">The modifier to apply to the item-spec.</param>
            /// <param name="fullPath">Full path if any was previously computed, to cache.</param>
            /// <returns>The modified item-spec (can be empty string, but will never be null).</returns>
            /// <exception cref="InvalidOperationException">Thrown when the item-spec is not a path.</exception>
            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Pre-existing")]
            internal static string GetItemSpecModifier(string currentDirectory, string itemSpec, string definingProjectEscaped, string modifier, ref string fullPath)
            {
                ErrorUtilities.VerifyThrow(itemSpec != null, "Need item-spec to modify.");
                ErrorUtilities.VerifyThrow(modifier != null, "Need modifier to apply to item-spec.");

                string modifiedItemSpec = null;

                try
                {
                    if (string.Equals(modifier, FileUtilities.ItemSpecModifiers.FullPath, StringComparison.OrdinalIgnoreCase))
                    {
                        if (fullPath != null)
                        {
                            return fullPath;
                        }

                        if (currentDirectory == null)
                        {
                            currentDirectory = String.Empty;
                        }

                        modifiedItemSpec = GetFullPath(itemSpec, currentDirectory);
                        fullPath = modifiedItemSpec;

                        ThrowForUrl(modifiedItemSpec, itemSpec, currentDirectory);
                    }
                    else if (string.Equals(modifier, FileUtilities.ItemSpecModifiers.RootDir, StringComparison.OrdinalIgnoreCase))
                    {
                        GetItemSpecModifier(currentDirectory, itemSpec, definingProjectEscaped, ItemSpecModifiers.FullPath, ref fullPath);

                        modifiedItemSpec = Path.GetPathRoot(fullPath);

                        if (!EndsWithSlash(modifiedItemSpec))
                        {
                            ErrorUtilities.VerifyThrow(FileUtilitiesRegex.StartsWithUncPattern(modifiedItemSpec),
                                "Only UNC shares should be missing trailing slashes.");

                            // restore/append trailing slash if Path.GetPathRoot() has either removed it, or failed to add it
                            // (this happens with UNC shares)
                            modifiedItemSpec += Path.DirectorySeparatorChar;
                        }
                    }
                    else if (string.Equals(modifier, FileUtilities.ItemSpecModifiers.Filename, StringComparison.OrdinalIgnoreCase))
                    {
                        // if the item-spec is a root directory, it can have no filename
                        if (IsRootDirectory(itemSpec))
                        {
                            // NOTE: this is to prevent Path.GetFileNameWithoutExtension() from treating server and share elements
                            // in a UNC file-spec as filenames e.g. \\server, \\server\share
                            modifiedItemSpec = String.Empty;
                        }
                        else
                        {
                            // Fix path to avoid problem with Path.GetFileNameWithoutExtension when backslashes in itemSpec on Unix
                            modifiedItemSpec = Path.GetFileNameWithoutExtension(FixFilePath(itemSpec));
                        }
                    }
                    else if (string.Equals(modifier, FileUtilities.ItemSpecModifiers.Extension, StringComparison.OrdinalIgnoreCase))
                    {
                        // if the item-spec is a root directory, it can have no extension
                        if (IsRootDirectory(itemSpec))
                        {
                            // NOTE: this is to prevent Path.GetExtension() from treating server and share elements in a UNC
                            // file-spec as filenames e.g. \\server.ext, \\server\share.ext
                            modifiedItemSpec = String.Empty;
                        }
                        else
                        {
                            modifiedItemSpec = Path.GetExtension(itemSpec);
                        }
                    }
                    else if (string.Equals(modifier, FileUtilities.ItemSpecModifiers.RelativeDir, StringComparison.OrdinalIgnoreCase))
                    {
                        modifiedItemSpec = GetDirectory(itemSpec);
                    }
                    else if (string.Equals(modifier, FileUtilities.ItemSpecModifiers.Directory, StringComparison.OrdinalIgnoreCase))
                    {
                        GetItemSpecModifier(currentDirectory, itemSpec, definingProjectEscaped, ItemSpecModifiers.FullPath, ref fullPath);

                        modifiedItemSpec = GetDirectory(fullPath);

                        if (NativeMethodsShared.IsWindows)
                        {
                            int length = -1;
                            if (FileUtilitiesRegex.StartsWithDrivePattern(modifiedItemSpec))
                            {
                                length = 2;
                            }
                            else
                            {
                                length = FileUtilitiesRegex.StartsWithUncPatternMatchLength(modifiedItemSpec);
                            }

                            if (length != -1)
                            {
                                ErrorUtilities.VerifyThrow((modifiedItemSpec.Length > length) && IsSlash(modifiedItemSpec[length]),
                                                           "Root directory must have a trailing slash.");

                                modifiedItemSpec = modifiedItemSpec.Substring(length + 1);
                            }
                        }
                        else
                        {
                            ErrorUtilities.VerifyThrow(!string.IsNullOrEmpty(modifiedItemSpec) && IsSlash(modifiedItemSpec[0]),
                                                       "Expected a full non-windows path rooted at '/'.");

                            // A full unix path is always rooted at
                            // `/`, and a root-relative path is the
                            // rest of the string.
                            modifiedItemSpec = modifiedItemSpec.Substring(1);
                        }
                    }
                    else if (string.Equals(modifier, FileUtilities.ItemSpecModifiers.RecursiveDir, StringComparison.OrdinalIgnoreCase))
                    {
                        // only the BuildItem class can compute this modifier -- so leave empty
                        modifiedItemSpec = String.Empty;
                    }
                    else if (string.Equals(modifier, FileUtilities.ItemSpecModifiers.Identity, StringComparison.OrdinalIgnoreCase))
                    {
                        modifiedItemSpec = itemSpec;
                    }
                    else if (string.Equals(modifier, FileUtilities.ItemSpecModifiers.ModifiedTime, StringComparison.OrdinalIgnoreCase))
                    {
                        // About to go out to the filesystem.  This means data is leaving the engine, so need
                        // to unescape first.
                        string unescapedItemSpec = EscapingUtilities.UnescapeAll(itemSpec);

                        FileInfo info = FileUtilities.GetFileInfoNoThrow(unescapedItemSpec);

                        if (info != null)
                        {
                            modifiedItemSpec = info.LastWriteTime.ToString(FileTimeFormat, null);
                        }
                        else
                        {
                            // File does not exist, or path is a directory
                            modifiedItemSpec = String.Empty;
                        }
                    }
                    else if (string.Equals(modifier, FileUtilities.ItemSpecModifiers.CreatedTime, StringComparison.OrdinalIgnoreCase))
                    {
                        // About to go out to the filesystem.  This means data is leaving the engine, so need
                        // to unescape first.
                        string unescapedItemSpec = EscapingUtilities.UnescapeAll(itemSpec);

                        if (FileSystems.Default.FileExists(unescapedItemSpec))
                        {
                            modifiedItemSpec = File.GetCreationTime(unescapedItemSpec).ToString(FileTimeFormat, null);
                        }
                        else
                        {
                            // File does not exist, or path is a directory                        
                            modifiedItemSpec = String.Empty;
                        }
                    }
                    else if (string.Equals(modifier, FileUtilities.ItemSpecModifiers.AccessedTime, StringComparison.OrdinalIgnoreCase))
                    {
                        // About to go out to the filesystem.  This means data is leaving the engine, so need
                        // to unescape first.
                        string unescapedItemSpec = EscapingUtilities.UnescapeAll(itemSpec);

                        if (FileSystems.Default.FileExists(unescapedItemSpec))
                        {
                            modifiedItemSpec = File.GetLastAccessTime(unescapedItemSpec).ToString(FileTimeFormat, null);
                        }
                        else
                        {
                            // File does not exist, or path is a directory                        
                            modifiedItemSpec = String.Empty;
                        }
                    }
                    else if (IsDefiningProjectModifier(modifier))
                    {
                        if (String.IsNullOrEmpty(definingProjectEscaped))
                        {
                            // We have nothing to work with, but that's sometimes OK -- so just return String.Empty
                            modifiedItemSpec = String.Empty;
                        }
                        else
                        {
                            if (string.Equals(modifier, FileUtilities.ItemSpecModifiers.DefiningProjectDirectory, StringComparison.OrdinalIgnoreCase))
                            {
                                // ItemSpecModifiers.Directory does not contain the root directory
                                modifiedItemSpec = Path.Combine
                                    (
                                        GetItemSpecModifier(currentDirectory, definingProjectEscaped, null, ItemSpecModifiers.RootDir),
                                        GetItemSpecModifier(currentDirectory, definingProjectEscaped, null, ItemSpecModifiers.Directory)
                                    );
                            }
                            else
                            {
                                string additionalModifier = null;

                                if (string.Equals(modifier, FileUtilities.ItemSpecModifiers.DefiningProjectFullPath, StringComparison.OrdinalIgnoreCase))
                                {
                                    additionalModifier = ItemSpecModifiers.FullPath;
                                }
                                else if (string.Equals(modifier, FileUtilities.ItemSpecModifiers.DefiningProjectName, StringComparison.OrdinalIgnoreCase))
                                {
                                    additionalModifier = ItemSpecModifiers.Filename;
                                }
                                else if (string.Equals(modifier, FileUtilities.ItemSpecModifiers.DefiningProjectExtension, StringComparison.OrdinalIgnoreCase))
                                {
                                    additionalModifier = ItemSpecModifiers.Extension;
                                }
                                else
                                {
                                    ErrorUtilities.ThrowInternalError("\"{0}\" is not a valid item-spec modifier.", modifier);
                                }

                                modifiedItemSpec = GetItemSpecModifier(currentDirectory, definingProjectEscaped, null, additionalModifier);
                            }
                        }
                    }
                    else
                    {
                        ErrorUtilities.ThrowInternalError("\"{0}\" is not a valid item-spec modifier.", modifier);
                    }
                }
                catch (Exception e) when (ExceptionHandling.IsIoRelatedException(e))
                {
                    ErrorUtilities.VerifyThrowInvalidOperation(false, "Shared.InvalidFilespecForTransform", modifier, itemSpec, e.Message);
                }

                return modifiedItemSpec;
            }

            /// <summary>
            /// Indicates whether the given path is a UNC or drive pattern root directory.
            /// <para>Note: This function mimics the behavior of checking if Path.GetDirectoryName(path) == null.</para>
            /// </summary>
            /// <param name="path"></param>
            /// <returns></returns>
            private static bool IsRootDirectory(string path)
            {
                // Eliminate all non-rooted paths
                if (!Path.IsPathRooted(path))
                {
                    return false;
                }

                int uncMatchLength = FileUtilitiesRegex.StartsWithUncPatternMatchLength(path);

                // Determine if the given path is a standard drive/unc pattern root
                if (FileUtilitiesRegex.IsDrivePattern(path) ||
                    FileUtilitiesRegex.IsDrivePatternWithSlash(path) ||
                    uncMatchLength == path.Length)
                {
                    return true;
                }

                // Eliminate all non-root unc paths.
                if (uncMatchLength != -1)
                {
                    return false;
                }

                // Eliminate any drive patterns that don't have a slash after the colon or where the 4th character is a non-slash
                // A non-slash at [3] is specifically checked here because Path.GetDirectoryName
                // considers "C:///" a valid root.
                if (FileUtilitiesRegex.StartsWithDrivePattern(path) &&
                    ((path.Length >= 3 && path[2] != '\\' && path[2] != '/') ||
                    (path.Length >= 4 && path[3] != '\\' && path[3] != '/')))
                {
                    return false;
                }

                // There are some edge cases that can get to this point.
                // After eliminating valid / invalid roots, fall back on original behavior.
                return Path.GetDirectoryName(path) == null;
            }

            /// <summary>
            /// Temporary check for something like http://foo which will end up like c:\foo\bar\http://foo
            /// We should either have no colon, or exactly one colon.
            /// UNDONE: This is a minimal safe change for Dev10. The correct fix should be to make GetFullPath/NormalizePath throw for this.
            /// </summary>
            private static void ThrowForUrl(string fullPath, string itemSpec, string currentDirectory)
            {
                if (fullPath.IndexOf(':') != fullPath.LastIndexOf(':'))
                {
                    // Cause a better error to appear
                    fullPath = Path.GetFullPath(Path.Combine(currentDirectory, itemSpec));
                }
            }
        }
    }
}


<|start_filename|>src/Tasks/ManifestUtil/DeployManifest.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Globalization;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using Microsoft.Build.Utilities;
using FrameworkNameVersioning = System.Runtime.Versioning.FrameworkName;
using System.Collections.Generic;
using Microsoft.Build.Shared.FileSystem;

namespace Microsoft.Build.Tasks.Deployment.ManifestUtilities
{
    /// <summary>
    /// Specifies how the application checks for updates.
    /// </summary>
    [ComVisible(false)]
    public enum UpdateMode
    {
        /// <summary>
        /// Check for updates in the background, after the application starts.
        /// </summary>
        Background,
        /// <summary>
        /// Check for updates in the foreground, before the application starts.
        /// </summary>
        Foreground
    }

    /// <summary>
    /// Specifies the units for the update interval.
    /// </summary>
    [ComVisible(false)]
    public enum UpdateUnit
    {
        /// <summary>
        /// Update interval is in hours.
        /// </summary>
        Hours,
        /// <summary>
        /// Update interval is in days.
        /// </summary>
        Days,
        /// <summary>
        /// Update interval is in weeks.
        /// </summary>
        Weeks
    }

    /// <summary>
    /// Describes a ClickOnce deployment manifest.
    /// </summary>
    [ComVisible(false)]
    [XmlRoot("DeployManifest")]
    public sealed class DeployManifest : Manifest
    {
        private string _createDesktopShortcut;
        private string _deploymentUrl;
        private string _disallowUrlActivation;
        private AssemblyReference _entryPoint;
        private string _errorReportUrl;
        private string _install = "true";
        private string _mapFileExtensions;
        private string _minimumRequiredVersion;
        private string _product;
        private string _publisher;
        private string _suiteName;
        private string _supportUrl;
        private string _trustUrlParameters;
        private string _updateEnabled;
        private string _updateInterval = "0";
        private string _updateMode;
        private string _updateUnit = "days";
        private CompatibleFrameworkCollection _compatibleFrameworkList;
        private List<CompatibleFramework> _compatibleFrameworks = new List<CompatibleFramework>();
        private string _targetFrameworkMoniker;

        private const string _redistListFolder = "RedistList";
        private const string _redistListFile = "FrameworkList.xml";

        /// <summary>
        /// Initializes a new instance of the DeployManifest class.
        /// </summary>
        public DeployManifest()
        {
        }

        /// <summary>
        /// Initializes a new instance of the DeployManifest class.
        /// </summary>
        public DeployManifest(string targetFrameworkMoniker)
        {
            DiscoverCompatFrameworks(targetFrameworkMoniker);
        }

        private void DiscoverCompatFrameworks(string moniker)
        {
            if (!string.IsNullOrEmpty(moniker))
            {
                var frameworkName = new FrameworkNameVersioning(moniker);
                if (frameworkName.Version.Major >= 4)
                {
                    _compatibleFrameworks.Clear();
                    DiscoverCompatibleFrameworks(frameworkName);
                }
            }
        }

        private void DiscoverCompatibleFrameworks(FrameworkNameVersioning frameworkName)
        {
            FrameworkNameVersioning installableFrameworkName = GetInstallableFrameworkName(frameworkName);

            // if profile is null or empty.
            if (string.IsNullOrEmpty(installableFrameworkName.Profile))
            {
                _compatibleFrameworks.Add(GetFullCompatFramework(installableFrameworkName));
            }
            else
            {
                _compatibleFrameworks.Add(GetSubsetCompatFramework(installableFrameworkName));
                _compatibleFrameworks.Add(GetFullCompatFramework(installableFrameworkName));
            }
        }

        /// <summary>
        /// codes from GetInstallableFrameworkForTargetFxInternal in 
        /// env/vscore/package/FxMultiTargeting/FrameworkMultiTargetingInternal.cs
        /// </summary>
        private static FrameworkNameVersioning GetInstallableFrameworkName(FrameworkNameVersioning frameworkName)
        {
            string installableFramework = null;
            FrameworkNameVersioning installableFrameworkObj;

            IList<string> referenceAssemblyPaths = GetPathToReferenceAssemblies(frameworkName);

            if (referenceAssemblyPaths?.Count > 0)
            {
                // the first one in the list is the reference assembly path for the requested TFM
                string referenceAssemblyPath = referenceAssemblyPaths[0];

                // Get the redistlist file path
                string redistListFilePath = GetRedistListFilePath(referenceAssemblyPath);

                if (FileSystems.Default.FileExists(redistListFilePath))
                {
                    installableFramework = GetInstallableFramework(redistListFilePath);
                }
            }

            // If the installable framework value is not in the redist, there was no redist, or no matching FX we return the sent TFM,  
            // this means frameworks that are installable themselves don't need to specify this property
            // and that all unknown frameworks are assumed to be installable.
            if (installableFramework == null)
            {
                installableFrameworkObj = frameworkName;
            }
            else
            {
                try
                {
                    installableFrameworkObj = new FrameworkNameVersioning(installableFramework);
                }
                catch (ArgumentException)
                {
                    // Redist list data was invalid, behave as if it was not defined.
                    installableFrameworkObj = frameworkName;
                }
            }

            return installableFrameworkObj;
        }

        private static string GetRedistListFilePath(string referenceAssemblyPath)
        {
            string redistListPath = Path.Combine(referenceAssemblyPath, _redistListFolder);
            return Path.Combine(redistListPath, _redistListFile);
        }

        private static IList<string> GetPathToReferenceAssemblies(FrameworkNameVersioning targetFrameworkMoniker)
        {
            IList<string> targetFrameworkPaths = null;
            try
            {
                targetFrameworkPaths = ToolLocationHelper.GetPathToReferenceAssemblies(targetFrameworkMoniker);

                // this returns the chained reference assemblies folders of the framework
                // ordered from highest to lowest version
            }
            catch (InvalidOperationException)
            {
                // The chained dirs does not exist
                // or could not read redistlist for chain
            }

            return targetFrameworkPaths;
        }

        /// <summary>
        /// Gets the InstallableFramework by reading the 'InstallableFramework' attribute in the redist file of the target framework
        /// </summary>
        /// <param name="redistListFilePath">the path to the redistlist file</param>
        /// <returns>InstallableFramework</returns>
        private static string GetInstallableFramework(string redistListFilePath)
        {
            string installableFramework = null;

            try
            {
                var doc = new XmlDocument();
                var xrSettings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore };
                using (XmlReader xr = XmlReader.Create(redistListFilePath, xrSettings))
                {
                    doc.Load(xr);
                    XmlNode fileListNode = doc.DocumentElement;
                    XmlAttribute nameattr = fileListNode?.Attributes["InstallableFramework"];
                    if (!String.IsNullOrEmpty(nameattr?.Value))
                    {
                        installableFramework = nameattr.Value;
                    }
                }
            }
            catch (Exception)
            {
            }

            return installableFramework;
        }

        private static CompatibleFramework GetSubsetCompatFramework(FrameworkNameVersioning frameworkName)
        {
            CompatibleFramework compat = GetFullCompatFramework(frameworkName);
            compat.Profile = frameworkName.Profile;

            return compat;
        }

        private static CompatibleFramework GetFullCompatFramework(FrameworkNameVersioning frameworkName)
        {
            var compat = new CompatibleFramework
            {
                Version = frameworkName.Version.ToString(),
                SupportedRuntime = PatchCLRVersion(Util.GetClrVersion(frameworkName.Version.ToString())),
                Profile = "Full"
            };

            return compat;
        }

        /// <summary>
        /// conver (MajorVersion).(MinorVersion).(Build).(Revision) to (MajorVersion).(MinorVersion).(Build)
        /// </summary>
        /// <param name="version"></param>
        /// <returns></returns>
        private static string PatchCLRVersion(string version)
        {
            try
            {
                var ver = new Version(version);
                var result = new Version(ver.Major, ver.Minor, ver.Build);
                return result.ToString();
            }
            catch (ArgumentException)
            {
                //continue
            }
            catch (FormatException)
            {
                //continue
            }
            catch (OverflowException)
            {
                //continue 
            }

            return version;
        }

        /// <summary>
        /// Specifies whether the application install will create a shortcut on the desktop
        /// If True, the installation will create a shortcut to the application on the desktop.
        /// The default is False
        /// If Install is False, this value will be ignored
        /// </summary>
        [XmlIgnore]
        public bool CreateDesktopShortcut
        {
            get => ConvertUtil.ToBoolean(_createDesktopShortcut);
            set => _createDesktopShortcut = (value ? "true" : null);
        }

        /// <summary>
        /// Specifies the target framework moniker of this project.
        /// </summary>
        [XmlIgnore]
        public string TargetFrameworkMoniker
        {
            get => _targetFrameworkMoniker;
            set
            {
                _targetFrameworkMoniker = value;
                DiscoverCompatFrameworks(_targetFrameworkMoniker);
            }
        }

        /// <summary>
        /// A collection of CompatibleFrameworks
        /// </summary>
        [XmlIgnore]
        public CompatibleFrameworkCollection CompatibleFrameworks
        {
            get
            {
                if (_compatibleFrameworkList == null && _compatibleFrameworks != null)
                {
                    _compatibleFrameworkList = new CompatibleFrameworkCollection(_compatibleFrameworks);
                }
                return _compatibleFrameworkList;
            }
        }

        /// <summary>
        /// Specifies the update location for the application.
        /// If this input is not specified then no update location will be defined for the application.
        /// However, if application updates are specified then the update location must be specified.
        /// The specified value should be a fully qualified URL or UNC path.
        /// </summary>
        [XmlIgnore]
        public string DeploymentUrl
        {
            get => _deploymentUrl;
            set => _deploymentUrl = value;
        }

        /// <summary>
        /// Specifies whether the application should be blocked from being activated via a URL.
        /// If this option is True then application can only be activated from the user's Start menu.
        /// The default is False.
        /// This option is ignored if the Install property is False.
        /// </summary>
        [XmlIgnore]
        public bool DisallowUrlActivation
        {
            get => ConvertUtil.ToBoolean(_disallowUrlActivation);
            set => _disallowUrlActivation = value ? "true" : null; // NOTE: disallowUrlActivation=false is implied, and Fusion prefers the false case to be unspecified
        }

        [XmlIgnore]
        public override AssemblyReference EntryPoint
        {
            get => _entryPoint;
            set => _entryPoint = value;
        }

        /// <summary>
        /// Specifies the link to use if there is a failure launching the application.
        /// The specified value should be a fully qualified URL or UNC path.
        /// </summary>
        [XmlIgnore]
        public string ErrorReportUrl
        {
            get => _errorReportUrl;
            set => _errorReportUrl = value;
        }

        /// <summary>
        /// Specifies whether the application is an installed application or an online only application.
        /// If this flag is True the application will be installed on the user's Start menu, and can be removed from the Add/Remove Programs dialog.
        /// If this flag is False then the application is intended for online use from a web page.
        /// The default is True.
        /// </summary>
        [XmlIgnore]
        public bool Install
        {
            get => ConvertUtil.ToBoolean(_install);
            set => _install = Convert.ToString(value, CultureInfo.InvariantCulture);
        }

        /// <summary>
        /// Specifies whether or not the ".deploy" file extension mapping is used.
        /// If this flag is true then every application file is published with a ".deploy" file extension.
        /// This option is useful for web server security to limit the number of file extensions that need to be unblocked to enable ClickOnce application deployment.
        /// The default is false.
        /// </summary>
        [XmlIgnore]
        public bool MapFileExtensions
        {
            get => ConvertUtil.ToBoolean(_mapFileExtensions);
            set => _mapFileExtensions = value ? "true" : null; // NOTE: mapFileExtensions=false is implied, and Fusion prefers the false case to be unspecified
        }

        /// <summary>
        /// Specifies whether or not the user can skip the update.
        /// If the user has a version less than the minimum required, he or she will not have the option to skip the update.
        /// The default is to have no minimum required version.
        /// This input only applies when Install is True.
        /// </summary>
        [XmlIgnore]
        public string MinimumRequiredVersion
        {
            get => _minimumRequiredVersion;
            set => _minimumRequiredVersion = value;
        }

        internal override void OnAfterLoad()
        {
            base.OnAfterLoad();
            if (_entryPoint == null && AssemblyReferences?.Count > 0)
            {
                _entryPoint = AssemblyReferences[0];
                _entryPoint.ReferenceType = AssemblyReferenceType.ClickOnceManifest;
            }
        }

        internal override void OnBeforeSave()
        {
            base.OnBeforeSave();
            if (AssemblyIdentity != null && String.IsNullOrEmpty(AssemblyIdentity.PublicKeyToken))
            {
                AssemblyIdentity.PublicKeyToken = "0000000000000000";
            }
        }

        /// <summary>
        /// Specifies the name of the application.
        /// If this input is not specified then the name is inferred from the identity of the generated manifest.
        /// This name is used for the shortcut name on the Start menu and is part of the name that appears in the Add/Remove Programs dialog.
        /// </summary>
        [XmlIgnore]
        public string Product
        {
            get => _product;
            set => _product = value;
        }

        /// <summary>
        /// Specifies the publisher of the application.
        /// If this input is not specified then the name is inferred from the registered user, or the identity of the generated manifest.
        /// This name is used for the folder name on the Start menu and is part of the name that appears in the Add/Remove Programs dialog.
        /// </summary>
        [XmlIgnore]
        public string Publisher
        {
            get => _publisher;
            set => _publisher = value;
        }

        /// <summary>
        /// Specifies the suite name of the application.
        /// This name is used for the sub-folder name on the Start menu (as a child of the publisher)
        /// </summary>
        [XmlIgnore]
        public string SuiteName
        {
            get => _suiteName;
            set => _suiteName = value;
        }

        /// <summary>
        /// Specifies the link that appears in the Add/Remove Programs dialog for the application.
        /// The specified value should be a fully qualified URL or UNC path.
        /// </summary>
        [XmlIgnore]
        public string SupportUrl
        {
            get => _supportUrl;
            set => _supportUrl = value;
        }

        /// <summary>
        /// Specifies whether or not URL query-string parameters should be made available to the application.
        /// The default is False indicating that parameters will not be available to the application.
        /// </summary>
        [XmlIgnore]
        public bool TrustUrlParameters
        {
            get => ConvertUtil.ToBoolean(_trustUrlParameters);
            set => _trustUrlParameters = value ? "true" : null;
            // NOTE: trustUrlParameters=false is implied, and Fusion prefers the false case to be unspecified
        }

        /// <summary>
        /// Indicates whether or not the application is updatable.
        /// The default is False.
        /// This input only applies when Install is True.
        /// </summary>
        [XmlIgnore]
        public bool UpdateEnabled
        {
            get => ConvertUtil.ToBoolean(_updateEnabled);
            set => _updateEnabled = Convert.ToString(value, CultureInfo.InvariantCulture);
        }

        /// <summary>
        /// Specifies the update interval for the application.
        /// The default is zero.
        /// This input only applies when Install and UpdateEnabled are both True.
        /// </summary>
        [XmlIgnore]
        public int UpdateInterval
        {
            get
            {
                try { return Convert.ToInt32(_updateInterval, CultureInfo.InvariantCulture); }
                catch (ArgumentException) { return 1; }
                catch (FormatException) { return 1; }
            }
            set => _updateInterval = Convert.ToString(value, CultureInfo.InvariantCulture);
        }

        /// <summary>
        /// Specifies whether updates should be checked in the foreground before starting the application, or in the background as the application is running.
        /// The default is "Background".
        /// This input only applies when Install and UpdateEnabled are both True.
        /// </summary>
        [XmlIgnore]
        public UpdateMode UpdateMode
        {
            get
            {
                try { return (UpdateMode)Enum.Parse(typeof(UpdateMode), _updateMode, true); }
                catch (FormatException) { return UpdateMode.Foreground; }
                catch (ArgumentException) { return UpdateMode.Foreground; }
            }
            set => _updateMode = value.ToString();
        }

        /// <summary>
        /// Specifies the units for UpdateInterval input.
        /// This input only applies when Install and UpdateEnabled are both True.
        /// </summary>
        [XmlIgnore]
        public UpdateUnit UpdateUnit
        {
            get
            {
                try { return (UpdateUnit)Enum.Parse(typeof(UpdateUnit), _updateUnit, true); }
                catch (FormatException) { return UpdateUnit.Days; }
                catch (ArgumentException) { return UpdateUnit.Days; }
            }
            set => _updateUnit = value.ToString();
        }

        public override void Validate()
        {
            base.Validate();
            ValidateDeploymentProvider();
            ValidateMinimumRequiredVersion();
            ValidatePlatform();
            ValidateEntryPoint();
        }

        private void ValidateDeploymentProvider()
        {
            if (!String.IsNullOrEmpty(_deploymentUrl) && PathUtil.IsLocalPath(_deploymentUrl))
            {
                OutputMessages.AddWarningMessage("GenerateManifest.InvalidDeploymentProvider");
            }
        }

        private void ValidateEntryPoint()
        {
            if (_entryPoint != null)
            {
                if (!String.IsNullOrEmpty(_entryPoint.TargetPath) && !_entryPoint.TargetPath.EndsWith(
                        ".manifest",
                        StringComparison.OrdinalIgnoreCase))
                {
                    OutputMessages.AddErrorMessage("GenerateManifest.InvalidEntryPoint", _entryPoint.ToString());
                }

                string manifestPath = _entryPoint.ResolvedPath;
                if (manifestPath == null)
                {
                    manifestPath = Path.Combine(Path.GetDirectoryName(SourcePath), _entryPoint.TargetPath);
                }
                if (FileSystems.Default.FileExists(manifestPath))
                {
                    ApplicationManifest entryPointManifest = ManifestReader.ReadManifest(manifestPath, false) as ApplicationManifest;
                    if (entryPointManifest != null)
                    {
                        if (Install)
                        {
                            if (entryPointManifest.HostInBrowser)
                            {
                                OutputMessages.AddErrorMessage("GenerateManifest.HostInBrowserNotOnlineOnly");
                            }
                        }
                        else
                        {
                            if (entryPointManifest.FileAssociations?.Count > 0)
                            {
                                OutputMessages.AddErrorMessage("GenerateManifest.FileAssociationsNotInstalled");
                            }
                        }
                    }
                }
            }
        }

        private void ValidateMinimumRequiredVersion()
        {
            if (!String.IsNullOrEmpty(_minimumRequiredVersion))
            {
                var v1 = new Version(_minimumRequiredVersion);
                var v2 = new Version(AssemblyIdentity.Version);
                if (v1 > v2)
                {
                    OutputMessages.AddErrorMessage("GenerateManifest.GreaterMinimumRequiredVersion");
                }
            }
        }

        #region " XmlSerializer "

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("CreateDesktopShortcut")]
        public string XmlCreateDesktopShortcut
        {
            get => _createDesktopShortcut?.ToLowerInvariant();
            set => _createDesktopShortcut = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlArray("CompatibleFrameworks")]
        public CompatibleFramework[] XmlCompatibleFrameworks
        {
            get => _compatibleFrameworks.Count > 0 ? _compatibleFrameworks.ToArray() : null;
            set => _compatibleFrameworks = new List<CompatibleFramework>(value);
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("DeploymentUrl")]
        public string XmlDeploymentUrl
        {
            get => _deploymentUrl;
            set => _deploymentUrl = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("DisallowUrlActivation")]
        public string XmlDisallowUrlActivation
        {
            get => _disallowUrlActivation?.ToLowerInvariant();
            set => _disallowUrlActivation = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("ErrorReportUrl")]
        public string XmlErrorReportUrl
        {
            get => _errorReportUrl;
            set => _errorReportUrl = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("Install")]
        public string XmlInstall
        {
            get => !String.IsNullOrEmpty(_install) ? _install.ToLower(CultureInfo.InvariantCulture) : "true";  // NOTE: Install attribute shouldn't be null in the manifest, so specify install="true" by default
            set => _install = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("MapFileExtensions")]
        public string XmlMapFileExtensions
        {
            get => _mapFileExtensions?.ToLowerInvariant();
            set => _mapFileExtensions = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("MinimumRequiredVersion")]
        public string XmlMinimumRequiredVersion
        {
            get => _minimumRequiredVersion;
            set => _minimumRequiredVersion = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("Product")]
        public string XmlProduct
        {
            get => _product;
            set => _product = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("Publisher")]
        public string XmlPublisher
        {
            get => _publisher;
            set => _publisher = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("SuiteName")]
        public string XmlSuiteName
        {
            get => _suiteName;
            set => _suiteName = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("SupportUrl")]
        public string XmlSupportUrl
        {
            get => _supportUrl;
            set => _supportUrl = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("TrustUrlParameters")]
        public string XmlTrustUrlParameters
        {
            get => _trustUrlParameters?.ToLowerInvariant();
            set => _trustUrlParameters = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("UpdateEnabled")]
        public string XmlUpdateEnabled
        {
            get => _updateEnabled?.ToLower(CultureInfo.InvariantCulture);
            set => _updateEnabled = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("UpdateInterval")]
        public string XmlUpdateInterval
        {
            get => _updateInterval;
            set => _updateInterval = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("UpdateMode")]
        public string XmlUpdateMode
        {
            get => _updateMode;
            set => _updateMode = value;
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("UpdateUnit")]
        public string XmlUpdateUnit
        {
            get => _updateUnit?.ToLower(CultureInfo.InvariantCulture);
            set => _updateUnit = value;
        }

        #endregion
    }
}


<|start_filename|>src/Xunit.NetCore.Extensions/AssemblyFixtureSupport/AssemblyFixtureAttribute.cs<|end_filename|>
﻿using System;

namespace Xunit
{
    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
    public class AssemblyFixtureAttribute : Attribute
    {
        public AssemblyFixtureAttribute(Type fixtureType)
        {
            FixtureType = fixtureType;
        }

        public Type FixtureType { get; private set; }

        public Scope LifetimeScope { get; set; }

        public enum Scope
        {
            Assembly,
            Class,
            Method
        }
    }
}


<|start_filename|>src/Tasks.UnitTests/MockTypeInfo.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices.ComTypes;

using Marshal = System.Runtime.InteropServices.Marshal;
using VarEnum = System.Runtime.InteropServices.VarEnum;
using IFixedTypeInfo = Microsoft.Build.Tasks.IFixedTypeInfo;
using Xunit;

namespace Microsoft.Build.UnitTests
{
    /// <summary>
    /// A generic interface for creating composite type infos - e.g. a safe array of pointers to something
    /// </summary>
    public interface ICompositeTypeInfo
    {
        TYPEDESC CreateTypeDesc(IntPtr finalTypeHRef, MockUnmanagedMemoryHelper memoryHelper);

        MockTypeInfo GetFinalTypeInfo();
    }

    /// <summary>
    /// Safe array composite type info
    /// </summary>
    public class ArrayCompositeTypeInfo : ICompositeTypeInfo
    {
        private ICompositeTypeInfo _baseElementType;

        public ArrayCompositeTypeInfo(ICompositeTypeInfo baseElement)
        {
            _baseElementType = baseElement;
        }

        #region ICreateTypeDesc Members

        public TYPEDESC CreateTypeDesc(IntPtr finalTypeHRef, MockUnmanagedMemoryHelper memoryHelper)
        {
            TYPEDESC typeDesc;
            typeDesc.vt = (short)VarEnum.VT_SAFEARRAY;
            typeDesc.lpValue = memoryHelper.AllocateHandle(Marshal.SizeOf<TYPEDESC>());
            Marshal.StructureToPtr(_baseElementType.CreateTypeDesc(finalTypeHRef, memoryHelper), typeDesc.lpValue, false);
            return typeDesc;
        }

        /// <summary>
        /// Defer to the base element to get the final type info - this will eventually terminate at a MockTypeInfo node 
        /// which returns itself
        /// </summary>
        /// <returns></returns>
        public MockTypeInfo GetFinalTypeInfo()
        {
            return _baseElementType.GetFinalTypeInfo();
        }

        #endregion
    }

    /// <summary>
    /// Pointer composite type info
    /// </summary>
    public class PtrCompositeTypeInfo : ICompositeTypeInfo
    {
        private ICompositeTypeInfo _baseElementType;

        public PtrCompositeTypeInfo(ICompositeTypeInfo baseElement)
        {
            _baseElementType = baseElement;
        }

        #region ICompositeTypeInfo Members

        public TYPEDESC CreateTypeDesc(IntPtr finalTypeHRef, MockUnmanagedMemoryHelper memoryHelper)
        {
            TYPEDESC typeDesc;
            typeDesc.vt = (short)VarEnum.VT_PTR;
            typeDesc.lpValue = memoryHelper.AllocateHandle(Marshal.SizeOf<TYPEDESC>());
            Marshal.StructureToPtr(_baseElementType.CreateTypeDesc(finalTypeHRef, memoryHelper), typeDesc.lpValue, false);
            return typeDesc;
        }

        public MockTypeInfo GetFinalTypeInfo()
        {
            return _baseElementType.GetFinalTypeInfo();
        }

        #endregion
    }

    /// <summary>
    /// All the information necessary to describe a single function signature
    /// </summary>
    public struct FuncInfo
    {
        public FuncInfo(ICompositeTypeInfo[] parameters, ICompositeTypeInfo returnType)
        {
            this.parameters = parameters;
            this.returnType = returnType;
        }

        public ICompositeTypeInfo[] parameters;
        public ICompositeTypeInfo returnType;
    }

    /// <summary>
    /// Mock class for the ITypeInfo interface
    /// </summary>
    public class MockTypeInfo : ITypeInfo, ICompositeTypeInfo, IFixedTypeInfo
    {
        static private int s_HREF_IMPLTYPES_OFFSET = 1000;
        static private int s_HREF_VARS_OFFSET = 2000;
        static private int s_HREF_FUNCSRET_OFFSET = 3000;
        static private int s_HREF_FUNCSPARAM_OFFSET = 4000;
        static private int s_HREF_FUNCSPARAM_OFFSET_PERFUNC = 100;
        static private int s_HREF_RANGE = 999;

        private MockTypeLib _containingTypeLib;

        public MockTypeLib ContainingTypeLib
        {
            set
            {
                _containingTypeLib = value;
            }
        }

        private int _indexInContainingTypeLib;

        public int IndexInContainingTypeLib
        {
            set
            {
                _indexInContainingTypeLib = value;
            }
        }

        private string _typeName;

        public string TypeName
        {
            set
            {
                _typeName = value;
            }
        }

        private TYPEATTR _typeAttributes;

        private List<MockTypeInfo> _implementedTypes;
        private List<ICompositeTypeInfo> _definedVariables;
        private List<FuncInfo> _definedFunctions;

        private MockUnmanagedMemoryHelper _memoryHelper;

        private MockFaultInjectionHelper<MockTypeLibrariesFailurePoints> _faultInjector;

        /// <summary>
        /// Default constructor
        /// </summary>
        public MockTypeInfo()
        {
            _implementedTypes = new List<MockTypeInfo>();
            _definedVariables = new List<ICompositeTypeInfo>();
            _definedFunctions = new List<FuncInfo>();

            _memoryHelper = new MockUnmanagedMemoryHelper();

            // each type has a unique guid
            _typeAttributes.guid = Guid.NewGuid();

            // default typekind value is TKIND_ENUM so just pick something else that doesn't have a special meaning in the code
            // (we skip enum type infos)
            _typeAttributes.typekind = TYPEKIND.TKIND_INTERFACE;
        }

        /// <summary>
        /// Use a known guid for creating this type info
        /// </summary>
        /// <param name="guid"></param>
        public MockTypeInfo(Guid guid)
            : this()
        {
            _typeAttributes.guid = guid;
        }

        /// <summary>
        /// Use a custom type kind
        /// </summary>
        /// <param name="typeKind"></param>
        public MockTypeInfo(TYPEKIND typeKind)
            : this()
        {
            _typeAttributes.typekind = typeKind;
        }

        /// <summary>
        /// Adds implementedType to the list of this type's implemented interfaces
        /// </summary>
        /// <param name="implementedType"></param>
        public void ImplementsInterface(MockTypeInfo implementedType)
        {
            _typeAttributes.cImplTypes++;
            _implementedTypes.Add(implementedType);
        }

        /// <summary>
        /// Adds implementedType to the list of this type's defined variables
        /// </summary>
        /// <param name="implementedType"></param>
        public void DefinesVariable(ICompositeTypeInfo variableType)
        {
            _typeAttributes.cVars++;
            _definedVariables.Add(variableType);
        }

        /// <summary>
        /// Adds a new function signature to the list of this type's implemented functions
        /// </summary>
        /// <param name="implementedType"></param>
        public void DefinesFunction(MockTypeInfo[] parameters, MockTypeInfo returnType)
        {
            _typeAttributes.cFuncs++;
            _definedFunctions.Add(new FuncInfo(parameters, returnType));
        }

        /// <summary>
        /// Sets the fault injection object for this type
        /// </summary>
        /// <param name="faultInjector"></param>
        public void SetFaultInjector(MockFaultInjectionHelper<MockTypeLibrariesFailurePoints> faultInjector)
        {
            _faultInjector = faultInjector;
        }

        /// <summary>
        /// Helper method for verifying there are no memory leaks
        /// </summary>
        public void AssertAllHandlesReleased()
        {
            _memoryHelper.AssertAllHandlesReleased();
        }

        #region IFixedTypeInfo members

        void IFixedTypeInfo.GetRefTypeOfImplType(int index, out System.IntPtr href)
        {
            Assert.True(index >= 0 && index < _typeAttributes.cImplTypes);

            _faultInjector.FailurePointThrow(MockTypeLibrariesFailurePoints.ITypeInfo_GetRefTypeOfImplType);

            href = ((System.IntPtr)index + s_HREF_IMPLTYPES_OFFSET);
        }

        void IFixedTypeInfo.GetRefTypeInfo(System.IntPtr hRef, out IFixedTypeInfo ppTI)
        {
            _faultInjector.FailurePointThrow(MockTypeLibrariesFailurePoints.ITypeInfo_GetRefTypeInfo);
            int hRefInt = (int)hRef;

            if (hRefInt >= s_HREF_IMPLTYPES_OFFSET && hRefInt <= s_HREF_IMPLTYPES_OFFSET + s_HREF_RANGE)
            {
                ppTI = _implementedTypes[hRefInt - s_HREF_IMPLTYPES_OFFSET];
            }
            else if (hRefInt >= s_HREF_VARS_OFFSET && hRefInt <= s_HREF_VARS_OFFSET + s_HREF_RANGE)
            {
                ppTI = _definedVariables[hRefInt - s_HREF_VARS_OFFSET].GetFinalTypeInfo();
            }
            else if (hRefInt >= s_HREF_FUNCSRET_OFFSET && hRefInt <= s_HREF_FUNCSRET_OFFSET + s_HREF_RANGE)
            {
                ppTI = _definedFunctions[hRefInt - s_HREF_FUNCSRET_OFFSET].returnType.GetFinalTypeInfo();
            }
            else if (hRefInt >= s_HREF_FUNCSPARAM_OFFSET && hRefInt <= s_HREF_FUNCSPARAM_OFFSET + s_HREF_RANGE)
            {
                ppTI = _definedFunctions[(hRefInt - s_HREF_FUNCSPARAM_OFFSET) / s_HREF_FUNCSPARAM_OFFSET_PERFUNC].parameters[(hRefInt - s_HREF_FUNCSPARAM_OFFSET) % s_HREF_FUNCSPARAM_OFFSET_PERFUNC].GetFinalTypeInfo();
            }
            else
            {
                ppTI = null;
                Assert.True(false, "unexpected hRef value");
            }
        }

        #endregion 

        #region Implemented ITypeInfo members

        public void GetContainingTypeLib(out ITypeLib ppTLB, out int pIndex)
        {
            _faultInjector.FailurePointThrow(MockTypeLibrariesFailurePoints.ITypeInfo_GetContainingTypeLib);

            ppTLB = _containingTypeLib;
            pIndex = _indexInContainingTypeLib;
        }

        public void GetTypeAttr(out IntPtr ppTypeAttr)
        {
            // Fail BEFORE allocating the handle to avoid leaks. If the real COM object fails in this method
            // and doesn't return the handle or clean it up itself there's not much we can do to avoid the leak.
            _faultInjector.FailurePointThrow(MockTypeLibrariesFailurePoints.ITypeInfo_GetTypeAttr);

            ppTypeAttr = _memoryHelper.AllocateHandle(Marshal.SizeOf<TYPEATTR>());
            Marshal.StructureToPtr(_typeAttributes, ppTypeAttr, false);
        }

        public void ReleaseTypeAttr(IntPtr pTypeAttr)
        {
            _memoryHelper.FreeHandle(pTypeAttr);

            // Fail AFTER releasing the handle to avoid leaks. If the real COM object fails in this method
            // there's really nothing we can do to avoid leaking stuff
            _faultInjector.FailurePointThrow(MockTypeLibrariesFailurePoints.ITypeInfo_ReleaseTypeAttr);
        }

        public void GetRefTypeOfImplType(int index, out int href)
        {
            Assert.True(index >= 0 && index < _typeAttributes.cImplTypes);

            _faultInjector.FailurePointThrow(MockTypeLibrariesFailurePoints.ITypeInfo_GetRefTypeOfImplType);

            href = index + s_HREF_IMPLTYPES_OFFSET;
        }

        public void GetRefTypeInfo(int hRef, out ITypeInfo ppTI)
        {
            _faultInjector.FailurePointThrow(MockTypeLibrariesFailurePoints.ITypeInfo_GetRefTypeInfo);

            if (hRef >= s_HREF_IMPLTYPES_OFFSET && hRef <= s_HREF_IMPLTYPES_OFFSET + s_HREF_RANGE)
            {
                ppTI = _implementedTypes[hRef - s_HREF_IMPLTYPES_OFFSET];
            }
            else if (hRef >= s_HREF_VARS_OFFSET && hRef <= s_HREF_VARS_OFFSET + s_HREF_RANGE)
            {
                ppTI = _definedVariables[hRef - s_HREF_VARS_OFFSET].GetFinalTypeInfo();
            }
            else if (hRef >= s_HREF_FUNCSRET_OFFSET && hRef <= s_HREF_FUNCSRET_OFFSET + s_HREF_RANGE)
            {
                ppTI = _definedFunctions[hRef - s_HREF_FUNCSRET_OFFSET].returnType.GetFinalTypeInfo();
            }
            else if (hRef >= s_HREF_FUNCSPARAM_OFFSET && hRef <= s_HREF_FUNCSPARAM_OFFSET + s_HREF_RANGE)
            {
                ppTI = _definedFunctions[(hRef - s_HREF_FUNCSPARAM_OFFSET) / s_HREF_FUNCSPARAM_OFFSET_PERFUNC].parameters[(hRef - s_HREF_FUNCSPARAM_OFFSET) % s_HREF_FUNCSPARAM_OFFSET_PERFUNC].GetFinalTypeInfo();
            }
            else
            {
                ppTI = null;
                Assert.True(false, "unexpected hRef value");
            }
        }

        public void GetVarDesc(int index, out IntPtr ppVarDesc)
        {
            // Fail BEFORE allocating the handle to avoid leaks. If the real COM object fails in this method
            // and doesn't return the handle or clean it up itself there's not much we can do to avoid the leak.
            _faultInjector.FailurePointThrow(MockTypeLibrariesFailurePoints.ITypeInfo_GetVarDesc);

            ppVarDesc = _memoryHelper.AllocateHandle(Marshal.SizeOf<VARDESC>());

            _memoryHelper.EnterSubAllocationScope(ppVarDesc);
            VARDESC varDesc = new VARDESC();
            varDesc.elemdescVar.tdesc = _definedVariables[index].CreateTypeDesc(new IntPtr(index + s_HREF_VARS_OFFSET), _memoryHelper);
            _memoryHelper.ExitSubAllocationScope();

            Marshal.StructureToPtr(varDesc, ppVarDesc, false);
        }

        public void ReleaseVarDesc(IntPtr pVarDesc)
        {
            _memoryHelper.FreeHandle(pVarDesc);

            // Fail AFTER releasing the handle to avoid leaks. If the real COM object fails in this method
            // there's really nothing we can do to avoid leaking stuff
            _faultInjector.FailurePointThrow(MockTypeLibrariesFailurePoints.ITypeInfo_ReleaseVarDesc);
        }

        public void GetFuncDesc(int index, out IntPtr ppFuncDesc)
        {
            // Fail BEFORE allocating the handle to avoid leaks. If the real COM object fails in this method
            // and doesn't return the handle or clean it up itself there's not much we can do to avoid the leak.
            _faultInjector.FailurePointThrow(MockTypeLibrariesFailurePoints.ITypeInfo_GetFuncDesc);

            ppFuncDesc = _memoryHelper.AllocateHandle(Marshal.SizeOf<FUNCDESC>());

            _memoryHelper.EnterSubAllocationScope(ppFuncDesc);
            FUNCDESC funcDesc = new FUNCDESC();

            funcDesc.lprgelemdescParam = _memoryHelper.AllocateHandle(_definedFunctions[index].parameters.Length * Marshal.SizeOf<ELEMDESC>());
            funcDesc.cParams = (short)_definedFunctions[index].parameters.Length;

            for (int i = 0; i < _definedFunctions[index].parameters.Length; i++)
            {
                ELEMDESC elemDesc = new ELEMDESC();
                elemDesc.tdesc = _definedFunctions[index].parameters[i].CreateTypeDesc(
                    new IntPtr((index * s_HREF_FUNCSPARAM_OFFSET_PERFUNC) + i + s_HREF_FUNCSPARAM_OFFSET), _memoryHelper);

                Marshal.StructureToPtr(
                    elemDesc,
                    new IntPtr(funcDesc.lprgelemdescParam.ToInt64() + (i * Marshal.SizeOf<ELEMDESC>())),
                    false);
            }

            funcDesc.elemdescFunc.tdesc = _definedFunctions[index].returnType.CreateTypeDesc(
                new IntPtr(index + s_HREF_FUNCSRET_OFFSET), _memoryHelper);
            _memoryHelper.ExitSubAllocationScope();

            Marshal.StructureToPtr(funcDesc, ppFuncDesc, false);
        }

        public void ReleaseFuncDesc(IntPtr pFuncDesc)
        {
            _memoryHelper.FreeHandle(pFuncDesc);

            // Fail AFTER releasing the handle to avoid leaks. If the real COM object fails in this method
            // there's really nothing we can do to avoid leaking stuff
            _faultInjector.FailurePointThrow(MockTypeLibrariesFailurePoints.ITypeInfo_ReleaseFuncDesc);
        }

        public void GetDocumentation(int index, out string strName, out string strDocString, out int dwHelpContext, out string strHelpFile)
        {
            Assert.Equal(-1, index);

            _faultInjector.FailurePointThrow(MockTypeLibrariesFailurePoints.ITypeInfo_GetDocumentation);

            strName = _typeName;
            strDocString = "garbage";
            dwHelpContext = -1;
            strHelpFile = "garbage^2";
        }

        #endregion

        #region ICreateTypeDesc Members

        public TYPEDESC CreateTypeDesc(IntPtr finalTypeHRef, MockUnmanagedMemoryHelper memoryHelper)
        {
            TYPEDESC typeDesc;
            typeDesc.vt = (short)VarEnum.VT_USERDEFINED;
            typeDesc.lpValue = finalTypeHRef;
            return typeDesc;
        }

        public MockTypeInfo GetFinalTypeInfo()
        {
            return this;
        }

        #endregion

        #region Stubbed ITypeInfo members

        public void AddressOfMember(int memid, INVOKEKIND invKind, out IntPtr ppv)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void CreateInstance(object pUnkOuter, ref Guid riid, out object ppvObj)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void GetDllEntry(int memid, INVOKEKIND invKind, IntPtr pBstrDllName, IntPtr pBstrName, IntPtr pwOrdinal)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void GetIDsOfNames(string[] rgszNames, int cNames, int[] pMemId)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void GetImplTypeFlags(int index, out IMPLTYPEFLAGS pImplTypeFlags)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void GetMops(int memid, out string pBstrMops)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void GetNames(int memid, string[] rgBstrNames, int cMaxNames, out int pcNames)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void GetTypeComp(out ITypeComp ppTComp)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void Invoke(object pvInstance, int memid, short wFlags, ref DISPPARAMS pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, out int puArgErr)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        #endregion
    }
}


<|start_filename|>src/Framework/XamlTypes/StringListProperty.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Microsoft.Build.Framework.XamlTypes
{
    /// <summary>
    /// Represents the schema of a list-of-strings property. 
    /// </summary>
    /// <remarks>
    /// Note, this represents
    /// a list of strings, not a list of <see cref="StringProperty"/>s.
    /// </remarks>
    public sealed class StringListProperty : BaseProperty
    {
        #region Constructor

        /// <summary>
        /// Default constructor. Needed for property XAML deserialization.
        /// </summary>
        public StringListProperty()
        {
            RendererValueSeparator = ";";
        }

        #endregion

        #region Properties

        /// <summary>
        /// The separator to use in delineating individual values of this string list property
        /// </summary>
        /// <remarks>
        /// For <c>Val1;Val2;Val3</c>, if <c>CommandLineValueSeparator</c> is specified as, say <c>,</c>,
        /// the command line looks like this: <c>/p:val1,val2,val3</c>
        /// If not specified, the command line looks like this: <c>/p:val1 /p:val2 /p:val3</c>
        /// This field is optional.
        /// </remarks>
        public string CommandLineValueSeparator
        {
            get;
            set;
        }

        /// <summary>
        /// Please don't use. This is planned to be deprecated.
        /// </summary>
        public string RendererValueSeparator
        {
            get;
            set;
        }

        /// <summary>
        /// Qualifies this string property to give it a more specific classification.
        /// </summary>
        /// <remarks>
        /// Similar to the <see cref="StringProperty.Subtype"/> property. 
        /// </remarks>
        public string Subtype
        {
            get;
            set;
        }

        #endregion
    }
}


<|start_filename|>src/Tasks.UnitTests/AssemblyDependency/Miscellaneous.cs<|end_filename|>
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using Microsoft.Build.Tasks;
using Microsoft.Build.Utilities;
using Microsoft.Win32;
using Xunit;
using SystemProcessorArchitecture = System.Reflection.ProcessorArchitecture;
using Xunit.Abstractions;
using Shouldly;
using System.Text;

namespace Microsoft.Build.UnitTests.ResolveAssemblyReference_Tests
{
    /// <summary>
    /// Unit tests for the ResolveAssemblyReference task.
    /// </summary>
    public sealed class Miscellaneous : ResolveAssemblyReferenceTestFixture
    {
        private static List<string> s_assemblyFolderExTestVersions = new List<string>
        {
            "v1.0",
            "v2.0.50727",
            "v3.0",
            "v3.5",
            "v4.0",
            "v4.0.2116",
            "v4.1",
            "v4.0.255",
            "v4.0.255.87",
            "v4.0.9999",
            "v4.0.0000",
            "v4.0001.0",
            "v4.0.2116.87",
            "v3.0SP1",
            "v3.0 BAZ",
            "v5.0",
            "v1",
            "v5",
            "v3.5.0.x86chk",
            "v3.5.1.x86chk",
            "v3.5.256.x86chk",
            "v",
            "1",
            "1.0",
            "1.0.0",
            "V3.5.0.0.0",
            "V3..",
            "V-1",
            "V9999999999999999",
            "Dan_rocks_bigtime",
            "v00001.0"
        };

        private string _fullRedistListContents =
            "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
            "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
            "<File AssemblyName='Microsoft.Build.Engine' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
            "</FileList >";

        /// <summary>
        /// The contents of a subsetFile which only contain the Microsoft.Build.Engine assembly in the white list
        /// </summary>
        private string _engineOnlySubset =
            "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
            "<File AssemblyName='Microsoft.Build.Engine' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
            "</FileList >";

        /// <summary>
        /// The contents of a subsetFile which only contain the System.Xml assembly in the white list
        /// </summary>
        private string _xmlOnlySubset =
            "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
            "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
            "</FileList >";

        /// <summary>
        /// The contents of a subsetFile which contain both the Microsoft.Build.Engine and System.Xml assemblies in the white list
        /// </summary>
        private string _engineAndXmlSubset =
            "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
            "<File AssemblyName='Microsoft.Build.Engine' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
            "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
            "</FileList >";

        public Miscellaneous(ITestOutputHelper output) : base(output)
        {
        }

        /// <summary>
        /// Let us have the following dependency structure
        ///
        /// X which is in the gac, depends on Z which is not in the GAC
        ///
        /// Let copyLocalDependenciesWhenParentReferenceInGac be set to false
        ///
        /// Since copyLocalDependenciesWhenParentReferenceInGac is set to false and the parent of Z is in the GAC
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void CopyLocalDependenciesWhenParentReferenceInGacFalseAllParentsInGac()
        {
            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            ITaskItem[] assemblyNames = new TaskItem[]
                    {
                        new TaskItem("X, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null")
                    };

            // Now, pass feed resolved primary references into ResolveAssemblyReference.
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = engine;
            t.Assemblies = assemblyNames;

            if (NativeMethodsShared.IsWindows)
            {
                t.SearchPaths = new string[] { "{gac}", s_myComponentsRootPath };
            }
            else
            {
                t.SearchPaths = new string[] { s_myComponentsRootPath };
            }

            t.CopyLocalDependenciesWhenParentReferenceInGac = false;
            bool succeeded = Execute(t);

            Assert.True(succeeded);
            Assert.Single(t.ResolvedFiles);
            Assert.Single(t.ResolvedDependencyFiles);
            Assert.Equal(0, engine.Errors);
            Assert.Equal(0, engine.Warnings);
            t.ResolvedDependencyFiles[0].GetMetadata("CopyLocal").ShouldBe("false", StringCompareShould.IgnoreCase);
            t.ResolvedFiles[0].GetMetadata("CopyLocal").ShouldBe("false", StringCompareShould.IgnoreCase);
        }

        [Fact]
        public void ValidateFrameworkNameError()
        {
            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            ITaskItem[] assemblyNames = new TaskItem[]
                    {
                        new TaskItem("X, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null")
                    };

            // Now, pass feed resolved primary references into ResolveAssemblyReference.
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = engine;
            t.Assemblies = assemblyNames;
            t.SearchPaths = new string[] { s_myComponentsRootPath };
            t.TargetFrameworkMoniker = "I am a random frameworkName";
            bool succeeded = Execute(t);

            Assert.False(succeeded);
            Assert.Equal(1, engine.Errors);
            Assert.Equal(0, engine.Warnings);
            string message = ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveAssemblyReference.InvalidParameter", "TargetFrameworkMoniker", t.TargetFrameworkMoniker, String.Empty);
            engine.AssertLogContains(message);
        }

        /// <summary>
        /// Let us have the following dependency structure
        ///
        /// X which is in the gac, depends on Z which is not in the GAC
        /// Y which is not in the gac, depends on Z which is not in the GAC
        ///
        /// Let copyLocalDependenciesWhenParentReferenceInGac be set to false
        ///
        /// Since copyLocalDependenciesWhenParentReferenceInGac is set to false but one of the parents of Z is not in the GAC and Z is not in the gac we should be copy local
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void CopyLocalDependenciesWhenParentReferenceInGacFalseSomeParentsInGac()
        {
            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            ITaskItem[] assemblyNames = new TaskItem[]
                    {
                        new TaskItem("X, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"),
                        new TaskItem("Y, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null")
                    };

            // Now, pass feed resolved primary references into ResolveAssemblyReference.
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = engine;
            t.Assemblies = assemblyNames;

            if (NativeMethodsShared.IsWindows)
            {
                t.SearchPaths = new string[] { "{gac}", s_myComponentsRootPath };
            }
            else
            {
                t.SearchPaths = new string[] { s_myComponentsRootPath };
            }

            t.CopyLocalDependenciesWhenParentReferenceInGac = false;
            bool succeeded = Execute(t);

            Assert.True(succeeded);
            Assert.Equal(2, t.ResolvedFiles.Length);
            Assert.Single(t.ResolvedDependencyFiles);
            Assert.Equal(0, engine.Errors);
            Assert.Equal(0, engine.Warnings);
            t.ResolvedFiles[0].GetMetadata("CopyLocal").ShouldBe("false", StringCompareShould.IgnoreCase);
            t.ResolvedFiles[1].GetMetadata("CopyLocal").ShouldBe("true", StringCompareShould.IgnoreCase);
            t.ResolvedDependencyFiles[0].GetMetadata("CopyLocal").ShouldBe("true", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// Make sure that when we parse the runtime version that if there is a bad one we default to 2.0.
        /// </summary>
        [Fact]
        public void TestSetRuntimeVersion()
        {
            Version parsedVersion = ResolveAssemblyReference.SetTargetedRuntimeVersion("4.0.21006");
            Assert.Equal(new Version("4.0.21006"), parsedVersion);

            parsedVersion = ResolveAssemblyReference.SetTargetedRuntimeVersion("BadVersion");
            Assert.Equal(new Version("2.0.50727"), parsedVersion);
        }

        /// <summary>
        /// Let us have the following dependency structure
        ///
        /// X which is in the gac, depends on Z which is not in the GAC
        ///
        /// Let copyLocalDependenciesWhenParentReferenceInGac be set to true
        ///
        /// Since copyLocalDependenciesWhenParentReferenceInGac is set to true and Z is not in the GAC it will be copy local true
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void CopyLocalDependenciesWhenParentReferenceInGacTrueAllParentsInGac()
        {
            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            ITaskItem[] assemblyNames = new TaskItem[]
                    {
                        new TaskItem("X, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null")
                    };

            // Now, pass feed resolved primary references into ResolveAssemblyReference.
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = engine;
            t.Assemblies = assemblyNames;

            if (NativeMethodsShared.IsWindows)
            {
                t.SearchPaths = new string[] { "{gac}", s_myComponentsRootPath };
            }
            else
            {
                t.SearchPaths = new string[] { s_myComponentsRootPath };
            }

            t.CopyLocalDependenciesWhenParentReferenceInGac = true;
            bool succeeded = Execute(t);

            Assert.True(succeeded);
            Assert.Single(t.ResolvedFiles);
            Assert.Single(t.ResolvedDependencyFiles);
            Assert.Equal(0, engine.Errors);
            Assert.Equal(0, engine.Warnings);
            t.ResolvedDependencyFiles[0].GetMetadata("CopyLocal").ShouldBe("true", StringCompareShould.IgnoreCase);
            t.ResolvedFiles[0].GetMetadata("CopyLocal").ShouldBe("false", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// Let us have the following dependency structure
        ///
        /// X which is in the gac, depends on Z which is not in the GAC
        /// Y which is not in the gac, depends on Z which is not in the GAC
        ///
        /// Let copyLocalDependenciesWhenParentReferenceInGac be set to true
        ///
        /// Since copyLocalDependenciesWhenParentReferenceInGac is set to true and Z is not in the GAC it will be copy local true
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void CopyLocalDependenciesWhenParentReferenceInGacTrueSomeParentsInGac()
        {
            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            ITaskItem[] assemblyNames = new TaskItem[]
                    {
                        new TaskItem("X, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"),
                        new TaskItem("Y, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null")
                    };

            // Now, pass feed resolved primary references into ResolveAssemblyReference.
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = engine;
            t.Assemblies = assemblyNames;

            if (NativeMethodsShared.IsWindows)
            {
                t.SearchPaths = new string[] { "{gac}", s_myComponentsRootPath };
            }
            else
            {
                t.SearchPaths = new string[] { s_myComponentsRootPath };
            }

            t.CopyLocalDependenciesWhenParentReferenceInGac = true;
            bool succeeded = Execute(t);

            Assert.True(succeeded);
            Assert.Equal(2, t.ResolvedFiles.Length);
            Assert.Single(t.ResolvedDependencyFiles);
            Assert.Equal(0, engine.Errors);
            Assert.Equal(0, engine.Warnings);
            t.ResolvedFiles[0].GetMetadata("CopyLocal").ShouldBe("false", StringCompareShould.IgnoreCase);
            t.ResolvedFiles[1].GetMetadata("CopyLocal").ShouldBe("true", StringCompareShould.IgnoreCase);
            t.ResolvedDependencyFiles[0].GetMetadata("CopyLocal").ShouldBe("true", StringCompareShould.IgnoreCase);
        }

        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void CopyLocalDependenciesWhenParentReferenceNotInGac()
        {
            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            ITaskItem[] assemblyNames = new TaskItem[]
                    {
                        // V not in GAC, depends on W (in GAC)
                        // V - CopyLocal should be true (resolved locally)
                        // W - CopyLocal should be false (resolved {gac})
                        new TaskItem("V, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"),
                    };

            // Now, pass feed resolved primary references into ResolveAssemblyReference.
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = engine;
            t.Assemblies = assemblyNames;
            t.SearchPaths = new string[] { "{gac}", @"c:\MyComponents" };
            bool succeeded = Execute(t);

            Assert.True(succeeded);
            Assert.Single(t.ResolvedFiles);
            Assert.Single(t.CopyLocalFiles);
            Assert.Single(t.ResolvedDependencyFiles);
            Assert.Equal(0, engine.Errors);
            Assert.Equal(0, engine.Warnings);
            t.ResolvedFiles[0].GetMetadata("CopyLocal").ShouldBe("true", StringCompareShould.IgnoreCase);
            t.ResolvedDependencyFiles[0].GetMetadata("CopyLocal").ShouldBe("false", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// Test the legacy behavior for copy local (set to false when an assembly exists in the gac no matter
        /// where it was actually resolved). Sets DoNotCopyLocalIfInGac = true
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void CopyLocalLegacyBehavior()
        {
            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            ITaskItem[] assemblyNames = new TaskItem[]
                    {
                        // V not in GAC, depends on W (in GAC)
                        // V - CopyLocal should be true (resolved locally)
                        // W - CopyLocal should be false (resolved from "c:\MyComponents" BUT exists in GAC, so false)
                        // (changed the order of the search paths to emulate this)
                        new TaskItem("V, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"),
                    };

            // Now, pass feed resolved primary references into ResolveAssemblyReference.
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = engine;
            t.Assemblies = assemblyNames;
            t.DoNotCopyLocalIfInGac = true;
            t.SearchPaths = new string[] { @"c:\MyComponents", "{gac}", };
            bool succeeded = Execute(t);

            Assert.True(succeeded);
            Assert.Single(t.ResolvedFiles);
            Assert.Single(t.CopyLocalFiles);
            Assert.Single(t.ResolvedDependencyFiles);
            Assert.Equal(0, engine.Errors);
            Assert.Equal(0, engine.Warnings);
            t.ResolvedFiles[0].GetMetadata("CopyLocal").ShouldBe("true", StringCompareShould.IgnoreCase);
            t.ResolvedDependencyFiles[0].GetMetadata("CopyLocal").ShouldBe("false", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// Very basic test.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        [Trait("Category", "mono-windows-failing")]
        public void Basic()
        {
            // This WriteLine is a hack.  On a slow machine, the Tasks unittest fails because remoting
            // times out the object used for remoting console writes.  Adding a write in the middle of
            // keeps remoting from timing out the object.
            Console.WriteLine("Performing Miscellaneous.Basic() test");

            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            // Construct a list of assembly files.
            ITaskItem[] assemblyFiles = new TaskItem[]
            {
                new TaskItem(s_myMissingAssemblyAbsPath)
            };

            // Also construct a set of assembly names to pass in.
            ITaskItem[] assemblyNames = new TaskItem[]
            {
                new TaskItem("System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
                new TaskItem("MyPrivateAssembly"),
                new TaskItem("MyGacAssembly"),
                new TaskItem("MyCopyLocalAssembly"),
                new TaskItem("MyDontCopyLocalAssembly"),
                new TaskItem("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
            };

            assemblyNames[0].SetMetadata("RandomAttributeThatShouldBeForwarded", "1776");
            // Metadata which should NOT be forwarded
            assemblyNames[0].SetMetadata(ItemMetadataNames.imageRuntime, "FOO");
            assemblyNames[0].SetMetadata(ItemMetadataNames.winMDFile, "NOPE");
            assemblyNames[0].SetMetadata(ItemMetadataNames.winmdImplmentationFile, "IMPL");

            assemblyNames[1].SetMetadata("Private", "true");
            assemblyNames[2].SetMetadata("Private", "false");
            assemblyNames[4].SetMetadata("Private", "false");

            // Now, pass feed resolved primary references into ResolveAssemblyReference.
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = engine;
            t.AssemblyFiles = assemblyFiles;
            t.Assemblies = assemblyNames;
            t.TargetFrameworkDirectories = new string[] { s_myVersion20Path };
            t.SearchPaths = DefaultPaths;
            Execute(t);

            // Now, loop over the closure of dependencies and make sure we have what we need.
            bool enSatellitePdbFound = false;
            bool systemXmlFound = false;
            bool systemDataFound = false;
            bool systemFound = false;
            bool mscorlibFound = false;
            bool myGacAssemblyFound = false;
            bool myPrivateAssemblyFound = false;
            bool myCopyLocalAssemblyFound = false;
            bool myDontCopyLocalAssemblyFound = false;
            bool engbSatellitePdbFound = false;
            bool missingAssemblyFound = false;

            // Process the primary items.
            foreach (ITaskItem item in t.ResolvedFiles)
            {
                if (String.Equals(item.ItemSpec, Path.Combine(s_myVersion20Path, "System.XML.dll"), StringComparison.OrdinalIgnoreCase))
                {
                    systemXmlFound = true;
                    item.GetMetadata("DestinationSubDirectory").ShouldBe("", StringCompareShould.IgnoreCase);
                    item.GetMetadata("RandomAttributeThatShouldBeForwarded").ShouldBe("1776", StringCompareShould.IgnoreCase);
                    item.GetMetadata("CopyLocal").ShouldBe("false", StringCompareShould.IgnoreCase);
                    item.GetMetadata("FusionName").ShouldBe("System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", StringCompareShould.IgnoreCase);
                    item.GetMetadata(ItemMetadataNames.imageRuntime).ShouldBe("v2.0.50727", StringCompareShould.IgnoreCase);
                    item.GetMetadata(ItemMetadataNames.winMDFile).ShouldBe("NOPE", StringCompareShould.IgnoreCase);
                    item.GetMetadata(ItemMetadataNames.winmdImplmentationFile).ShouldBe("IMPL", StringCompareShould.IgnoreCase);
                }
                else if (item.ItemSpec.EndsWith(Path.Combine("v2.0.MyVersion", "System.Data.dll")))
                {
                    systemDataFound = true;
                    item.GetMetadata("DestinationSubDirectory").ShouldBe("", StringCompareShould.IgnoreCase);
                    item.GetMetadata("RandomAttributeThatShouldBeForwarded").ShouldBe("", StringCompareShould.IgnoreCase);
                    item.GetMetadata("CopyLocal").ShouldBe("false", StringCompareShould.IgnoreCase);
                    item.GetMetadata("FusionName").ShouldBe("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", StringCompareShould.IgnoreCase);
                }
                else if (item.ItemSpec.EndsWith(Path.Combine("v2.0.MyVersion", "MyGacAssembly.dll")))
                {
                    myGacAssemblyFound = true;
                    item.GetMetadata("DestinationSubDirectory").ShouldBe("", StringCompareShould.IgnoreCase);
                    item.GetMetadata("RandomAttributeThatShouldBeForwarded").ShouldBe("", StringCompareShould.IgnoreCase);
                    item.GetMetadata("CopyLocal").ShouldBe("false", StringCompareShould.IgnoreCase);
                }
                else if (item.ItemSpec.EndsWith(s_myPrivateAssemblyRelPath))
                {
                    myPrivateAssemblyFound = true;
                    item.GetMetadata("DestinationSubDirectory").ShouldBe("", StringCompareShould.IgnoreCase);
                    item.GetMetadata("RandomAttributeThatShouldBeForwarded").ShouldBe("", StringCompareShould.IgnoreCase);
                    item.GetMetadata("CopyLocal").ShouldBe("true", StringCompareShould.IgnoreCase);
                }
                else if (item.ItemSpec.EndsWith(Path.Combine("MyProject", "MyCopyLocalAssembly.dll")))
                {
                    myCopyLocalAssemblyFound = true;
                    item.GetMetadata("DestinationSubDirectory").ShouldBe("", StringCompareShould.IgnoreCase);
                    item.GetMetadata("RandomAttributeThatShouldBeForwarded").ShouldBe("", StringCompareShould.IgnoreCase);
                    item.GetMetadata("CopyLocal").ShouldBe("true", StringCompareShould.IgnoreCase);
                }
                else if (item.ItemSpec.EndsWith(Path.Combine("MyProject", "MyDontCopyLocalAssembly.dll")))
                {
                    myDontCopyLocalAssemblyFound = true;
                    item.GetMetadata("DestinationSubDirectory").ShouldBe("", StringCompareShould.IgnoreCase);
                    item.GetMetadata("RandomAttributeThatShouldBeForwarded").ShouldBe("", StringCompareShould.IgnoreCase);
                    item.GetMetadata("CopyLocal").ShouldBe("false", StringCompareShould.IgnoreCase);
                }
                else if (item.ItemSpec.EndsWith(s_myMissingAssemblyRelPath))
                {
                    missingAssemblyFound = true;
                    item.GetMetadata("DestinationSubDirectory").ShouldBe("", StringCompareShould.IgnoreCase);
                    item.GetMetadata("RandomAttributeThatShouldBeForwarded").ShouldBe("", StringCompareShould.IgnoreCase);

                    // Its debatable whether this file should be CopyLocal or not.
                    // It doesn't exist on disk, but is it ResolveAssemblyReference's job to make sure that it does?
                    // For now, let the default CopyLocal rules apply.
                    item.GetMetadata("CopyLocal").ShouldBe("true", StringCompareShould.IgnoreCase);
                    item.GetMetadata("FusionName").ShouldBe("MyMissingAssembly", StringCompareShould.IgnoreCase);
                }
                else if (String.Equals(item.ItemSpec, Path.Combine(s_myProjectPath, "System.Xml.dll"), StringComparison.OrdinalIgnoreCase))
                {
                    // The version of System.Xml.dll in C:\MyProject is an older version.
                    // This version is not a match. When want the current version which should have been in a different directory.
                    Assert.True(false, "Wrong version of System.Xml.dll matched--version was wrong");
                }
                else if (String.Equals(item.ItemSpec, Path.Combine(s_myProjectPath, "System.Data.dll"), StringComparison.OrdinalIgnoreCase))
                {
                    // The version of System.Data.dll in C:\MyProject has an incorrect PKT
                    // This version is not a match.
                    Assert.True(false, "Wrong version of System.Data.dll matched--public key token was wrong");
                }
                else
                {
                    Assert.True(false, String.Format("A new resolved file called '{0}' was found. If this is intentional, then add unittests above.", item.ItemSpec));
                }
            }

            // Process the dependencies.
            foreach (ITaskItem item in t.ResolvedDependencyFiles)
            {
                if (item.ItemSpec.EndsWith(Path.Combine("v2.0.MyVersion", "SysTem.dll")))
                {
                    systemFound = true;
                    item.GetMetadata("DestinationSubDirectory").ShouldBe("", StringCompareShould.IgnoreCase);
                    item.GetMetadata("RandomAttributeThatShouldBeForwarded").ShouldBe("", StringCompareShould.IgnoreCase);
                    item.GetMetadata("CopyLocal").ShouldBe("false", StringCompareShould.IgnoreCase);
                    item.GetMetadata("FusionName").ShouldBe("System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", StringCompareShould.IgnoreCase);
                }
                else if (item.ItemSpec.EndsWith(Path.Combine("v2.0.MyVersion", "mscorlib.dll")))
                {
                    mscorlibFound = true;
                    item.GetMetadata("DestinationSubDirectory").ShouldBe("", StringCompareShould.IgnoreCase);
                    item.GetMetadata("RandomAttributeThatShouldBeForwarded").ShouldBe("1776", StringCompareShould.IgnoreCase);
                    item.GetMetadata("CopyLocal").ShouldBe("false", StringCompareShould.IgnoreCase);
                    item.GetMetadata(ItemMetadataNames.imageRuntime).ShouldBe("v2.0.50727", StringCompareShould.IgnoreCase);
                    Assert.Empty(item.GetMetadata(ItemMetadataNames.winMDFile));
                    Assert.Empty(item.GetMetadata(ItemMetadataNames.winmdImplmentationFile));

                    // Notice how the following doesn't have 'version'. This is because all versions of mscorlib 'unify'
                    Assert.Equal(AssemblyRef.Mscorlib, item.GetMetadata("FusionName"));
                }
                else
                {
                    Assert.True(false, String.Format("A new dependency called '{0}' was found. If this is intentional, then add unittests above.", item.ItemSpec));
                }
            }

            // Process the related files.
            foreach (ITaskItem item in t.RelatedFiles)
            {
                Assert.True(false, String.Format("A new dependency called '{0}' was found. If this is intentional, then add unittests above.", item.ItemSpec));
            }

            // Process the satellites.
            foreach (ITaskItem item in t.SatelliteFiles)
            {
                if (String.Equals(item.ItemSpec, Path.Combine(s_myVersion20Path, "en", "System.XML.resources.pdb"), StringComparison.OrdinalIgnoreCase))
                {
                    enSatellitePdbFound = true;
                    Assert.Empty(item.GetMetadata(ItemMetadataNames.imageRuntime));
                    Assert.Empty(item.GetMetadata(ItemMetadataNames.winMDFile));
                    Assert.Empty(item.GetMetadata(ItemMetadataNames.winmdImplmentationFile));
                }
                else if (String.Equals(item.ItemSpec, Path.Combine(s_myVersion20Path, "en-GB", "System.XML.resources.pdb"), StringComparison.OrdinalIgnoreCase))
                {
                    engbSatellitePdbFound = true;
                    Assert.Empty(item.GetMetadata(ItemMetadataNames.imageRuntime));
                    Assert.Empty(item.GetMetadata(ItemMetadataNames.winMDFile));
                    Assert.Empty(item.GetMetadata(ItemMetadataNames.winmdImplmentationFile));
                }
                else
                {
                    Assert.True(false, String.Format("A new dependency called '{0}' was found. If this is intentional, then add unittests above.", item.ItemSpec));
                }
            }

            Assert.False(enSatellitePdbFound); // "Expected to not find satellite pdb."
            Assert.True(systemXmlFound); // "Expected to find returned item."
            Assert.True(systemDataFound); // "Expected to find returned item."
            Assert.True(systemFound); // "Expected to find returned item."
            Assert.False(mscorlibFound); // "Expected to not find returned item."
            Assert.True(myGacAssemblyFound); // "Expected to find returned item."
            Assert.True(myPrivateAssemblyFound); // "Expected to find returned item."
            Assert.True(myCopyLocalAssemblyFound); // "Expected to find returned item."
            Assert.True(myDontCopyLocalAssemblyFound); // "Expected to find returned item."
            Assert.False(engbSatellitePdbFound); // "Expected to not find satellite pdb."
            Assert.True(missingAssemblyFound); // "Expected to find returned item."
        }

        /// <summary>
        /// Auxiliary enumeration for EmbedInteropTypes test.
        /// Defines indices for accessing test's data structures.
        /// </summary>
        private enum EmbedInteropTypes_Indices
        {
            MyMissingAssembly = 0,
            MyCopyLocalAssembly = 1,
            MyDontCopyLocalAssembly = 2,

            EndMarker
        };

        /// <summary>
        /// Make sure the imageruntime is correctly returned.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestGetImageRuntimeVersion()
        {
            string imageRuntimeReportedByAsssembly = this.GetType().Assembly.ImageRuntimeVersion;
            string pathForAssembly = this.GetType().Assembly.Location;

            string inspectedRuntimeVersion = AssemblyInformation.GetRuntimeVersion(pathForAssembly);
            Assert.Equal(inspectedRuntimeVersion, imageRuntimeReportedByAsssembly);
        }

        /// <summary>
        /// Make sure the imageruntime is correctly returned.
        /// </summary>
        [Fact]
        public void TestGetImageRuntimeVersionBadPath()
        {
            string realFile = FileUtilities.GetTemporaryFile();
            try
            {
                string inspectedRuntimeVersion = AssemblyInformation.GetRuntimeVersion(realFile);
                Assert.Equal(inspectedRuntimeVersion, String.Empty);
            }
            finally
            {
                File.Delete(realFile);
            }
        }

        /// <summary>
        /// When specifying "EmbedInteropTypes" on a project targeting Fx higher than v4.0 -
        /// CopyLocal should be overridden to false
        /// </summary>
        [Fact]
        public void EmbedInteropTypes()
        {
            // This WriteLine is a hack.  On a slow machine, the Tasks unittest fails because remoting
            // times out the object used for remoting console writes.  Adding a write in the middle of
            // keeps remoting from timing out the object.
            Console.WriteLine("Performing Miscellaneous.Basic() test");

            // Construct a list of assembly files.
            ITaskItem[] assemblyFiles = new TaskItem[]
            {
                new TaskItem(s_myMissingAssemblyAbsPath)
            };

            assemblyFiles[0].SetMetadata("Private", "true");
            assemblyFiles[0].SetMetadata("EmbedInteropTypes", "true");

            // Construct a list of assembly names.
            ITaskItem[] assemblies = new TaskItem[]
            {
                new TaskItem("MyCopyLocalAssembly"),
                new TaskItem("MyDontCopyLocalAssembly")
            };

            assemblies[0].SetMetadata("Private", "true");
            assemblies[0].SetMetadata("EmbedInteropTypes", "true");
            assemblies[1].SetMetadata("Private", "false");
            assemblies[1].SetMetadata("EmbedInteropTypes", "true");

            // the matrix of TargetFrameworkVersion values we are testing
            string[] fxVersions =
            {
                "v2.0",
                "v3.0",
                "v3.5",
                "v4.0"
            };

            // expected ItemSpecs for corresponding assemblies
            string[] expectedItemSpec =
            {
                s_myMissingAssemblyRelPath,                 // MyMissingAssembly
                Path.Combine("MyProject", "MyCopyLocalAssembly.dll"),       // MyCopyLocalAssembly
                Path.Combine("MyProject", "MyDontCopyLocalAssembly.dll"),   // MyDontCopyLocalAssembly
            };

            // matrix of expected CopyLocal value per assembly per framework
            string[,] expectedCopyLocal =
            {
                // v2.0     v3.0     v3.5      v4.0
                { "true",  "true",  "true",  "false" },    // MyMissingAssembly
                { "true",  "true",  "true",  "false" },    // MyCopyLocalAssembly
                { "false", "false", "false", "false" }     // MyDontCopyLocalAssembly
            };

            int assembliesCount = (int)EmbedInteropTypes_Indices.EndMarker;

            // now let's verify our data structures are all set up correctly
            Assert.Equal(fxVersions.GetLength(0), expectedCopyLocal.GetLength(1)); // "fxVersions: test setup is incorrect"
            Assert.Equal(expectedItemSpec.Length, assembliesCount); // "expectedItemSpec: test setup is incorrect"
            Assert.Equal(expectedCopyLocal.GetLength(0), assembliesCount); // "expectedCopyLocal: test setup is incorrect"

            for (int i = 0; i < fxVersions.Length; i++)
            {
                // Create the engine.
                MockEngine engine = new MockEngine(_output);
                // Now, pass feed resolved primary references into ResolveAssemblyReference.
                ResolveAssemblyReference t = new ResolveAssemblyReference();
                t.BuildEngine = engine;
                t.Assemblies = assemblies;
                t.AssemblyFiles = assemblyFiles;
                t.SearchPaths = DefaultPaths;

                string fxVersion = fxVersions[i];
                t.TargetFrameworkDirectories = new string[] { String.Format(@"c:\WINNT\Microsoft.NET\Framework\{0}.MyVersion", fxVersion) };
                t.TargetFrameworkVersion = fxVersion;
                Execute(t);

                bool[] assembliesFound = new bool[assembliesCount];

                // Now, process primary items and make sure we have what we need.
                foreach (ITaskItem item in t.ResolvedFiles)
                {
                    string copyLocal = item.GetMetadata("CopyLocal");

                    int j;
                    for (j = 0; j < assembliesCount; j++)
                    {
                        if (item.ItemSpec.EndsWith(expectedItemSpec[j]))
                        {
                            assembliesFound[j] = true;
                            string assemblyName = Enum.GetName(typeof(EmbedInteropTypes_Indices), j);
                            copyLocal.ShouldBe(expectedCopyLocal[j, i], fxVersion + ": unexpected CopyValue for " + assemblyName, StringCompareShould.IgnoreCase);
                            break;
                        }
                    }

                    if (j == assembliesCount)
                    {
                        Assert.True(false, String.Format("{0}: A new resolved file called '{1}' was found. If this is intentional, then add unittests above.", fxVersion, item.ItemSpec));
                    }
                }

                for (int j = 0; j < assembliesCount; j++)
                {
                    string assemblyName = Enum.GetName(typeof(EmbedInteropTypes_Indices), j);
                    Assert.True(assembliesFound[j], fxVersion + ": Expected to find returned item " + assemblyName);
                }
            }
        }

        /// <summary>
        /// If items lists are empty, then this is a NOP not a failure.
        /// </summary>
        [Fact]
        public void NOPForEmptyItemLists()
        {
            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            // Now, pass feed resolved primary references into ResolveAssemblyReference.
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = engine;
            t.TargetFrameworkDirectories = new string[] { s_myVersion20Path };
            t.SearchPaths = DefaultPaths;

            bool succeeded = Execute(t);

            Assert.True(succeeded); // "Expected success."
        }

        /// <summary>
        /// If no related file extensions are input to RAR, .pdb and .xml should be used
        /// by default.
        /// </summary>
        [Fact]
        public void DefaultAllowedRelatedFileExtensionsAreUsed()
        {
            // This WriteLine is a hack.  On a slow machine, the Tasks unittest fails because remoting
            // times out the object used for remoting console writes.  Adding a write in the middle of
            // keeps remoting from timing out the object.
            Console.WriteLine("Performing Miscellaneous.DefaultRelatedFileExtensionsAreUsed() test");

            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            // Construct a list of assembly files.
            ITaskItem[] assemblies = new TaskItem[]
            {
                new TaskItem(s_assemblyFolder_SomeAssemblyDllPath)
            };

            // Now, pass feed resolved primary references into ResolveAssemblyReference.
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = engine;
            t.Assemblies = assemblies;
            t.TargetFrameworkDirectories = new string[] { s_myVersion20Path };
            t.SearchPaths = DefaultPaths;
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.EndsWith(Path.Combine("AssemblyFolder", "SomeAssembly.dll"), t.ResolvedFiles[0].ItemSpec);

            // Process the related files.
            Assert.Equal(3, t.RelatedFiles.Length);

            bool pdbFound = false;
            bool xmlFound = false;
            bool priFound = false;

            foreach (ITaskItem item in t.RelatedFiles)
            {
                if (item.ItemSpec.EndsWith(Path.Combine("AssemblyFolder", "SomeAssembly.pdb")))
                {
                    pdbFound = true;
                }
                if (item.ItemSpec.EndsWith(Path.Combine("AssemblyFolder", "SomeAssembly.xml")))
                {
                    xmlFound = true;
                }
                if (item.ItemSpec.EndsWith(Path.Combine("AssemblyFolder", "SomeAssembly.pri")))
                {
                    priFound = true;
                }
            }

            Assert.True(pdbFound && xmlFound && priFound); // "Expected to find .pdb, .xml, and .pri related files."
        }

        /// <summary>
        /// Externally resolved references do not get their related files identified by RAR. In the common
        /// nuget assets case, RAR cannot be the one to identify what to copy because RAR sees only the
        /// compile-time assets and not the runtime assets.
        /// </summary>
        [Theory]
        [InlineData(true)]
        [InlineData(false)]
        public void RelatedFilesAreNotFoundForExternallyResolvedReferences(bool findDependenciesOfExternallyResolvedReferences)
        {
            // This WriteLine is a hack.  On a slow machine, the Tasks unittest fails because remoting
            // times out the object used for remoting console writes.  Adding a write in the middle of
            // keeps remoting from timing out the object.
            Console.WriteLine("Performing Miscellaneous.DefaultRelatedFileExtensionsAreUsed() test");

            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            // Construct a list of assembly files.
            ITaskItem[] assemblies = new TaskItem[]
            {
                new TaskItem(s_assemblyFolder_SomeAssemblyDllPath)
            };

            assemblies[0].SetMetadata("ExternallyResolved", "true");

            // Now, pass feed resolved primary references into ResolveAssemblyReference.
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = engine;
            t.Assemblies = assemblies;
            t.TargetFrameworkDirectories = new string[] { s_myVersion20Path };
            t.SearchPaths = DefaultPaths;
            t.FindDependenciesOfExternallyResolvedReferences = findDependenciesOfExternallyResolvedReferences; // does not impact related file search
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.EndsWith(Path.Combine("AssemblyFolder", "SomeAssembly.dll"), t.ResolvedFiles[0].ItemSpec);
            Assert.Empty(t.RelatedFiles);
        }

        /// <summary>
        /// RAR should use any given related file extensions.
        /// </summary>
        [Fact]
        public void InputAllowedRelatedFileExtensionsAreUsed()
        {
            // This WriteLine is a hack.  On a slow machine, the Tasks unittest fails because remoting
            // times out the object used for remoting console writes.  Adding a write in the middle of
            // keeps remoting from timing out the object.
            Console.WriteLine("Performing Miscellaneous.InputRelatedFileExtensionsAreUsed() test");

            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            // Construct a list of assembly files.
            ITaskItem[] assemblies = new TaskItem[]
            {
                new TaskItem(s_assemblyFolder_SomeAssemblyDllPath)
            };

            // Now, pass feed resolved primary references into ResolveAssemblyReference.
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = engine;
            t.Assemblies = assemblies;
            t.TargetFrameworkDirectories = new string[] { s_myVersion20Path };
            t.SearchPaths = DefaultPaths;
            t.AllowedRelatedFileExtensions = new string[] { @".licenses", ".xml" }; //no .pdb or .config
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.EndsWith(Path.Combine("AssemblyFolder", "SomeAssembly.dll"), t.ResolvedFiles[0].ItemSpec);

            // Process the related files.
            Assert.Equal(2, t.RelatedFiles.Length);

            bool licensesFound = false;
            bool xmlFound = false;
            foreach (ITaskItem item in t.RelatedFiles)
            {
                if (item.ItemSpec.EndsWith(Path.Combine("AssemblyFolder", "SomeAssembly.licenses")))
                {
                    licensesFound = true;
                }
                if (item.ItemSpec.EndsWith(Path.Combine("AssemblyFolder", "SomeAssembly.xml")))
                {
                    xmlFound = true;
                }
            }

            Assert.True(licensesFound && xmlFound); // "Expected to find .licenses and .xml related files."
        }

        /// <summary>
        /// Simulate a CreateProject resolution. This is primarily for IO monitoring.
        /// </summary>
        private void SimulateCreateProjectAgainstWhidbeyInternal(string fxfolder)
        {
            // This WriteLine is a hack.  On a slow machine, the Tasks unittest fails because remoting
            // times out the object used for remoting console writes.  Adding a write in the middle of
            // keeps remoting from timing out the object.
            Console.WriteLine("Performing SimulateCreateProjectAgainstWhidbey() test");

            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            // Now, pass feed resolved primary references into ResolveAssemblyReference.
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = engine;
            t.Assemblies = new ITaskItem[] {
                new TaskItem("System"),
                new TaskItem("System.Deployment"),
                new TaskItem("System.Drawing"),
                new TaskItem("System.Windows.Forms"),
            };
            t.TargetFrameworkDirectories = new string[] { fxfolder };

            t.SearchPaths = new string[]
            {
                "{CandidateAssemblyFiles}",
                // Reference path
                "{HintPathFromItem}",
                @"{TargetFrameworkDirectory}",
                @"{Registry:Software\Microsoft\.NetFramework,v2.0,AssemblyFoldersEx}",
                "{AssemblyFolders}",
                "{GAC}",
                "{RawFileName}"
            };

            bool succeeded = Execute(t);

            Assert.True(succeeded); // "Expected success."
        }

        /// <summary>
        /// Test with a standard path.
        /// </summary>
        [Fact]
        public void SimulateCreateProjectAgainstWhidbey()
        {
            SimulateCreateProjectAgainstWhidbeyInternal(ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version45));
        }

        /// <summary>
        /// Test with a standard trailing-slash path.
        /// </summary>
        [Fact]
        public void SimulateCreateProjectAgainstWhidbeyWithTrailingSlash()
        {
            SimulateCreateProjectAgainstWhidbeyInternal(ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version45) + @"\");
        }

        /// <summary>
        /// Invalid candidate assembly files should not crash
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void Regress286699_InvalidCandidateAssemblyFiles()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("mscorlib") };
            t.CandidateAssemblyFiles = new string[] { "|" };

            bool retval = Execute(t);

            Assert.False(retval);

            // Should not crash.
        }

        /// <summary>
        /// Invalid assembly files should not crash
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void Regress286699_InvalidAssemblyFiles()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("mscorlib") };
            t.AssemblyFiles = new ITaskItem[] { new TaskItem("|") };

            bool retval = Execute(t);

            Assert.False(retval);

            // Should not crash.
        }

        /// <summary>
        /// Invalid assemblies param should not crash
        /// </summary>
        [Fact]
        public void Regress286699_InvalidAssembliesParameter()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("|!@#$%::") };

            bool retval = Execute(t);

            // I think this should return true
            Assert.True(retval);

            // Should not crash.
        }

        /// <summary>
        /// Target framework path with a newline should not crash.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void Regress286699_InvalidTargetFrameworkDirectory()
        {
            // This WriteLine is a hack.  On a slow machine, the Tasks unittest fails because remoting
            // times out the object used for remoting console writes.  Adding a write in the middle of
            // keeps remoting from timing out the object.
            Console.WriteLine("Performing Regress286699_InvalidTargetFrameworkDirectory() test");

            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.TargetFrameworkDirectories = new string[] { "\nc:\\blah\\v2.0.1234" };

            bool retval = Execute(t);

            Assert.False(retval);

            // Should not crash.
        }

        /// <summary>
        /// Invalid search path should not crash.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void Regress286699_InvalidSearchPath()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("mscorlib") };
            t.SearchPaths = new string[] { "|" };

            bool retval = Execute(t);

            Assert.False(retval);

            // Should not crash.
        }

        /// <summary>
        /// Invalid app.config path should not crash.
        /// </summary>
        [Fact]
        public void Regress286699_InvalidAppConfig()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("mscorlib") };
            t.AppConfigFile = "|";

            bool retval = Execute(t);

            Assert.False(retval);

            // Should not crash.
        }

        /// <summary>
        /// Make sure that nonexistent references are just eliminated.
        /// </summary>
        [Fact]
        public void NonExistentReference()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);
            t.Assemblies = new ITaskItem[] {
                new TaskItem("System.Xml"), new TaskItem("System.Nonexistent")
            };
            t.SearchPaths = new string[] { Path.GetDirectoryName(typeof(object).Module.FullyQualifiedName), "{AssemblyFolders}", "{HintPathFromItem}", "{RawFileName}" };
            t.Execute();
            Assert.Single(t.ResolvedFiles);
            Assert.Equal(0, String.Compare(ToolLocationHelper.GetPathToDotNetFrameworkFile("System.Xml.dll", TargetDotNetFrameworkVersion.Version45), t.ResolvedFiles[0].ItemSpec, StringComparison.OrdinalIgnoreCase));
        }

        /// <summary>
        /// Consider this situation.
        ///
        ///    Assembly A
        ///     References: B (a simple name)
        ///
        ///    Assembly B
        ///     Assembly Name: B, PKT=aaa, Version=bbb, Culture=ccc
        ///
        /// A does _not_ want to load B because it simple name B does not match the
        /// B's assembly name.
        ///
        /// Because of this, we want to be sure that if A asks for B (as a simple name)
        /// that we don't find a strongly named assembly.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void StrongWeakMismatchInDependency()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);
            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("DependsOnSimpleA")
            };

            t.SearchPaths = new string[] { s_myAppRootPath, @"c:\MyStronglyNamed", @"c:\MyWeaklyNamed" };
            Execute(t);
            Assert.Single(t.ResolvedDependencyFiles);
            Assert.Equal(@"c:\MyWeaklyNamed\A.dll", t.ResolvedDependencyFiles[0].ItemSpec);
        }

        /// <summary>
        /// When a reference is marked as externally resolved, it is supposed to have provided
        /// everything needed as primary references and dependencies are therefore not searched
        /// as an optimization. This is a contrived case of a dangling dependency off of an
        /// externally resolved reference, so that we can observe that the dependency search is
        /// not performed in a test.
        /// </summary>
        [Fact]
        public void DependenciesOfExternallyResolvedReferencesAreNotSearched()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);
            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("DependsOnSimpleA")
            };

            t.Assemblies[0].SetMetadata("ExternallyResolved", "true");

            t.SearchPaths = new string[] { s_myAppRootPath, @"c:\MyStronglyNamed", @"c:\MyWeaklyNamed" };
            Execute(t);
            Assert.Empty(t.ResolvedDependencyFiles);
        }

        /// <summary>
        /// If an Item has a HintPath and there is a {HintPathFromItem} in the SearchPaths
        /// property, then the task should be able to resolve an assembly there.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void UseSuppliedHintPath()
        {
            // This WriteLine is a hack.  On a slow machine, the Tasks unittest fails because remoting
            // times out the object used for remoting console writes.  Adding a write in the middle of
            // keeps remoting from timing out the object.
            Console.WriteLine("Performing UseSuppliedHintPath() test");

            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            ITaskItem i = new TaskItem("My.Assembly");

            i.SetMetadata("HintPath", @"C:\myassemblies\My.Assembly.dll");
            i.SetMetadata("Baggage", @"Carry-On");
            t.Assemblies = new ITaskItem[] { i };
            t.SearchPaths = DefaultPaths;
            Execute(t);
            Assert.Equal(@"C:\myassemblies\My.Assembly.dll", t.ResolvedFiles[0].ItemSpec);
            Assert.Single(t.ResolvedFiles);

            // All attributes, including HintPath, should be forwarded from input to output
            Assert.Equal(@"C:\myassemblies\My.Assembly.dll", t.ResolvedFiles[0].GetMetadata("HintPath"));
            Assert.Equal(@"Carry-On", t.ResolvedFiles[0].GetMetadata("Baggage"));
        }

        /// <summary>
        /// Regress this devices bug.
        /// If a simple name is provided then we need to accept the first simple file name match.
        /// Devices frameworks files are signed with a different PK so there should be no unification
        /// with normal fx files.
        /// </summary>
        [Fact]
        public void Regress200872()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("mscorlib") };
            t.SearchPaths = new string[]
            {
                s_myVersionPocket20Path,
                s_myVersion20Path
            };

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(Path.Combine(s_myVersionPocket20Path, "mscorlib.dll"), t.ResolvedFiles[0].ItemSpec);
        }

        /// <summary>
        /// Do the most basic AssemblyFoldersEx resolve.
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExBasic()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("MyGrid") };
            t.SearchPaths = DefaultPaths;

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(@"C:\MyComponents\MyGrid.dll", t.ResolvedFiles[0].ItemSpec);
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Microsoft\.NetFramework,v2.0,AssemblyFoldersEx}", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// Verify that higher alphabetical values for a component are chosen over lower alphabetic values of a component.
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExVerifyComponentFolderSorting()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("CustomComponent") };
            t.SearchPaths = DefaultPaths;

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(@"C:\MyComponentsB\CustomComponent.dll", t.ResolvedFiles[0].ItemSpec);
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Microsoft\.NetFramework,v2.0,AssemblyFoldersEx}", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// If the target framework version provided by the targets file doesn't begin
        /// with the letter "v", we should tolerate it and treat it as if it does.
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExTargetFrameworkVersionDoesNotBeginWithV()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("MyGrid") };
            t.SearchPaths = new string[] { @"{Registry:Software\Microsoft\.NetFramework,2.0,AssemblyFoldersEx}" };

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(@"C:\MyComponents\MyGrid.dll", t.ResolvedFiles[0].ItemSpec);
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Microsoft\.NetFramework,2.0,AssemblyFoldersEx}", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// The above but now requires us to make sure the processor architecture of what we are targeting matches what we are resolving.
        ///
        /// Target AMD64 and try to get an assembly out of the X86 directory.
        /// Expect it not to resolve and get a message on the console
        ///
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExProcessorArchDoesNotMatch()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine mockEngine = new MockEngine(_output);
            t.BuildEngine = mockEngine;

            t.Assemblies = new ITaskItem[] { new TaskItem("A") };
            t.SearchPaths = new string[] { @"{Registry:Software\Regress714052,v2.0.0,X86}" };
            t.TargetProcessorArchitecture = "AMD64";
            Execute(t);

            Assert.Empty(t.ResolvedFiles);
            string message = ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveAssemblyReference.TargetedProcessorArchitectureDoesNotMatch", @"C:\Regress714052\X86\A.dll", "X86", "AMD64");
            mockEngine.AssertLogContains(message);
        }

        /// <summary>
        /// Regress DevDiv Bugs 714052.
        ///
        /// The above but now requires us to make sure the processor architecture of what we are targeting matches what we are resolving.
        ///
        /// Target MSIL and get an assembly out of the X86 directory.
        ///
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExProcessorArchMSILX86()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine mockEngine = new MockEngine(_output);
            t.BuildEngine = mockEngine;

            t.Assemblies = new ITaskItem[] { new TaskItem("A") };
            t.SearchPaths = new string[] { @"{Registry:Software\Regress714052,v2.0.0,X86}" };
            t.TargetProcessorArchitecture = "MSIL";
            t.WarnOrErrorOnTargetArchitectureMismatch = "None";
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(0, mockEngine.Warnings);
            Assert.Equal(0, mockEngine.Errors);
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Regress714052,v2.0.0,X86}", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// Verify if there is a mismatch between what the project targets and the architecture of the resolved primary reference log a warning.
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        [Trait("Category", "mono-windows-failing")]
        public void VerifyProcessArchitectureMismatchWarning()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine mockEngine = new MockEngine(_output);
            t.BuildEngine = mockEngine;

            t.Assemblies = new ITaskItem[] { new TaskItem("A"), new TaskItem("B") };
            t.SearchPaths = new string[] { @"{Registry:Software\Regress714052,v2.0.0,X86}" };
            t.TargetProcessorArchitecture = "MSIL";
            t.WarnOrErrorOnTargetArchitectureMismatch = "Warning";
            Execute(t);

            Assert.Equal(2, t.ResolvedFiles.Length);
            Assert.Equal(2, mockEngine.Warnings);
            Assert.Equal(0, mockEngine.Errors);
            mockEngine.AssertLogContainsMessageFromResource(resourceDelegate, "ResolveAssemblyReference.MismatchBetweenTargetedAndReferencedArch", "MSIL", @"A", "X86");
            mockEngine.AssertLogContainsMessageFromResource(resourceDelegate, "ResolveAssemblyReference.MismatchBetweenTargetedAndReferencedArch", "MSIL", @"B", "X86");
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Regress714052,v2.0.0,X86}", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// Verify if there is a mismatch between what the project targets and the architecture of the resolved primary reference log a warning.
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        [Trait("Category", "mono-windows-failing")]
        public void VerifyProcessArchitectureMismatchWarningDefault()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine mockEngine = new MockEngine(_output);
            t.BuildEngine = mockEngine;

            t.Assemblies = new ITaskItem[] { new TaskItem("A"), new TaskItem("B") };
            t.SearchPaths = new string[] { @"{Registry:Software\Regress714052,v2.0.0,X86}" };
            t.TargetProcessorArchitecture = "MSIL";
            Execute(t);

            Assert.Equal(2, t.ResolvedFiles.Length);
            Assert.Equal(2, mockEngine.Warnings);
            Assert.Equal(0, mockEngine.Errors);
            mockEngine.AssertLogContainsMessageFromResource(resourceDelegate, "ResolveAssemblyReference.MismatchBetweenTargetedAndReferencedArch", "MSIL", @"A", "X86");
            mockEngine.AssertLogContainsMessageFromResource(resourceDelegate, "ResolveAssemblyReference.MismatchBetweenTargetedAndReferencedArch", "MSIL", @"B", "X86");
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Regress714052,v2.0.0,X86}", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// Verify if there is a mismatch between what the project targets and the architecture of the resolved primary reference log a error.
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        [Trait("Category", "mono-windows-failing")]
        public void VerifyProcessArchitectureMismatchError()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine mockEngine = new MockEngine(_output);
            t.BuildEngine = mockEngine;

            t.Assemblies = new ITaskItem[] { new TaskItem("A"), new TaskItem("B") };
            t.SearchPaths = new string[] { @"{Registry:Software\Regress714052,v2.0.0,X86}" };
            t.TargetProcessorArchitecture = "MSIL";
            t.WarnOrErrorOnTargetArchitectureMismatch = "Error";
            Execute(t);

            Assert.Equal(2, t.ResolvedFiles.Length);
            Assert.Equal(0, mockEngine.Warnings);
            Assert.Equal(2, mockEngine.Errors);
            mockEngine.AssertLogContainsMessageFromResource(resourceDelegate, "ResolveAssemblyReference.MismatchBetweenTargetedAndReferencedArch", "MSIL", @"A", "X86");
            mockEngine.AssertLogContainsMessageFromResource(resourceDelegate, "ResolveAssemblyReference.MismatchBetweenTargetedAndReferencedArch", "MSIL", @"B", "X86");
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Regress714052,v2.0.0,X86}", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// The above but now requires us to make sure the processor architecture of what we are targeting matches what we are resolving.
        ///
        /// Target None and get an assembly out of the X86 directory.
        ///
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExProcessorArchNoneX86()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine mockEngine = new MockEngine(_output);
            t.BuildEngine = mockEngine;

            t.Assemblies = new ITaskItem[] { new TaskItem("A") };
            t.SearchPaths = new string[] { @"{Registry:Software\Regress714052,v2.0.0,X86}" };
            t.TargetProcessorArchitecture = "NONE";
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Regress714052,v2.0.0,X86}", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// If we are targeting NONE and there are two assemblies with the same name then we want to pick the first one rather than look for an assembly which
        /// has a MSIL architecture or a NONE architecture. NONE means you do not care what architecture is picked.
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExProcessorArchNoneMix()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine mockEngine = new MockEngine(_output);
            t.BuildEngine = mockEngine;

            t.Assemblies = new ITaskItem[] { new TaskItem("A") };
            t.SearchPaths = new string[] { @"{Registry:Software\Regress714052,v2.0.0,MIX}" };
            t.TargetProcessorArchitecture = "NONE";
            t.WarnOrErrorOnTargetArchitectureMismatch = "Error";  // should not do anything
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(0, mockEngine.Warnings);
            Assert.Equal(0, mockEngine.Errors);
            Assert.Equal(@"C:\Regress714052\Mix\a.winmd", t.ResolvedFiles[0].ItemSpec, true);
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Regress714052,v2.0.0,Mix}", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// The above but now requires us to make sure the processor architecture of what we are targeting matches what we are resolving.
        ///
        /// Assume the folders are searched in the order  A and B.  A contains an x86 assembly and B contains an MSIL assembly.
        /// When targeting MSIL we want to return the MSIL assembly even if we find one in a previous folder first.
        /// Target MSIL and get an assembly out of the MSIL directory.
        ///
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExProcessorArchMSILLastFolder()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine mockEngine = new MockEngine(_output);
            t.BuildEngine = mockEngine;

            t.Assemblies = new ITaskItem[] { new TaskItem("A") };
            t.SearchPaths = new string[] { @"{Registry:Software\Regress714052,v2.0.0,AssemblyFoldersEx}" };
            t.TargetProcessorArchitecture = "MSIL";
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(@"C:\Regress714052\MSIL\A.dll", t.ResolvedFiles[0].ItemSpec);
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Regress714052,v2.0.0,AssemblyFoldersEX}", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// The above but now requires us to make sure the processor architecture of what we are targeting matches what we are resolving.
        ///
        /// Assume the folders are searched in the order  A and B.  A contains an x86 assembly and B contains an MSIL assembly.
        /// When targeting None we want to return the MSIL assembly even if we find one in a previous folder first.
        /// Target None and get an assembly out of the MSIL directory.
        ///
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExProcessorArchNoneLastFolder()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine mockEngine = new MockEngine(_output);
            t.BuildEngine = mockEngine;

            t.Assemblies = new ITaskItem[] { new TaskItem("A") };
            t.SearchPaths = new string[] { @"{Registry:Software\Regress714052,v2.0.0,AssemblyFoldersEx}" };
            t.TargetProcessorArchitecture = "None";
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(@"C:\Regress714052\MSIL\A.dll", t.ResolvedFiles[0].ItemSpec);
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Regress714052,v2.0.0,AssemblyFoldersEX}", StringCompareShould.IgnoreCase);
        }
        /// <summary>
        /// The above but now requires us to make sure the processor architecture of what we are targeting matches what we are resolving.
        ///
        /// Assume the folders are searched in the order  A and B.  A contains an x86 assembly and B contains an MSIL assembly.
        /// When targeting X86 we want to return the MSIL assembly even if we find one in a previous folder first.
        /// Target MSIL and get an assembly out of the MSIL directory.
        ///
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExProcessorArchX86FirstFolder()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine mockEngine = new MockEngine(_output);
            t.BuildEngine = mockEngine;

            t.Assemblies = new ITaskItem[] { new TaskItem("A") };
            t.SearchPaths = new string[] { @"{Registry:Software\Regress714052,v2.0.0,AssemblyFoldersEx}" };
            t.TargetProcessorArchitecture = "X86";
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(@"C:\Regress714052\X86\A.dll", t.ResolvedFiles[0].ItemSpec);
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Regress714052,v2.0.0,AssemblyFoldersEX}", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// The above but now requires us to make sure the processor architecture of what we are targeting matches what we are resolving.
        ///
        /// Target X86 and get an assembly out of the MSIL directory.
        ///
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExProcessorArchX86MSIL()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine mockEngine = new MockEngine(_output);
            t.BuildEngine = mockEngine;

            t.Assemblies = new ITaskItem[] { new TaskItem("A") };
            t.SearchPaths = new string[] { @"{Registry:Software\Regress714052,v2.0.0,MSIL}" };
            t.TargetProcessorArchitecture = "X86";
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Regress714052,v2.0.0,MSIL}", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// The above but now requires us to make sure the processor architecture of what we are targeting matches what we are resolving.
        ///
        /// Target X86 and get an assembly out of the None directory.
        ///
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExProcessorArchX86None()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine mockEngine = new MockEngine(_output);
            t.BuildEngine = mockEngine;

            t.Assemblies = new ITaskItem[] { new TaskItem("A") };
            t.SearchPaths = new string[] { @"{Registry:Software\Regress714052,v2.0.0,None}" };
            t.TargetProcessorArchitecture = "X86";
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Regress714052,v2.0.0,None}", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// The above but now requires us to make sure the processor architecture of what we are targeting matches what we are resolving.
        ///
        /// Target None and get an assembly out of the None directory.
        ///
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExProcessorArchNoneNone()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine mockEngine = new MockEngine(_output);
            t.BuildEngine = mockEngine;

            t.Assemblies = new ITaskItem[] { new TaskItem("A") };
            t.SearchPaths = new string[] { @"{Registry:Software\Regress714052,v2.0.0,None}" };
            t.TargetProcessorArchitecture = "None";
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Regress714052,v2.0.0,None}", StringCompareShould.IgnoreCase);
        }
        /// <summary>
        /// The above but now requires us to make sure the processor architecture of what we are targeting matches what we are resolving.
        ///
        /// Target MSIL and get an assembly out of the None directory.
        ///
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExProcessorArcMSILNone()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine mockEngine = new MockEngine(_output);
            t.BuildEngine = mockEngine;

            t.Assemblies = new ITaskItem[] { new TaskItem("A") };
            t.SearchPaths = new string[] { @"{Registry:Software\Regress714052,v2.0.0,None}" };
            t.TargetProcessorArchitecture = "MSIL";
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Regress714052,v2.0.0,None}", StringCompareShould.IgnoreCase);
        }
        /// <summary>
        /// The above but now requires us to make sure the processor architecture of what we are targeting matches what we are resolving.
        ///
        /// Target None and get an assembly out of the MSIL directory.
        ///
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExProcessorArchNoneMSIL()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine mockEngine = new MockEngine(_output);
            t.BuildEngine = mockEngine;

            t.Assemblies = new ITaskItem[] { new TaskItem("A") };
            t.SearchPaths = new string[] { @"{Registry:Software\Regress714052,v2.0.0,MSIL}" };
            t.TargetProcessorArchitecture = "None";
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Regress714052,v2.0.0,MSIL}", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// The above but now requires us to make sure the processor architecture of what we are targeting matches what we are resolving.
        ///
        /// Target MSIL and get an assembly out of the MSIL directory.
        ///
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExProcessorArchMSILMSIL()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine mockEngine = new MockEngine(_output);
            t.BuildEngine = mockEngine;

            t.Assemblies = new ITaskItem[] { new TaskItem("A") };
            t.SearchPaths = new string[] { @"{Registry:Software\Regress714052,v2.0.0,MSIL}" };
            t.TargetProcessorArchitecture = "MSIL";
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Regress714052,v2.0.0,MSIL}", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// The above but now requires us to make sure the processor architecture of what we are targeting matches what we are resolving.
        ///
        /// Target X86 and get an assembly out of the X86 directory.
        ///
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExProcessorArchMatches()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("A") };
            t.SearchPaths = new string[] { @"{Registry:Software\Regress714052,v2.0.0,X86}" };
            t.TargetProcessorArchitecture = "X86";
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(@"C:\Regress714052\X86\A.dll", t.ResolvedFiles[0].ItemSpec);
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Regress714052,v2.0.0,X86}", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// If the target framework version specified in the registry search path
        /// provided by the targets file has some bogus value, we should just ignore it.
        ///
        /// This means if there are remaining search paths to inspect, we should
        /// carry on and inspect those.
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExTargetFrameworkVersionBogusValue()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            ITaskItem assemblyToResolve = new TaskItem("MyGrid");
            assemblyToResolve.SetMetadata("HintPath", @"C:\MyComponents\MyGrid.dll");
            t.Assemblies = new ITaskItem[] { assemblyToResolve };
            t.SearchPaths = new string[] { @"{Registry:Software\Microsoft\.NetFramework,x.y.z,AssemblyFoldersEx}", "{HintPathFromItem}" };

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal("{HintPathFromItem}", t.ResolvedFiles[0].GetMetadata("ResolvedFrom")); //                 "Assembly should have been resolved from HintPathFromItem!"
        }

        /// <summary>
        /// Tolerate keys like v2.0.x86chk.
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void Regress357227_AssemblyFoldersExAgainstRawDrop()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("MyRawDropControl") };
            t.SearchPaths = DefaultPaths;

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(@"C:\MyRawDropControls\MyRawDropControl.dll", t.ResolvedFiles[0].ItemSpec);
            t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(@"{Registry:Software\Microsoft\.NetFramework,v2.0,AssemblyFoldersEx}", StringCompareShould.IgnoreCase);
        }

        /// <summary>
        /// Matches that exist only in the HKLM hive.
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExHKLM()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("MyHKLMControl") };
            t.SearchPaths = DefaultPaths;

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(@"C:\MyComponents\HKLM Components\MyHKLMControl.dll", t.ResolvedFiles[0].ItemSpec);
        }

        /// <summary>
        /// Matches that exist in both HKLM and HKCU should favor HKCU
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExHKCUTrumpsHKLM()
        {
            // This WriteLine is a hack.  On a slow machine, the Tasks unittest fails because remoting
            // times out the object used for remoting console writes.  Adding a write in the middle of
            // keeps remoting from timing out the object.
            Console.WriteLine("Performing AssemblyFoldersExHKCUTrumpsHKLM() test");

            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("MyHKLMandHKCUControl") };
            t.SearchPaths = DefaultPaths;

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(@"C:\MyComponents\HKCU Components\MyHKLMandHKCUControl.dll", t.ResolvedFiles[0].ItemSpec);
        }

        /// <summary>
        /// When matches that have v3.0 (future) and v2.0 (current) versions, the 2.0 version wins.
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExFutureTargetNDPVersionsDontMatch()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("MyControlWithFutureTargetNDPVersion") };
            t.SearchPaths = DefaultPaths;

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(Path.Combine(s_myComponentsV20Path, "MyControlWithFutureTargetNDPVersion.dll"), t.ResolvedFiles[0].ItemSpec);
        }

        /// <summary>
        /// If there is no v2.0 (current target NDP) match, then v1.0 should match.
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExMatchBackVersion()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("MyNDP1Control") };
            t.SearchPaths = DefaultPaths;

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(Path.Combine(s_myComponentsV10Path, "MyNDP1Control.dll"), t.ResolvedFiles[0].ItemSpec);
        }

        /// <summary>
        /// If there is a 2.0 and a 1.0 then match 2.0.
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExCurrentTargetVersionTrumpsPastTargetVersion()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("MyControlWithPastTargetNDPVersion") };
            t.SearchPaths = DefaultPaths;

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(Path.Combine(s_myComponentsV20Path, "MyControlWithPastTargetNDPVersion.dll"), t.ResolvedFiles[0].ItemSpec);
        }

        /// <summary>
        /// If a control has a service pack then that wins over the control itself
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExServicePackTrumpsBaseVersion()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("MyControlWithServicePack") };
            t.SearchPaths = DefaultPaths;

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(@"C:\MyComponentServicePack2\MyControlWithServicePack.dll", t.ResolvedFiles[0].ItemSpec);
        }

        /// <summary>
        /// Conditions (OSVersion/Platform) can be passed in SearchPaths to filter the result.
        /// Test MaxOSVersion condition
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExConditionFilterMaxOS()
        {
            // This WriteLine is a hack.  On a slow machine, the Tasks unittest fails because remoting
            // times out the object used for remoting console writes.  Adding a write in the middle of
            // keeps remoting from timing out the object.
            Console.WriteLine("Performing AssemblyFoldersExConditionFilterMaxOS() test");

            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("MyDeviceControlAssembly") };
            t.SearchPaths = new string[]
            {
                "{RawFileName}",
                "{CandidateAssemblyFiles}",
                s_myProjectPath,
                s_myVersion20Path,
                @"{Registry:Software\Microsoft\.NETCompactFramework,v2.0,PocketPC\AssemblyFoldersEx,OSVersion=4.0.0:Platform=3C41C503-53EF-4c2a-8DD4-A8217CAD115E}",
                "{AssemblyFolders}",
                "{HintPathFromItem}"
            };

            SetupAssemblyFoldersExTestConditionRegistryKey();

            try
            {
                Execute(t);
            }
            finally
            {
                RemoveAssemblyFoldersExTestConditionRegistryKey();
            }

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(@"C:\V1ControlSP1\MyDeviceControlAssembly.dll", t.ResolvedFiles[0].ItemSpec);
        }

        /// <summary>
        /// Conditions (OSVersion/Platform) can be passed in SearchPaths to filter the result.
        /// Test MinOSVersion condition
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExConditionFilterMinOS()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("MyDeviceControlAssembly") };
            t.SearchPaths = new string[]
            {
                "{RawFileName}",
                "{CandidateAssemblyFiles}",
                s_myProjectPath,
                s_myVersion20Path,
                @"{Registry:Software\Microsoft\.NETCompactFramework,v2.0,PocketPC\AssemblyFoldersEx,OSVersion=5.1.0:Platform=3C41C503-53EF-4c2a-8DD4-A8217CAD115E}",
                "{AssemblyFolders}",
                "{HintPathFromItem}"
            };

            SetupAssemblyFoldersExTestConditionRegistryKey();

            try
            {
                Execute(t);
            }
            finally
            {
                RemoveAssemblyFoldersExTestConditionRegistryKey();
            }

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(@"C:\V1Control\MyDeviceControlAssembly.dll", t.ResolvedFiles[0].ItemSpec);
        }

#if FEATURE_WIN32_REGISTRY
        [Fact]
        public void GatherVersions10DotNet()
        {
            List<ExtensionFoldersRegistryKey> returnedVersions = AssemblyFoldersEx.GatherVersionStrings("v1.0", s_assemblyFolderExTestVersions);

            Assert.NotNull(returnedVersions);
            Assert.Equal(3, returnedVersions.Count);
            Assert.Equal("v1.0", (string)returnedVersions[0].RegistryKey);
            Assert.Equal("v1", (string)returnedVersions[1].RegistryKey);
            Assert.Equal("v00001.0", (string)returnedVersions[2].RegistryKey);
        }

        [Fact]
        public void GatherVersions20DotNet()
        {
            List<ExtensionFoldersRegistryKey> returnedVersions = AssemblyFoldersEx.GatherVersionStrings("v2.0", s_assemblyFolderExTestVersions);

            Assert.NotNull(returnedVersions);
            Assert.Equal(4, returnedVersions.Count);
            Assert.Equal("v2.0.50727", (string)returnedVersions[0].RegistryKey);
            Assert.Equal("v1.0", (string)returnedVersions[1].RegistryKey);
            Assert.Equal("v1", (string)returnedVersions[2].RegistryKey);
            Assert.Equal("v00001.0", (string)returnedVersions[3].RegistryKey);
        }

        [Fact]
        public void GatherVersions30DotNet()
        {
            List<ExtensionFoldersRegistryKey> returnedVersions = AssemblyFoldersEx.GatherVersionStrings("v3.0", s_assemblyFolderExTestVersions);

            Assert.NotNull(returnedVersions);
            Assert.Equal(7, returnedVersions.Count);

            Assert.Equal("v3.0", (string)returnedVersions[0].RegistryKey);
            Assert.Equal("v2.0.50727", (string)returnedVersions[1].RegistryKey);
            Assert.Equal("v1.0", (string)returnedVersions[2].RegistryKey);
            Assert.Equal("v1", (string)returnedVersions[3].RegistryKey);
            Assert.Equal("v00001.0", (string)returnedVersions[4].RegistryKey);
            Assert.Equal("v3.0SP1", (string)returnedVersions[5].RegistryKey);
            Assert.Equal("v3.0 BAZ", (string)returnedVersions[6].RegistryKey);
        }

        [Fact]
        public void GatherVersionsVDotNet()
        {
            List<ExtensionFoldersRegistryKey> returnedVersions = AssemblyFoldersEx.GatherVersionStrings("v", s_assemblyFolderExTestVersions);

            Assert.NotNull(returnedVersions);
            Assert.Equal(27, returnedVersions.Count);

            Assert.Equal("v5.0", (string)returnedVersions[0].RegistryKey);
            Assert.Equal("v5", (string)returnedVersions[1].RegistryKey);
            Assert.Equal("v4.0001.0", (string)returnedVersions[2].RegistryKey);
            Assert.Equal("v4.1", (string)returnedVersions[3].RegistryKey);
            Assert.Equal("v172.16.31.10", (string)returnedVersions[4].RegistryKey);
            Assert.Equal("v4.0.255", (string)returnedVersions[5].RegistryKey);
            Assert.Equal("v4.0.0000", (string)returnedVersions[6].RegistryKey);
            Assert.Equal("v4.0.9999", (string)returnedVersions[7].RegistryKey);
            Assert.Equal("v4.0.2116.87", (string)returnedVersions[8].RegistryKey);
            Assert.Equal("v4.0.2116", (string)returnedVersions[9].RegistryKey);
            Assert.Equal("v4.0", (string)returnedVersions[10].RegistryKey);
            Assert.Equal("v3.5", (string)returnedVersions[11].RegistryKey);
            Assert.Equal("v3.0", (string)returnedVersions[12].RegistryKey);
            Assert.Equal("v2.0.50727", (string)returnedVersions[13].RegistryKey);
            Assert.Equal("v1.0", (string)returnedVersions[14].RegistryKey);
            Assert.Equal("v1", (string)returnedVersions[15].RegistryKey);
            Assert.Equal("v00001.0", (string)returnedVersions[16].RegistryKey);
            Assert.Equal("v3.0SP1", (string)returnedVersions[17].RegistryKey);
            Assert.Equal("v3.0 BAZ", (string)returnedVersions[18].RegistryKey);
            Assert.Equal("v3.5.0.x86chk", (string)returnedVersions[19].RegistryKey);
            Assert.Equal("v3.5.1.x86chk", (string)returnedVersions[20].RegistryKey);
            Assert.Equal("v3.5.256.x86chk", (string)returnedVersions[21].RegistryKey);
            Assert.Equal("v", (string)returnedVersions[22].RegistryKey);
            Assert.Equal("V3.5.0.0.0", (string)returnedVersions[23].RegistryKey);
            Assert.Equal("V3..", (string)returnedVersions[24].RegistryKey);
            Assert.Equal("V-1", (string)returnedVersions[25].RegistryKey);
            Assert.Equal("v9999999999999999", (string)returnedVersions[26].RegistryKey, true);
        }

        [Fact]
        public void GatherVersions35DotNet()
        {
            List<ExtensionFoldersRegistryKey> returnedVersions = AssemblyFoldersEx.GatherVersionStrings("v3.5", s_assemblyFolderExTestVersions);

            Assert.NotNull(returnedVersions);
            Assert.Equal(10, returnedVersions.Count);
            Assert.Equal("v3.5", (string)returnedVersions[0].RegistryKey);
            Assert.Equal("v3.0", (string)returnedVersions[1].RegistryKey);
            Assert.Equal("v2.0.50727", (string)returnedVersions[2].RegistryKey);
            Assert.Equal("v1.0", (string)returnedVersions[3].RegistryKey);
            Assert.Equal("v1", (string)returnedVersions[4].RegistryKey);
            Assert.Equal("v00001.0", (string)returnedVersions[5].RegistryKey);
            Assert.Equal("v3.5.0.x86chk", (string)returnedVersions[6].RegistryKey);
            Assert.Equal("v3.5.1.x86chk", (string)returnedVersions[7].RegistryKey);
            Assert.Equal("v3.5.256.x86chk", (string)returnedVersions[8].RegistryKey);
            Assert.Equal("V3.5.0.0.0", (string)returnedVersions[9].RegistryKey);
        }

        [Fact]
        public void GatherVersions40DotNet()
        {
            List<ExtensionFoldersRegistryKey> returnedVersions = AssemblyFoldersEx.GatherVersionStrings("v4.0", s_assemblyFolderExTestVersions);

            Assert.NotNull(returnedVersions);
            Assert.Equal(10, returnedVersions.Count);
            Assert.Equal("v4.0.9999", (string)returnedVersions[0].RegistryKey);
            Assert.Equal("v4.0.2116.87", (string)returnedVersions[1].RegistryKey);
            Assert.Equal("v4.0.2116", (string)returnedVersions[2].RegistryKey);
            Assert.Equal("v4.0", (string)returnedVersions[3].RegistryKey);
            Assert.Equal("v3.5", (string)returnedVersions[4].RegistryKey);
            Assert.Equal("v3.0", (string)returnedVersions[5].RegistryKey);
            Assert.Equal("v2.0.50727", (string)returnedVersions[6].RegistryKey);
            Assert.Equal("v1.0", (string)returnedVersions[7].RegistryKey);
            Assert.Equal("v1", (string)returnedVersions[8].RegistryKey);
            Assert.Equal("v00001.0", (string)returnedVersions[9].RegistryKey);
        }

        [Fact]
        public void GatherVersions400DotNet()
        {
            List<ExtensionFoldersRegistryKey> returnedVersions = AssemblyFoldersEx.GatherVersionStrings("v4.0.0", s_assemblyFolderExTestVersions);

            Assert.NotNull(returnedVersions);
            Assert.Equal(11, returnedVersions.Count);
            Assert.Equal("v4.0.0000", (string)returnedVersions[0].RegistryKey);
            Assert.Equal("v4.0.9999", (string)returnedVersions[1].RegistryKey);
            Assert.Equal("v4.0.2116.87", (string)returnedVersions[2].RegistryKey);
            Assert.Equal("v4.0.2116", (string)returnedVersions[3].RegistryKey);
            Assert.Equal("v4.0", (string)returnedVersions[4].RegistryKey);
            Assert.Equal("v3.5", (string)returnedVersions[5].RegistryKey);
            Assert.Equal("v3.0", (string)returnedVersions[6].RegistryKey);
            Assert.Equal("v2.0.50727", (string)returnedVersions[7].RegistryKey);
            Assert.Equal("v1.0", (string)returnedVersions[8].RegistryKey);
            Assert.Equal("v1", (string)returnedVersions[9].RegistryKey);
            Assert.Equal("v00001.0", (string)returnedVersions[10].RegistryKey);
        }

        [Fact]
        public void GatherVersions41DotNet()
        {
            List<ExtensionFoldersRegistryKey> returnedVersions = AssemblyFoldersEx.GatherVersionStrings("v4.1", s_assemblyFolderExTestVersions);

            Assert.NotNull(returnedVersions);
            Assert.Equal(14, returnedVersions.Count);

            Assert.Equal("v4.1", (string)returnedVersions[0].RegistryKey);
            Assert.Equal("v172.16.31.10", (string)returnedVersions[1].RegistryKey);
            Assert.Equal("v4.0.255", (string)returnedVersions[2].RegistryKey);
            Assert.Equal("v4.0.0000", (string)returnedVersions[3].RegistryKey);
            Assert.Equal("v4.0.9999", (string)returnedVersions[4].RegistryKey);
            Assert.Equal("v4.0.2116.87", (string)returnedVersions[5].RegistryKey);
            Assert.Equal("v4.0.2116", (string)returnedVersions[6].RegistryKey);
            Assert.Equal("v4.0", (string)returnedVersions[7].RegistryKey);
            Assert.Equal("v3.5", (string)returnedVersions[8].RegistryKey);
            Assert.Equal("v3.0", (string)returnedVersions[9].RegistryKey);
            Assert.Equal("v2.0.50727", (string)returnedVersions[10].RegistryKey);
            Assert.Equal("v1.0", (string)returnedVersions[11].RegistryKey);
            Assert.Equal("v1", (string)returnedVersions[12].RegistryKey);
            Assert.Equal("v00001.0", (string)returnedVersions[13].RegistryKey);
        }

        [Fact]
        public void GatherVersions410DotNet()
        {
            List<ExtensionFoldersRegistryKey> returnedVersions = AssemblyFoldersEx.GatherVersionStrings("v4.1.0", s_assemblyFolderExTestVersions);

            Assert.NotNull(returnedVersions);
            Assert.Equal(15, returnedVersions.Count);

            Assert.Equal("v4.0001.0", (string)returnedVersions[0].RegistryKey);
            Assert.Equal("v4.1", (string)returnedVersions[1].RegistryKey);
            Assert.Equal("v172.16.31.10", (string)returnedVersions[2].RegistryKey);
            Assert.Equal("v4.0.255", (string)returnedVersions[3].RegistryKey);
            Assert.Equal("v4.0.0000", (string)returnedVersions[4].RegistryKey);
            Assert.Equal("v4.0.9999", (string)returnedVersions[5].RegistryKey);
            Assert.Equal("v4.0.2116.87", (string)returnedVersions[6].RegistryKey);
            Assert.Equal("v4.0.2116", (string)returnedVersions[7].RegistryKey);
            Assert.Equal("v4.0", (string)returnedVersions[8].RegistryKey);
            Assert.Equal("v3.5", (string)returnedVersions[9].RegistryKey);
            Assert.Equal("v3.0", (string)returnedVersions[10].RegistryKey);
            Assert.Equal("v2.0.50727", (string)returnedVersions[11].RegistryKey);
            Assert.Equal("v1.0", (string)returnedVersions[12].RegistryKey);
            Assert.Equal("v1", (string)returnedVersions[13].RegistryKey);
            Assert.Equal("v00001.0", (string)returnedVersions[14].RegistryKey);
        }

        [Fact]
        public void GatherVersions40255DotNet()
        {
            List<ExtensionFoldersRegistryKey> returnedVersions = AssemblyFoldersEx.GatherVersionStrings("v4.0.255", s_assemblyFolderExTestVersions);

            Assert.NotNull(returnedVersions);
            Assert.Equal(13, returnedVersions.Count);
            Assert.Equal("v4.0.255.87", (string)returnedVersions[0].RegistryKey);
            Assert.Equal("v4.0.255", (string)returnedVersions[1].RegistryKey);
            Assert.Equal("v4.0.0000", (string)returnedVersions[2].RegistryKey);
            Assert.Equal("v4.0.9999", (string)returnedVersions[3].RegistryKey);
            Assert.Equal("v4.0.2116.87", (string)returnedVersions[4].RegistryKey);
            Assert.Equal("v4.0.2116", (string)returnedVersions[5].RegistryKey);
            Assert.Equal("v4.0", (string)returnedVersions[6].RegistryKey);
            Assert.Equal("v3.5", (string)returnedVersions[7].RegistryKey);
            Assert.Equal("v3.0", (string)returnedVersions[8].RegistryKey);
            Assert.Equal("v2.0.50727", (string)returnedVersions[9].RegistryKey);
            Assert.Equal("v1.0", (string)returnedVersions[10].RegistryKey);
            Assert.Equal("v1", (string)returnedVersions[11].RegistryKey);
            Assert.Equal("v00001.0", (string)returnedVersions[12].RegistryKey);
        }

        [Fact]
        public void GatherVersions5DotNet()
        {
            List<ExtensionFoldersRegistryKey> returnedVersions = AssemblyFoldersEx.GatherVersionStrings("v5.0", s_assemblyFolderExTestVersions);

            Assert.NotNull(returnedVersions);
            Assert.Equal(17, returnedVersions.Count);

            Assert.Equal("v5.0", (string)returnedVersions[0].RegistryKey);
            Assert.Equal("v5", (string)returnedVersions[1].RegistryKey);
            Assert.Equal("v4.0001.0", (string)returnedVersions[2].RegistryKey);
            Assert.Equal("v4.1", (string)returnedVersions[3].RegistryKey);
            Assert.Equal("v4.0.255.87", (string)returnedVersions[4].RegistryKey);
            Assert.Equal("v4.0.255", (string)returnedVersions[5].RegistryKey);
            Assert.Equal("v4.0.0000", (string)returnedVersions[6].RegistryKey);
            Assert.Equal("v4.0.9999", (string)returnedVersions[7].RegistryKey);
            Assert.Equal("v4.0.2116.87", (string)returnedVersions[8].RegistryKey);
            Assert.Equal("v4.0.2116", (string)returnedVersions[9].RegistryKey);
            Assert.Equal("v4.0", (string)returnedVersions[10].RegistryKey);
            Assert.Equal("v3.5", (string)returnedVersions[11].RegistryKey);
            Assert.Equal("v3.0", (string)returnedVersions[12].RegistryKey);
            Assert.Equal("v2.0.50727", (string)returnedVersions[13].RegistryKey);
            Assert.Equal("v1.0", (string)returnedVersions[14].RegistryKey);
            Assert.Equal("v1", (string)returnedVersions[15].RegistryKey);
            Assert.Equal("v00001.0", (string)returnedVersions[16].RegistryKey);
        }

        [Fact]
        public void GatherVersionsv5DotNet()
        {
            List<ExtensionFoldersRegistryKey> returnedVersions = AssemblyFoldersEx.GatherVersionStrings("v5", s_assemblyFolderExTestVersions);

            Assert.NotNull(returnedVersions);
            Assert.Equal(17, returnedVersions.Count);

            Assert.Equal("v5.0", (string)returnedVersions[0].RegistryKey);
            Assert.Equal("v5", (string)returnedVersions[1].RegistryKey);
            Assert.Equal("v4.0001.0", (string)returnedVersions[2].RegistryKey);
            Assert.Equal("v4.1", (string)returnedVersions[3].RegistryKey);
            Assert.Equal("v172.16.31.10", (string)returnedVersions[4].RegistryKey);
            Assert.Equal("v4.0.255", (string)returnedVersions[5].RegistryKey);
            Assert.Equal("v4.0.0000", (string)returnedVersions[6].RegistryKey);
            Assert.Equal("v4.0.9999", (string)returnedVersions[7].RegistryKey);
            Assert.Equal("v4.0.2116.87", (string)returnedVersions[8].RegistryKey);
            Assert.Equal("v4.0.2116", (string)returnedVersions[9].RegistryKey);
            Assert.Equal("v4.0", (string)returnedVersions[10].RegistryKey);
            Assert.Equal("v3.5", (string)returnedVersions[11].RegistryKey);
            Assert.Equal("v3.0", (string)returnedVersions[12].RegistryKey);
            Assert.Equal("v2.0.50727", (string)returnedVersions[13].RegistryKey);
            Assert.Equal("v1.0", (string)returnedVersions[14].RegistryKey);
            Assert.Equal("v1", (string)returnedVersions[15].RegistryKey);
            Assert.Equal("v00001.0", (string)returnedVersions[16].RegistryKey);
        }

        [Fact]
        public void GatherVersions35x86chkDotNet()
        {
            List<ExtensionFoldersRegistryKey> returnedVersions = AssemblyFoldersEx.GatherVersionStrings("v3.5.0.x86chk", s_assemblyFolderExTestVersions);

            Assert.NotNull(returnedVersions);
            Assert.Single(returnedVersions);

            Assert.Equal("v3.5.0.x86chk", (string)returnedVersions[0].RegistryKey);
        }
#endif

        /// <summary>
        /// Conditions (OSVersion/Platform) can be passed in SearchPaths to filter the result.
        /// Test Platform condition
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]
        public void AssemblyFoldersExConditionFilterPlatform()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("MyDeviceControlAssembly") };
            t.SearchPaths = new string[]
            {
                "{RawFileName}",
                "{CandidateAssemblyFiles}",
                s_myProjectPath,
                s_myVersion20Path,
                @"{Registry:Software\Microsoft\.NETCompactFramework,v2.0,PocketPC\AssemblyFoldersEx,Platform=3C41C503-X-4c2a-8DD4-A8217CAD115E}",
                "{AssemblyFolders}",
                "{HintPathFromItem}"
            };

            SetupAssemblyFoldersExTestConditionRegistryKey();

            try
            {
                Execute(t);
            }
            finally
            {
                RemoveAssemblyFoldersExTestConditionRegistryKey();
            }

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(@"C:\V1Control\MyDeviceControlAssembly.dll", t.ResolvedFiles[0].ItemSpec);
        }

        private void SetupAssemblyFoldersExTestConditionRegistryKey()
        {
            // Setup the following registry keys:
            //  HKCU\SOFTWARE\Microsoft\.NETCompactFramework\v2.0.3600\PocketPC\AssemblyFoldersEx\AFETestDeviceControl
            //          @c:\V1Control
            //          @MinOSVersion=5.0.0
            //  HKCU\SOFTWARE\Microsoft\.NETCompactFramework\v2.0.3600\PocketPC\AssemblyFoldersEx\AFETestDeviceControl\1234
            //          @c:\V1ControlSP1
            //          @MinOSVersion=4.0.0
            //          @MaxOSVersion=4.1.0
            //          @Platform=4118C335-430C-497f-BE48-11C3316B135E;3C41C503-53EF-4c2a-8DD4-A8217CAD115E

            RegistryKey baseKey = Registry.CurrentUser;
            RegistryKey folderKey = baseKey.CreateSubKey(@"SOFTWARE\Microsoft\.NETCompactFramework\v2.0.3600\PocketPC\AssemblyFoldersEx\AFETestDeviceControl");
            folderKey.SetValue("", @"C:\V1Control");
            folderKey.SetValue("MinOSVersion", "5.0.0");

            RegistryKey servicePackKey = baseKey.CreateSubKey(@"SOFTWARE\Microsoft\.NETCompactFramework\v2.0.3600\PocketPC\AssemblyFoldersEx\AFETestDeviceControl\1234");
            servicePackKey.SetValue("", @"C:\V1ControlSP1");
            servicePackKey.SetValue("MinOSVersion", "4.0.0");

            servicePackKey.SetValue("MaxOSVersion", "4.1.0");
            servicePackKey.SetValue("Platform", "4118C335-430C-497f-BE48-11C3316B135E;3C41C503-53EF-4c2a-8DD4-A8217CAD115E");
        }

        private void RemoveAssemblyFoldersExTestConditionRegistryKey()
        {
            RegistryKey baseKey = Registry.CurrentUser;
            try
            {
                baseKey.DeleteSubKeyTree(@"SOFTWARE\Microsoft\.NETCompactFramework\v2.0.3600\PocketPC\AssemblyFoldersEx\AFETestDeviceControl");
            }
            catch (Exception)
            {
            }
        }

        /// <summary>
        /// CandidateAssemblyFiles are extra files passed in through the CandidateAssemblyFiles
        /// that should be considered for matching when search paths contains {CandidateAssemblyFiles}
        /// </summary>
        [Fact]
        public void CandidateAssemblyFiles()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("System.XML") };
            t.SearchPaths = new string[] { "{CandidateAssemblyFiles}" };
            t.CandidateAssemblyFiles = new string[] { Path.Combine(s_myVersion20Path, "System.Xml.dll") };

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(Path.Combine(s_myVersion20Path, "System.Xml.dll"), t.ResolvedFiles[0].ItemSpec);
        }

        /// <summary>
        /// Make sure three part version numbers put on the required target framework do not cause a problem.
        /// </summary>
        [Fact]
        public void ThreePartVersionNumberRequiredFrameworkHigherThanTargetFramework()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);
            TaskItem item = new TaskItem("System.XML");
            item.SetMetadata("RequiredTargetFramework", "v4.0.255");
            t.Assemblies = new ITaskItem[] { item };
            t.SearchPaths = new string[] { "{CandidateAssemblyFiles}" };
            t.CandidateAssemblyFiles = new string[] { Path.Combine(s_myVersion20Path, "System.Xml.dll") };
            t.TargetFrameworkVersion = "v4.0";
            Execute(t);

            Assert.Empty(t.ResolvedFiles);
        }

        /// <summary>
        /// Make sure three part version numbers put on the required target framework do not cause a problem.
        /// </summary>
        [Fact]
        public void ThreePartVersionNumberRequiredFrameworkLowerThanTargetFramework()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);
            TaskItem item = new TaskItem("System.XML");
            item.SetMetadata("RequiredTargetFramework", "v4.0.255");
            t.Assemblies = new ITaskItem[] { item };
            t.SearchPaths = new string[] { "{CandidateAssemblyFiles}" };
            t.CandidateAssemblyFiles = new string[] { Path.Combine(s_myVersion20Path, "System.Xml.dll") };
            t.TargetFrameworkVersion = "v4.0.256";
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(Path.Combine(s_myVersion20Path, "System.Xml.dll"), t.ResolvedFiles[0].ItemSpec);
        }

        /// <summary>
        /// Try a candidate assembly file that has an extension but no base name.
        /// </summary>
        [Fact]
        public void Regress242970()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine engine = new MockEngine(_output);
            t.BuildEngine = engine;

            t.Assemblies = new ITaskItem[] { new TaskItem("System.XML") };
            t.SearchPaths = new string[] { "{CandidateAssemblyFiles}" };
            t.CandidateAssemblyFiles = new string[]
            {
                @"NonUI\testDirectoryRoot\.hiddenfile",
                @"NonUI\testDirectoryRoot\.dll",
                Path.Combine(s_myVersion20Path, "System.Xml.dll")
            };

            bool succeeded = Execute(t);

            Assert.True(succeeded);
            Assert.Single(t.ResolvedFiles);
            Assert.Equal(Path.Combine(s_myVersion20Path, "System.Xml.dll"), t.ResolvedFiles[0].ItemSpec);

            // For {CandidateAssemblyFiles} we don't even want to see a comment logged for files with non-standard extensions.
            // This is because {CandidateAssemblyFiles} is very likely to contain non-assemblies and its best not to clutter
            // up the log.
            engine.AssertLogDoesntContain
            (
                String.Format(".hiddenfile")
            );

            // ...but we do want to see a log entry for standard extensions, even if the base file name is empty.
            engine.AssertLogContains
            (
                String.Format(@"NonUI\testDirectoryRoot\.dll")
            );
        }

        /// <summary>
        /// If a file name is passed in through the Assemblies parameter and the search paths contains {RawFileName}
        /// then try to resolve directly to that file name.
        /// </summary>
        [Fact]
        public void RawFileName()
        {
            // This WriteLine is a hack.  On a slow machine, the Tasks unittest fails because remoting
            // times out the object used for remoting console writes.  Adding a write in the middle of
            // keeps remoting from timing out the object.
            Console.WriteLine("Performing RawFileName() test");

            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem(Path.Combine(s_myVersion20Path, "System.Xml.dll")) };
            t.SearchPaths = new string[]
            {
                "{RawFileName}",
                "{CandidateAssemblyFiles}",
                s_myProjectPath,
                "{TargetFrameworkDirectory}",
                @"{Registry:Software\Microsoft\.NetFramework,v2.0,AssemblyFoldersEx}",
                "{AssemblyFolders}",
                "{HintPathFromItem}",
                "{GAC}"
            };

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(Path.Combine(s_myVersion20Path, "System.Xml.dll"), t.ResolvedFiles[0].ItemSpec);
        }

        /// <summary>
        /// Make sure when there are duplicate entries in the redist list, with different versions of ingac (true and false) that we will not read in two entries,
        /// we will instead pick the one with ingac true and ignore the ingac false entry.   If there is one of more entries in the redist list with ingac false
        /// and no entries with ingac true for a given assembly then we should only have one entry with ingac false.
        /// </summary>
        [Fact]
        public void TestDuplicateHandlingForRedistLists()
        {
            string fullRedistListContentsDuplicates =
              "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' />" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                  "<File AssemblyName='System.XML' Version='3.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' />" +
                  "<File AssemblyName='Microsoft.BuildEngine' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' />" +
                  "<File AssemblyName='Microsoft.BuildEngine' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                  "<File AssemblyName='Microsoft.BuildEngine' Version='3.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' />" +
              "</FileList >";

            string redistFile = FileUtilities.GetTemporaryFile();
            try
            {
                File.WriteAllText(redistFile, fullRedistListContentsDuplicates);

                AssemblyTableInfo info = new AssemblyTableInfo(redistFile, String.Empty);
                List<AssemblyEntry> assembliesReadIn = new List<AssemblyEntry>();
                List<Exception> errors = new List<Exception>();
                List<string> errorFileNames = new List<string>();
                RedistList.ReadFile(info, assembliesReadIn, errors, errorFileNames, null);
                Assert.Empty(errors); // "Expected no Errors"
                Assert.Empty(errorFileNames); // "Expected no Error file names"
                Assert.Equal(4, assembliesReadIn.Count);
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        /// <summary>
        /// Make sure that if there are different SimpleName then they will not be considered duplicates.
        /// </summary>
        [Fact]
        public void TestDuplicateHandling()
        {
            string fullRedistListContentsDuplicates =
              "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208'/>" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208'/>" +
                  "<File AssemblyName='System.XML' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' />" +
              "</FileList >";

            ExpectRedistEntries(fullRedistListContentsDuplicates, 1, 0);
        }

        /// <summary>
        /// Make sure that if there are different IsRedistRoot then they will not be considered duplicates.
        /// </summary>
        [Fact]
        public void TestDuplicateHandlingDifferentIsRedistRoot()
        {
            string fullRedistListContentsDuplicates =
              "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' IsRedistRoot='true'/>" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                  "<File AssemblyName='System.XML' Version='3.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' IsRedistRoot='false' />" +
              "</FileList >";

            ExpectRedistEntries(fullRedistListContentsDuplicates, 3, 0);
        }

        /// <summary>
        /// Make sure that if there are different IsRedistRoot then they will not be considered duplicates.
        /// </summary>
        [Fact]
        public void TestDuplicateHandlingDifferentName()
        {
            string fullRedistListContentsDuplicates =
              "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true'/>" +
                  "<File AssemblyName='MyAssembly' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                  "<File AssemblyName='AnotherAssembly' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
              "</FileList >";

            ExpectRedistEntries(fullRedistListContentsDuplicates, 3, 0);
        }

        /// <summary>
        /// Make sure that if there are different culture then they will not be considered duplicates.
        /// </summary>
        [Fact]
        public void TestDuplicateHandlingDifferentCulture()
        {
            string fullRedistListContentsDuplicates =
              "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='en-EN' FileVersion='2.0.50727.208' InGAC='true'/>" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='fr-FR' FileVersion='2.0.50727.208' InGAC='true' />" +
              "</FileList >";

            ExpectRedistEntries(fullRedistListContentsDuplicates, 3, 0);
        }

        /// <summary>
        /// Make sure that if there are different public key tokens then they will not be considered duplicates.
        /// </summary>
        [Fact]
        public void TestDuplicateHandlingDifferentPublicKeyToken()
        {
            string fullRedistListContentsDuplicates =
              "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208'/>" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' />" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='b03f5f7f11d50a3d' Culture='Neutral' FileVersion='2.0.50727.208' />" +
              "</FileList >";

            ExpectRedistEntries(fullRedistListContentsDuplicates, 3, 0);
        }

        /// <summary>
        /// Make sure that if there are different retargetable flags then they will not be considered duplicates.
        /// </summary>
        [Fact]
        public void TestDuplicateHandlingDifferentRetargetable()
        {
            string fullRedistListContentsDuplicates =

              "<FileList Redist='Microsoft-Windows-CLRCoreComp'>" +
                  "<Remap>" +
                  "<From AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' Retargetable='Yes'>" +
                     "<To AssemblyName='Remapped' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='en-us' FileVersion='2.0.50727.208' InGAC='false'/>" +
                     "</From>" +
                  "</Remap>" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' Retargetable='Yes'/>" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' Retargetable='Yes'/>" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' Retargetable='No'/>" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' />" +
              "</FileList >";

            ExpectRedistEntries(fullRedistListContentsDuplicates, 2, 1);
        }
        /// <summary>
        /// Make sure that if there are different versions that they are all picked
        /// </summary>
        [Fact]
        public void TestDuplicateHandlingDifferentVersion()
        {
            string fullRedistListContentsDuplicates =
              "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                  "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208'/>" +
                 "<Remap>" +
                     "<From AssemblyName='System.Xml2' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' Retargetable='Yes'>" +
                        "<To AssemblyName='Remapped2' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='en-us' FileVersion='2.0.50727.208' InGAC='false'/>" +
                     "</From>" +
                 "</Remap>" +
                  "<File AssemblyName='System.Xml' Version='3.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' />" +
                  "<File AssemblyName='System.Xml' Version='4.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208'/>" +
                  "<Remap>" +
                     "<From AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' Retargetable='Yes'>" +
                        "<To AssemblyName='Remapped' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='en-us' FileVersion='2.0.50727.208' InGAC='false'/>" +
                     "</From>" +
                 "</Remap>" +
            "</FileList >";

            List<AssemblyEntry> entries = ExpectRedistEntries(fullRedistListContentsDuplicates, 3, 2);
        }

        /// <summary>
        /// Expect to read in a certain number of redist list entries, this is factored out because we went to test a number of input combinations which will all result in entries returned.
        /// </summary>
        private static List<AssemblyEntry> ExpectRedistEntries(string fullRedistListContentsDuplicates, int numberOfExpectedEntries, int numberofExpectedRemapEntries)
        {
            string redistFile = FileUtilities.GetTemporaryFile();
            List<AssemblyEntry> assembliesReadIn = new List<AssemblyEntry>();
            List<AssemblyRemapping> remapEntries = new List<AssemblyRemapping>();
            try
            {
                File.WriteAllText(redistFile, fullRedistListContentsDuplicates);

                AssemblyTableInfo info = new AssemblyTableInfo(redistFile, String.Empty);
                List<Exception> errors = new List<Exception>();
                List<string> errorFileNames = new List<string>();
                RedistList.ReadFile(info, assembliesReadIn, errors, errorFileNames, remapEntries);
                Assert.Empty(errors); // "Expected no Errors"
                Assert.Empty(errorFileNames); // "Expected no Error file names"
                Assert.Equal(assembliesReadIn.Count, numberOfExpectedEntries);
                Assert.Equal(remapEntries.Count, numberofExpectedRemapEntries);
            }
            finally
            {
                File.Delete(redistFile);
            }

            return assembliesReadIn;
        }

        /// <summary>
        /// Test the basics of reading in the remapping section
        /// </summary>
        [Fact]
        public void TestRemappingSectionBasic()
        {
            string fullRedistListContents =
              "<Remap>" +
                  "<From AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' Retargetable='Yes'>" +
                     "<To AssemblyName='Remapped' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='en-us' FileVersion='2.0.50727.208' InGAC='false'/>" +
                     "</From>" +
                 "</Remap>";

            string redistFile = Path.GetTempFileName();
            try
            {
                File.WriteAllText(redistFile, fullRedistListContents);

                AssemblyTableInfo info = new AssemblyTableInfo(redistFile, String.Empty);
                List<AssemblyEntry> assembliesReadIn = new List<AssemblyEntry>();
                List<AssemblyRemapping> remap = new List<AssemblyRemapping>();
                List<Exception> errors = new List<Exception>();
                List<string> errorFileNames = new List<string>();
                RedistList.ReadFile(info, assembliesReadIn, errors, errorFileNames, remap);
                Assert.Empty(errors); // "Expected no Errors"
                Assert.Empty(errorFileNames); // "Expected no Error file names"
                Assert.Single(remap);

                AssemblyRemapping pair = remap[0];
                Assert.Equal("System.Xml", pair.From.Name);
                Assert.Equal("Remapped", pair.To.Name);
                Assert.True(pair.From.Retargetable);
                Assert.False(pair.To.Retargetable);
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        /// <summary>
        /// If there are multiple "To" elements under the "From" element then pick the first one.
        /// </summary>
        [Fact]
        public void MultipleToElementsUnderFrom()
        {
            string fullRedistListContents =
              "<Remap>" +
                  "<From AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' Retargetable='Yes'>" +
                     "<To AssemblyName='Remapped' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='en-us' FileVersion='2.0.50727.208' InGAC='false'/>" +
                     "<To AssemblyName='RemappedSecond' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='en-us' FileVersion='2.0.50727.208' InGAC='false'/>" +
                     "</From>" +
                 "</Remap>";

            string redistFile = Path.GetTempFileName();
            try
            {
                File.WriteAllText(redistFile, fullRedistListContents);

                AssemblyTableInfo info = new AssemblyTableInfo(redistFile, String.Empty);
                List<AssemblyEntry> assembliesReadIn = new List<AssemblyEntry>();
                List<AssemblyRemapping> remap = new List<AssemblyRemapping>();
                List<Exception> errors = new List<Exception>();
                List<string> errorFileNames = new List<string>();
                RedistList.ReadFile(info, assembliesReadIn, errors, errorFileNames, remap);
                Assert.Empty(errors); // "Expected no Errors"
                Assert.Empty(errorFileNames); // "Expected no Error file names"
                Assert.Single(remap);

                AssemblyRemapping pair = remap.First<AssemblyRemapping>();
                Assert.Equal("System.Xml", pair.From.Name);
                Assert.Equal("Remapped", pair.To.Name);
                Assert.True(pair.From.Retargetable);
                Assert.False(pair.To.Retargetable);
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        /// <summary>
        /// If there are two from tags which map to the same "To" element then we still need two entries.
        /// </summary>
        [Fact]
        public void DifferentFromsToSameTo()
        {
            string fullRedistListContents =
              "<Remap>" +
                  "<From AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' Retargetable='Yes'>" +
                     "<To AssemblyName='Remapped' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='en-us' FileVersion='2.0.50727.208' InGAC='false'/>" +
                     "</From>" +
                   "<From AssemblyName='System.Core' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' Retargetable='Yes'>" +
                     "<To AssemblyName='Remapped' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='en-us' FileVersion='2.0.50727.208' InGAC='false'/>" +
                    "</From>" +
                 "</Remap>";

            string redistFile = Path.GetTempFileName();
            try
            {
                File.WriteAllText(redistFile, fullRedistListContents);

                AssemblyTableInfo info = new AssemblyTableInfo(redistFile, String.Empty);
                List<AssemblyEntry> assembliesReadIn = new List<AssemblyEntry>();
                List<AssemblyRemapping> remap = new List<AssemblyRemapping>();
                List<Exception> errors = new List<Exception>();
                List<string> errorFileNames = new List<string>();
                RedistList.ReadFile(info, assembliesReadIn, errors, errorFileNames, remap);
                Assert.Empty(errors); // "Expected no Errors"
                Assert.Empty(errorFileNames); // "Expected no Error file names"
                Assert.Equal(2, remap.Count);

                foreach (AssemblyRemapping pair in remap)
                {
                    Assert.Equal("Remapped", pair.To.Name);
                    Assert.False(pair.To.Retargetable);
                }
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        /// <summary>
        /// If there are two identical entries then pick the first one
        /// </summary>
        [Fact]
        public void DuplicateEntries()
        {
            string fullRedistListContents =
              "<Remap>" +
                  "<From AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' Retargetable='Yes'>" +
                     "<To AssemblyName='Remapped' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='en-us' FileVersion='2.0.50727.208' InGAC='false'/>" +
                     "</From>" +
                   "<From AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' Retargetable='Yes'>" +
                     "<To AssemblyName='Remapped2' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='en-us' FileVersion='2.0.50727.208' InGAC='false'/>" +
                    "</From>" +
                 "</Remap>";

            string redistFile = Path.GetTempFileName();
            try
            {
                File.WriteAllText(redistFile, fullRedistListContents);

                AssemblyTableInfo info = new AssemblyTableInfo(redistFile, String.Empty);
                List<AssemblyEntry> assembliesReadIn = new List<AssemblyEntry>();
                List<AssemblyRemapping> remap = new List<AssemblyRemapping>();
                List<Exception> errors = new List<Exception>();
                List<string> errorFileNames = new List<string>();
                RedistList.ReadFile(info, assembliesReadIn, errors, errorFileNames, remap);
                Assert.Empty(errors); // "Expected no Errors"
                Assert.Empty(errorFileNames); // "Expected no Error file names"
                Assert.Single(remap);

                AssemblyRemapping pair = remap.First<AssemblyRemapping>();
                Assert.Equal("Remapped", pair.To.Name);
                Assert.False(pair.To.Retargetable);
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        /// <summary>
        /// Test if the remapping section is empty
        /// </summary>
        [Fact]
        public void EmptyRemapping()
        {
            string fullRedistListContents = "<Remap/>";

            string redistFile = Path.GetTempFileName();
            try
            {
                File.WriteAllText(redistFile, fullRedistListContents);

                AssemblyTableInfo info = new AssemblyTableInfo(redistFile, String.Empty);
                List<AssemblyEntry> assembliesReadIn = new List<AssemblyEntry>();
                List<AssemblyRemapping> remap = new List<AssemblyRemapping>();
                List<Exception> errors = new List<Exception>();
                List<string> errorFileNames = new List<string>();
                RedistList.ReadFile(info, assembliesReadIn, errors, errorFileNames, remap);
                Assert.Empty(errors); // "Expected no Errors"
                Assert.Empty(errorFileNames); // "Expected no Error file names"
                Assert.Empty(remap);
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        /// <summary>
        /// Test if the we have a "from" element but no "to" element. We expect that to be ignored
        /// </summary>
        [Fact]
        public void FromElementButNoToElement()
        {
            string fullRedistListContents =
        "<Remap>" +
         "<From AssemblyName='System.Core' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' Retargetable='Yes'/>" +
         "<From AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' Retargetable='Yes'>" +
                     "<To AssemblyName='Remapped' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='en-us' FileVersion='2.0.50727.208' InGAC='false'/>" +
         "</From>" +
        "</Remap>";

            string redistFile = Path.GetTempFileName();
            try
            {
                File.WriteAllText(redistFile, fullRedistListContents);

                AssemblyTableInfo info = new AssemblyTableInfo(redistFile, String.Empty);
                List<AssemblyEntry> assembliesReadIn = new List<AssemblyEntry>();
                List<AssemblyRemapping> remap = new List<AssemblyRemapping>();
                List<Exception> errors = new List<Exception>();
                List<string> errorFileNames = new List<string>();
                RedistList.ReadFile(info, assembliesReadIn, errors, errorFileNames, remap);
                Assert.Empty(errors); // "Expected no Errors"
                Assert.Empty(errorFileNames); // "Expected no Error file names"
                Assert.Single(remap);

                AssemblyRemapping pair = remap.First<AssemblyRemapping>();
                Assert.Equal("System.Xml", pair.From.Name);
                Assert.Equal("Remapped", pair.To.Name);
                Assert.True(pair.From.Retargetable);
                Assert.False(pair.To.Retargetable);
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        /// <summary>
        /// Test if the we have a "To" element but no "from" element. We expect that to be ignored
        /// </summary>
        [Fact]
        public void ToElementButNoFrom()
        {
            string fullRedistListContents =
        "<Remap>" +
         "<To AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' Retargetable='Yes'/>" +
        "</Remap>";

            string redistFile = Path.GetTempFileName();
            try
            {
                File.WriteAllText(redistFile, fullRedistListContents);

                AssemblyTableInfo info = new AssemblyTableInfo(redistFile, String.Empty);
                List<AssemblyEntry> assembliesReadIn = new List<AssemblyEntry>();
                List<AssemblyRemapping> remap = new List<AssemblyRemapping>();
                List<Exception> errors = new List<Exception>();
                List<string> errorFileNames = new List<string>();
                RedistList.ReadFile(info, assembliesReadIn, errors, errorFileNames, remap);
                Assert.Empty(errors); // "Expected no Errors"
                Assert.Empty(errorFileNames); // "Expected no Error file names"
                Assert.Empty(remap);
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        /// <summary>
        /// If a relative file name is passed in through the Assemblies parameter and the search paths contains {RawFileName}
        /// then try to resolve directly to that file name and make it a full path.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void RawFileNameRelative()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            string testPath = Path.Combine(Path.GetTempPath(), @"RawFileNameRelative");
            string previousCurrentDirectory = Directory.GetCurrentDirectory();

            Directory.CreateDirectory(testPath);
            Directory.SetCurrentDirectory(testPath);
            try
            {
                t.Assemblies = new ITaskItem[] { new TaskItem(@"..\RawFileNameRelative\System.Xml.dll") };
                t.SearchPaths = new string[] { "{RawFileName}" };
                Execute(t);

                Assert.Single(t.ResolvedFiles);
                Assert.Equal(Path.Combine(testPath, "System.Xml.dll"), t.ResolvedFiles[0].ItemSpec);
            }
            finally
            {
                Directory.SetCurrentDirectory(previousCurrentDirectory);

                if (Directory.Exists(testPath))
                {
                    FileUtilities.DeleteWithoutTrailingBackslash(testPath);
                }
            }
        }

        /// <summary>
        /// If a relative searchPath is passed in through the search path parameter
        /// then try to resolve the file but make sure it is a full name
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void RelativeDirectoryResolver()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            string testPath = Path.Combine(Path.GetTempPath(), @"RawFileNameRelative");
            string previousCurrentDirectory = Directory.GetCurrentDirectory();

            Directory.CreateDirectory(testPath);
            Directory.SetCurrentDirectory(testPath);
            try
            {
                t.Assemblies = new ITaskItem[] { new TaskItem(@"System.Xml.dll") };
                t.SearchPaths = new string[] { "..\\RawFileNameRelative" };
                Execute(t);

                Assert.Single(t.ResolvedFiles);
                Assert.Equal(Path.Combine(testPath, "System.Xml.dll"), t.ResolvedFiles[0].ItemSpec);
            }
            finally
            {
                Directory.SetCurrentDirectory(previousCurrentDirectory);

                if (Directory.Exists(testPath))
                {
                    FileUtilities.DeleteWithoutTrailingBackslash(testPath);
                }
            }
        }

        /// <summary>
        /// If a relative file name is passed in through the HintPath then try to resolve directly to that file name and make it a full path.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void HintPathRelative()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            string testPath = Path.Combine(Path.GetTempPath(), @"RawFileNameRelative");
            string previousCurrentDirectory = Directory.GetCurrentDirectory();

            Directory.CreateDirectory(testPath);
            Directory.SetCurrentDirectory(testPath);
            try
            {
                TaskItem taskItem = new TaskItem(AssemblyRef.SystemXml);
                taskItem.SetMetadata("HintPath", @"..\RawFileNameRelative\System.Xml.dll");

                t.Assemblies = new ITaskItem[] { taskItem };
                t.SearchPaths = new string[] { "{HintPathFromItem}" };
                Execute(t);

                Assert.Single(t.ResolvedFiles);
                Assert.Equal(Path.Combine(testPath, "System.Xml.dll"), t.ResolvedFiles[0].ItemSpec);
            }
            finally
            {
                Directory.SetCurrentDirectory(previousCurrentDirectory);

                if (Directory.Exists(testPath))
                {
                    FileUtilities.DeleteWithoutTrailingBackslash(testPath);
                }
            }
        }
        /// <summary>
        /// Make sure we do not crash if a raw file name is passed in and the specific version metadata is set
        /// </summary>
        [Fact]
        public void RawFileNameWithSpecificVersionFalse()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            ITaskItem taskItem = new TaskItem(Path.Combine(s_myVersion20Path, "System.Xml.dll"));
            taskItem.SetMetadata("SpecificVersion", "false");

            t.Assemblies = new ITaskItem[] { taskItem };
            t.SearchPaths = new string[]
            {
                "{RawFileName}",
            };

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(Path.Combine(s_myVersion20Path, "System.Xml.dll"), t.ResolvedFiles[0].ItemSpec);
        }

        /// <summary>
        /// Make sure we do not crash if a raw file name is passed in and the specific version metadata is set
        /// </summary>
        [Fact]
        public void RawFileNameWithSpecificVersionTrue()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            ITaskItem taskItem = new TaskItem(Path.Combine(s_myVersion20Path, "System.Xml.dll"));
            taskItem.SetMetadata("SpecificVersion", "true");

            t.Assemblies = new ITaskItem[] { taskItem };
            t.SearchPaths = new string[]
            {
                "{RawFileName}",
            };

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(Path.Combine(s_myVersion20Path, "System.Xml.dll"), t.ResolvedFiles[0].ItemSpec);
        }

        /// <summary>
        /// If the user passed in a file name but no {RawFileName} was specified.
        /// </summary>
        [Fact]
        public void Regress363340_RawFileNameMissing()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem(Path.Combine(s_myVersion20Path, "System.Xml.dll")),
                new TaskItem(@"System.Data")
            };

            t.SearchPaths = new string[]
            {
                s_myVersion20Path,
            };

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(Path.Combine(s_myVersion20Path, "System.Data.dll"), t.ResolvedFiles[0].ItemSpec);
        }

        /// <summary>
        /// If the reference include looks like a file name rather than a properly formatted reference and a good hint path is provided,
        /// good means the hintpath points to a file which exists on disk. Then we were getting an exception
        /// because assemblyName was null and we were comparing the assemblyName from the hintPath to the null assemblyName.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void Regress444793()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine engine = new MockEngine(_output);
            t.BuildEngine = engine;

            TaskItem item = new TaskItem(@"c:\DoesntExist\System.Xml.dll");
            item.SetMetadata("HintPath", Path.Combine(s_myVersion20Path, "System.Data.dll"));
            item.SetMetadata("SpecificVersion", "true");
            t.Assemblies = new ITaskItem[] { item };
            t.SearchPaths = new string[]
            {
                @"{HintPathFromItem}"
            };

            bool succeeded = Execute(t);
            Assert.True(succeeded);
            engine.AssertLogDoesntContain("MSB4018");

            engine.AssertLogContains
            (
                String.Format(AssemblyResources.GetString("General.MalformedAssemblyName"), "c:\\DoesntExist\\System.Xml.dll")
            );
        }

        /// <summary>
        /// If a file name is passed in through the Assemblies parameter and the search paths contains {RawFileName}
        /// then try to resolve directly to that file name.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void RawFileNameDoesntExist()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine engine = new MockEngine(_output);
            t.BuildEngine = engine;

            t.Assemblies = new ITaskItem[] { new TaskItem(@"c:\DoesntExist\System.Xml.dll") };
            t.SearchPaths = new string[] { "{RawFileName}" };

            bool succeeded = Execute(t);
            Assert.True(succeeded);
            engine.AssertLogContains
            (
                String.Format(AssemblyResources.GetString("General.MalformedAssemblyName"), "c:\\DoesntExist\\System.Xml.dll")
            );
        }

        /// <summary>
        /// If a candidate file has a different base name, then this should not be a match.
        /// </summary>
        [Fact]
        public void CandidateAssemblyFilesDifferentBaseName()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem("VendorAssembly") };
            t.SearchPaths = new string[] { "{CandidateAssemblyFiles}" };
            t.CandidateAssemblyFiles = new string[] { @"Dlls\ProjectItemAssembly.dll" };

            Execute(t);

            Assert.Empty(t.ResolvedFiles);
        }

        /// <summary>
        /// Given a strong name, resolve it to a location in the GAC if possible.
        /// </summary>
        [Fact]
        public void ResolveToGAC()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine engine = new MockEngine(_output);
            t.BuildEngine = engine;

            t.Assemblies = new ITaskItem[] { new TaskItem("System") };
            t.TargetedRuntimeVersion = typeof(Object).Assembly.ImageRuntimeVersion;
            t.SearchPaths = new string[] { "{GAC}" };
            bool succeeded = t.Execute();
            Assert.True(succeeded);
            Assert.Single(t.ResolvedFiles);
        }

        /// <summary>
        /// Given a strong name, resolve it to a location in the GAC if possible.
        /// </summary>
        [Fact]
        public void ResolveToGACSpecificVersion()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            MockEngine engine = new MockEngine(_output);
            t.BuildEngine = engine;

            TaskItem item = new TaskItem("System");
            item.SetMetadata("SpecificVersion", "true");
            t.Assemblies = new ITaskItem[] { item };
            t.SearchPaths = new string[] { "{GAC}" };
            t.TargetedRuntimeVersion = new Version("0.5.0.0").ToString();
            bool succeeded = t.Execute();
            Assert.True(succeeded);
            Assert.Single(t.ResolvedFiles);
        }

        /// <summary>
        /// Verify that when we are calculating the search paths for a dependency that we take into account where the parent assembly was resolved from
        /// for example if the parent assembly was resolved from the GAC or AssemblyFolders then we do not want to look in the parent assembly directory
        /// instead we want to let the assembly be resolved normally so that the GAC and AF checks will work.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void ParentAssemblyResolvedFromAForGac()
        {
            var parentReferenceFolders = new List<string>();
            var referenceList = new List<Reference>();

            var taskItem = new TaskItem("Microsoft.VisualStudio.Interopt, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
            var reference = new Reference(isWinMDFile, fileExists, getRuntimeVersion);
            reference.MakePrimaryAssemblyReference(taskItem, false, ".dll");
            reference.FullPath = "c:\\AssemblyFolders\\Microsoft.VisualStudio.Interopt.dll";
            reference.ResolvedSearchPath = "{AssemblyFolders}";

            Reference reference2 = new Reference(isWinMDFile, fileExists, getRuntimeVersion);
            reference2.MakePrimaryAssemblyReference(taskItem, false, ".dll");
            reference2.FullPath = "c:\\SomeOtherFolder\\Microsoft.VisualStudio.Interopt2.dll";
            reference2.ResolvedSearchPath = "c:\\SomeOtherFolder";

            Reference reference3 = new Reference(isWinMDFile, fileExists, getRuntimeVersion);
            reference3.MakePrimaryAssemblyReference(taskItem, false, ".dll");
            reference3.FullPath = "c:\\SomeOtherFolder\\Microsoft.VisualStudio.Interopt3.dll";
            reference3.ResolvedSearchPath = "{GAC}";

            referenceList.Add(reference);
            referenceList.Add(reference2);
            referenceList.Add(reference3);

            foreach (Reference parentReference in referenceList)
            {
                ReferenceTable.CalculateParentAssemblyDirectories(parentReferenceFolders, parentReference);
            }

            Assert.Single(parentReferenceFolders);
            Assert.Equal(reference2.ResolvedSearchPath, parentReferenceFolders[0]);
        }
        
        /// <summary>
        /// Generate a fake reference which has been resolved from the gac. We will use it to verify the creation of the exclusion list.
        /// </summary>
        /// <returns></returns>
        private ReferenceTable GenerateTableWithAssemblyFromTheGlobalLocation(string location)
        {
            ReferenceTable referenceTable = new ReferenceTable(null, false, false, false, false, new string[0], null, null, null, null, null, null, SystemProcessorArchitecture.None, fileExists, null, null, null, null,
#if FEATURE_WIN32_REGISTRY
                null, null, null,
#endif
                null, null, new Version("4.0"), null, null, null, true, false, null, null, false, null, WarnOrErrorOnTargetArchitectureMismatchBehavior.None, false, false, null);

            AssemblyNameExtension assemblyNameExtension = new AssemblyNameExtension(new AssemblyName("Microsoft.VisualStudio.Interopt, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"));
            TaskItem taskItem = new TaskItem("Microsoft.VisualStudio.Interopt, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");

            Reference reference = new Reference(isWinMDFile, fileExists, getRuntimeVersion);
            reference.MakePrimaryAssemblyReference(taskItem, false, ".dll");
            // "Resolve the assembly from the gac"
            reference.FullPath = "c:\\Microsoft.VisualStudio.Interopt.dll";
            reference.ResolvedSearchPath = location;
            referenceTable.AddReference(assemblyNameExtension, reference);

            assemblyNameExtension = new AssemblyNameExtension(new AssemblyName("Team.System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"));
            taskItem = new TaskItem("Team, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");

            reference = new Reference(isWinMDFile, fileExists, getRuntimeVersion);
            reference.MakePrimaryAssemblyReference(taskItem, false, ".dll");

            // "Resolve the assembly from the gac"
            reference.FullPath = "c:\\Team.System.dll";
            reference.ResolvedSearchPath = location;
            referenceTable.AddReference(assemblyNameExtension, reference);
            return referenceTable;
        }

        /// <summary>
        /// Given a reference that resolves to a bad image, we should get a warning and
        /// no reference. We don't want an exception.
        /// </summary>
        [Fact]
        public void ResolveBadImageInPrimary()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine engine = new MockEngine(_output);
            t.BuildEngine = engine;
            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("BadImage")
            };
            t.Assemblies[0].SetMetadata("Private", "true");
            t.SearchPaths = new string[] { s_myVersion20Path };
            t.TargetFrameworkDirectories = new string[] { s_myVersion20Path };

            Execute(t);

            // There should be no resolved file, because the image was bad.
            Assert.Empty(t.ResolvedFiles);

            // There should be no related files either.
            Assert.Empty(t.RelatedFiles);
            engine.AssertLogDoesntContain("BadImage.pdb");
            engine.AssertLogDoesntContain("HRESULT");

            // There should have been one warning about the exception.
            Assert.Equal(1, engine.Warnings);
        }

        /// <summary>
        /// Given a reference that resolves to a bad image, we should get a message, no warning and
        /// no reference. We don't want an exception.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void ResolveBadImageInSecondary()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine engine = new MockEngine(true);
            t.BuildEngine = engine;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("DependsOnBadImage")
            };

            t.SearchPaths = new string[]
            {
                @"c:\Regress563286",
                @"c:\WINNT\Microsoft.NET\Framework\v2.0.MyVersion"
            };
            Execute(t);

            // There should be one resolved file, because the dependency was bad.
            Assert.Single(t.ResolvedFiles);

            // There should be no related files.
            Assert.Empty(t.RelatedFiles);
            engine.AssertLogDoesntContain("BadImage.pdb");
            engine.AssertLogDoesntContain("HRESULT");

            // There should have been no warning about the exception because it's only a dependency
            Assert.Equal(0, engine.Warnings);
        }

        /// <summary>
        /// Test the case where the search path, earlier on, contains an assembly that almost matches
        /// but the PKT is wrong.
        /// </summary>
        [Fact]
        public void ResolveReferenceThatHasWrongPKTInEarlierAssembly()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem(AssemblyRef.SystemData) };
            t.SearchPaths = new string[]
            {
                s_myProjectPath,
                s_myVersion20Path
            };

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(Path.Combine(s_myVersion20Path, "System.Data.dll"), t.ResolvedFiles[0].ItemSpec);
        }

        /// <summary>
        /// FX assemblies should not be CopyLocal.
        /// </summary>
        [Fact]
        public void PrimaryFXAssemblyRefIsNotCopyLocal()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] { new TaskItem(AssemblyRef.SystemData) };
            t.SearchPaths = new string[]
            {
                s_myVersion20Path
            };

            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(Path.Combine(s_myVersion20Path, "System.Data.dll"), t.ResolvedFiles[0].ItemSpec);
            Assert.Equal("false", t.ResolvedFiles[0].GetMetadata("CopyLocal"));
        }

        /// <summary>
        /// If an item is explicitly Private=='true' (as opposed to implicitly when the attribute isn't set at all)
        /// then it should be CopyLocal true even if its in the FX directory
        /// </summary>
        [Fact]
        public void PrivateItemInFrameworksGetsCopyLocalTrue()
        {
            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            // Create the mocks.
            Microsoft.Build.Shared.FileExists fileExists = new Microsoft.Build.Shared.FileExists(FileExists);
            Microsoft.Build.Shared.DirectoryExists directoryExists = new Microsoft.Build.Shared.DirectoryExists(DirectoryExists);
            Microsoft.Build.Tasks.GetDirectories getDirectories = new Microsoft.Build.Tasks.GetDirectories(GetDirectories);
            Microsoft.Build.Tasks.GetAssemblyName getAssemblyName = new Microsoft.Build.Tasks.GetAssemblyName(GetAssemblyName);
            Microsoft.Build.Tasks.GetAssemblyMetadata getAssemblyMetadata = new Microsoft.Build.Tasks.GetAssemblyMetadata(GetAssemblyMetadata);

            // Also construct a set of assembly names to pass in.
            ITaskItem[] assemblyNames = new TaskItem[]
            {
                new TaskItem("System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
            };

            assemblyNames[0].SetMetadata("Private", "true"); // Fx file, but user chose private=true.

            // Now, pass feed resolved primary references into ResolveAssemblyReference.
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = engine;
            t.Assemblies = assemblyNames;
            t.TargetFrameworkDirectories = new string[] { s_myVersion20Path };
            t.SearchPaths = DefaultPaths;
            Execute(t);
            Assert.Equal(@"true", t.ResolvedFiles[0].GetMetadata("CopyLocal"));
        }

        /// <summary>
        /// If we have no framework directories passed in and an assembly is found outside of the GAC then it should be able to be copy local.
        /// </summary>
        [Fact]
        public void NoFrameworkDirectoriesStillCopyLocal()
        {
            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            // Also construct a set of assembly names to pass in.
            ITaskItem[] assemblyNames = new TaskItem[]
            {
                new TaskItem(s_assemblyFolder_SomeAssemblyDllPath)
            };

            // Now, pass feed resolved primary references into ResolveAssemblyReference.
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = engine;
            t.Assemblies = assemblyNames;
            t.TargetFrameworkDirectories = new string[] { };
            t.SearchPaths = new string[] { "{RawFileName}" };
            Execute(t);
            Assert.Equal(@"true", t.ResolvedFiles[0].GetMetadata("CopyLocal"));
        }

        /// <summary>
        /// If an item has a bad value for a boolean attribute, report a nice error that indicates which attribute it was.
        /// </summary>
        [Fact]
        public void Regress284485_PrivateItemWithBogusValue()
        {
            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            // Also construct a set of assembly names to pass in.
            ITaskItem[] assemblyNames = new TaskItem[]
            {
                new TaskItem("System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
            };

            assemblyNames[0].SetMetadata("Private", "bogus"); // Fx file, but user chose private=true.

            // Now, pass feed resolved primary references into ResolveAssemblyReference.
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = engine;
            t.Assemblies = assemblyNames;
            t.TargetFrameworkDirectories = new string[] { s_myVersion20Path };
            t.SearchPaths = DefaultPaths;
            Execute(t);

            string message = String.Format(AssemblyResources.GetString("General.InvalidAttributeMetadata"), assemblyNames[0].ItemSpec, "Private", "bogus", "bool");
            Assert.Contains(message, engine.Log);
        }

        /// <summary>
        /// Consider this dependency chain:
        ///
        /// App
        ///   Primary References
        ///         C
        ///         A version 2
        ///         And both A version 2 and C are CopyLocal=true
        ///   References - C
        ///        Depends on A version 1
        ///        Depends on B
        ///   References - B
        ///        Depends on A version 2
        ///
        ///
        /// Expect to have some information indicating that C and B depend on two different versions of A and that the primary reference which caused the problems
        /// are A and C.
        /// </summary>
        [Fact]
        public void ConflictBetweenCopyLocalDependenciesRegress444809()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine engine = new MockEngine(_output);
            t.BuildEngine = engine;

            t.Assemblies = new ITaskItem[] {
                new TaskItem("A, Version=2.0.0.0, Culture=Neutral, PublicKeyToken=null"), new TaskItem("C, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=null")
            };

            t.SearchPaths = new string[] {
                s_regress444809RootPath, s_regress444809_V2RootPath
            };

            t.TargetFrameworkDirectories = new string[] { s_myVersion20Path };

            bool result = Execute(t);
            ResourceManager resources = new ResourceManager("Microsoft.Build.Tasks.Strings", Assembly.GetExecutingAssembly());

            //Unresolved primary reference with itemspec "A, Version=20.0.0.0, Culture=Neutral, PublicKeyToken=null".
            engine.AssertLogContainsMessageFromResource(resourceDelegate, "ResolveAssemblyReference.ReferenceDependsOn", "A, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=null", s_regress444809_ADllPath);
            engine.AssertLogContainsMessageFromResource(resourceDelegate, "ResolveAssemblyReference.ReferenceDependsOn", "A, Version=2.0.0.0, Culture=Neutral, PublicKeyToken=null", s_regress444809_V2_ADllPath);
            engine.AssertLogContainsMessageFromResource(resourceDelegate, "ResolveAssemblyReference.PrimarySourceItemsForReference", s_regress444809_CDllPath);
            engine.AssertLogContainsMessageFromResource(resourceDelegate, "ResolveAssemblyReference.PrimarySourceItemsForReference", s_regress444809_BDllPath);
            engine.AssertLogContainsMessageFromResource(resourceDelegate, "ResolveAssemblyReference.PrimarySourceItemsForReference", s_regress444809_V2_ADllPath);
        }

        /// <summary>
        /// Consider this dependency chain:
        ///
        /// App
        ///   Primary References
        ///         A version 20 (Un Resolved)
        ///         B
        ///         D
        ///   References - B
        ///        Depends on A version 2
        ///   References - D
        ///        Depends on A version 20
        ///
        ///
        /// Expect to have some information indicating that Primary reference A, Reference B and Reference D conflict.
        /// </summary>
        [Fact]
        public void ConflictBetweenCopyLocalDependenciesRegress444809UnResolvedPrimaryReference()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine engine = new MockEngine(_output);
            t.BuildEngine = engine;

            t.Assemblies = new ITaskItem[] {
                new TaskItem("A, Version=172.16.31.10, Culture=Neutral, PublicKeyToken=null"),
                new TaskItem("B, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=null"),
                new TaskItem("D, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=null")
            };

            t.SearchPaths = new string[] {
                s_regress444809RootPath, s_regress444809_V2RootPath
            };

            t.TargetFrameworkDirectories = new string[] { s_myVersion20Path };

            bool result = Execute(t);

            engine.AssertLogContainsMessageFromResource(resourceDelegate, "ResolveAssemblyReference.ReferenceDependsOn", "A, Version=172.16.31.10, Culture=Neutral, PublicKeyToken=null", String.Empty);
            engine.AssertLogContainsMessageFromResource(resourceDelegate, "ResolveAssemblyReference.ReferenceDependsOn", "A, Version=2.0.0.0, Culture=Neutral, PublicKeyToken=null", s_regress444809_V2_ADllPath);
            engine.AssertLogContainsMessageFromResource(resourceDelegate, "ResolveAssemblyReference.UnResolvedPrimaryItemSpec", "A, Version=172.16.31.10, Culture=Neutral, PublicKeyToken=null");
            engine.AssertLogContainsMessageFromResource(resourceDelegate, "ResolveAssemblyReference.PrimarySourceItemsForReference", s_regress444809_DDllPath);
            engine.AssertLogContainsMessageFromResource(resourceDelegate, "ResolveAssemblyReference.PrimarySourceItemsForReference", s_regress444809_BDllPath);
        }

        /// <summary>
        /// Consider this dependency chain:
        ///
        /// App
        ///   References - B
        ///        Depends on D version 2
        ///   References - D, version 1
        ///
        /// Both D1 and D2 are CopyLocal. This is a warning because D1 is a lower version
        /// than both D2 so that can't unify. These means that eventually when 
        /// they're copied to the output directory they'll conflict.
        /// </summary>
        [Fact]
        public void ConflictGeneratesMessageReferencingAssemblyName()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("B"),
                new TaskItem("D, Version=1.0.0.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa")
            };

            t.SearchPaths = new string[]
            {
                s_myLibrariesRootPath, s_myLibraries_V2Path, s_myLibraries_V1Path
            };

            t.TargetFrameworkDirectories = new string[] { s_myVersion20Path };

            bool result = Execute(t);

            Assert.Equal(1, e.Warnings); // @"Expected one warning."

            // Check that we have a message identifying conflicts with "D"
            string warningMessage = e.WarningEvents[0].Message;
            warningMessage.ShouldContain(ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveAssemblyReference.FoundConflicts", "D", string.Empty));
            warningMessage.ShouldContain(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ResolveAssemblyReference.ConflictFound", "D, Version=1.0.0.0, CulTUre=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa", "D, Version=2.0.0.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa"));
            warningMessage.ShouldContain(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ResolveAssemblyReference.FourSpaceIndent", ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ResolveAssemblyReference.ReferenceDependsOn", "D, Version=1.0.0.0, CulTUre=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa", Path.Combine(s_myLibraries_V1Path, "D.dll"))));
        }

        [Fact]
        public void ConflictOutputsExtraInformationOnDemand()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("B"),
                new TaskItem("D, Version=1.0.0.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa")
            };

            t.SearchPaths = new string[]
            {
                s_myLibrariesRootPath, s_myLibraries_V2Path, s_myLibraries_V1Path
            };

            t.TargetFrameworkDirectories = new string[] { s_myVersion20Path };
            t.OutputUnresolvedAssemblyConflicts = true;

            Execute(t);

            ITaskItem[] conflicts = t.UnresolvedAssemblyConflicts;
            conflicts.Length.ShouldBe(1);
            conflicts[0].ItemSpec.ShouldBe("D");
            conflicts[0].GetMetadata("victorVersionNumber").ShouldBe("1.0.0.0");
            conflicts[0].GetMetadata("victimVersionNumber").ShouldBe("2.0.0.0");
        }

        /// <summary>
        /// Consider this dependency chain:
        ///
        /// App
        ///   References - B
        ///        Depends on D version 2
        ///        Depends on G, version 2
        ///   References - D, version 1
        ///   References - G, version 1
        ///
        /// All of Dv1, Dv2, Gv1 and Gv2 are CopyLocal. We should get two conflict warnings, one for D and one for G.
        /// </summary>
        [Fact]
        public void ConflictGeneratesMessageReferencingEachConflictingAssemblyName()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("B"),
                new TaskItem("D, Version=1.0.0.0, Culture=neutral, PublicKeyToken=<KEY>"),
                new TaskItem("G, Version=1.0.0.0, Culture=neutral, PublicKeyToken=<KEY>")
            };

            t.SearchPaths = new string[]
            {
                s_myLibrariesRootPath, s_myLibraries_V2Path, s_myLibraries_V1Path
            };

            t.TargetFrameworkDirectories = new string[] { s_myVersion20Path };

            bool result = Execute(t);

            Assert.Equal(2, e.Warnings); // @"Expected two warnings."

            // Check that we have both the expected messages
            string warningMessage = e.WarningEvents[0].Message;
            warningMessage.ShouldContain(ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveAssemblyReference.FoundConflicts", "D", string.Empty));
            warningMessage.ShouldContain(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ResolveAssemblyReference.ConflictFound", "D, Version=1.0.0.0, CulTUre=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa", "D, Version=2.0.0.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa"));
            warningMessage.ShouldContain(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ResolveAssemblyReference.FourSpaceIndent", ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ResolveAssemblyReference.ReferenceDependsOn", "D, Version=1.0.0.0, CulTUre=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa", Path.Combine(s_myLibraries_V1Path, "D.dll"))));

            warningMessage = e.WarningEvents[1].Message;
            warningMessage.ShouldContain(ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveAssemblyReference.FoundConflicts", "G", string.Empty));
            warningMessage.ShouldContain(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ResolveAssemblyReference.ConflictFound", "G, Version=1.0.0.0, CulTUre=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa", "G, Version=2.0.0.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa"));
            warningMessage.ShouldContain(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ResolveAssemblyReference.FourSpaceIndent", ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ResolveAssemblyReference.ReferenceDependsOn", "G, Version=1.0.0.0, CulTUre=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa", Path.Combine(s_myLibraries_V1Path, "G.dll"))));
        }

        /// <summary>
        /// Consider this dependency chain:
        ///
        /// App
        ///   References - A
        ///        Depends on D version 1
        ///   References - B
        ///        Depends on D version 2
        ///   References - D, version 2
        ///
        /// Both D1 and D2 are CopyLocal. This is not an error because D2 is a higher version
        /// than D1 so that can unify. D2 should be output as a Primary and D1 should be output
        /// as a dependency.
        /// </summary>
        [Fact]
        public void ConflictWithForeVersionPrimary()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("B"),
                new TaskItem("A"),
                new TaskItem("D, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>")
            };

            t.SearchPaths = new string[] {
                s_myLibrariesRootPath, s_myLibraries_V2Path, s_myLibraries_V1Path
            };

            t.TargetFrameworkDirectories = new string[] { s_myVersion20Path };

            bool result = Execute(t);

            Assert.True(result); // @"Expected a success because this conflict is solvable."
            Assert.Equal(3, t.ResolvedFiles.Length);
            Assert.True(ContainsItem(t.ResolvedFiles, s_myLibraries_V2_DDllPath));

            Assert.Equal(2, t.ResolvedDependencyFiles.Length);
            Assert.True(ContainsItem(t.ResolvedDependencyFiles, s_myLibraries_V1_DDllPath));
            Assert.True(ContainsItem(t.ResolvedDependencyFiles, s_myLibraries_V2_GDllPath));
        }

        /// <summary>
        /// Consider this dependency chain:
        ///
        /// App
        ///   References - D, version 1
        ///   References - D, version 2
        ///
        /// Both D1 and D2 are CopyLocal. This is an error because both D1 and D2 can't be copied to
        /// the output directory.
        /// </summary>
        [Fact]
        public void ConflictBetweenBackAndForeVersionsCopyLocal()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("D, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>"),
                new TaskItem("D, Version=1.0.0.0, Culture=neutral, PublicKeyToken=<KEY>")
            };

            t.SearchPaths = new string[]
            {
                s_myLibrariesRootPath, s_myLibraries_V2Path, s_myLibraries_V1Path
            };

            t.TargetFrameworkDirectories = new string[] { s_myVersion20Path };

            bool result = Execute(t);

            Assert.Equal(2, e.Warnings); // @"Expected a warning because this is an unresolvable conflict."
            Assert.Equal(2, t.ResolvedFiles.Length);
            Assert.True(ContainsItem(t.ResolvedFiles, s_myLibraries_V2_DDllPath)); // "Expected to find assembly, but didn't."
            Assert.True(ContainsItem(t.ResolvedFiles, s_myLibraries_V1_DDllPath)); // "Expected to find assembly, but didn't."
        }

        /// <summary>
        /// Consider this dependency chain:
        ///
        /// App
        ///   References - D, version 1
        ///   References - D, version 2
        ///
        /// Neither D1 nor D2 are CopyLocal. This is a solvable conflict because D2 has a higher version
        /// than D1 and there won't be an output directory conflict.
        /// </summary>
        [Fact]
        public void ConflictBetweenBackAndForeVersionsNotCopyLocal()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("D, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>"),
                new TaskItem("D, Version=1.0.0.0, Culture=neutral, PublicKeyToken=<KEY>")
            };

            t.SearchPaths = new string[] {
                s_myLibrariesRootPath, s_myLibraries_V2Path, s_myLibraries_V1Path
            };

            bool result = Execute(t);

            Assert.True(result); // @"Expected success because this conflict is solvable."
            Assert.Equal(2, t.ResolvedFiles.Length);
            Assert.True(ContainsItem(t.ResolvedFiles, s_myLibraries_V2_DDllPath)); // "Expected to find assembly, but didn't."
            Assert.True(ContainsItem(t.ResolvedFiles, s_myLibraries_V1_DDllPath)); // "Expected to find assembly, but didn't."
        }

        /// <summary>
        /// Consider this dependency chain:
        ///
        /// App
        ///   References - A
        ///        Depends on D version 1, PKT=XXXX
        ///   References - C
        ///        Depends on D version 1, PKT=YYYY
        ///
        /// We can't tell which should win because the PKTs are different. This should be an error.
        /// </summary>
        [Fact]
        public void ConflictingDependenciesWithNonMatchingNames()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A"),
                new TaskItem("C")
            };

            t.SearchPaths = new string[]
            {
                s_myLibrariesRootPath, s_myLibraries_V1Path, @"c:\RogueLibraries\v1"
            };

            bool result = Execute(t);
            Assert.True(result); // "Execute should have failed because of insoluble conflict."
        }

        /// <summary>
        /// Consider this dependency chain:
        ///
        /// App
        ///   References - A
        ///        Depends on D version 1, PKT=XXXX
        ///   References - C
        ///        Depends on D version 1, PKT=YYYY
        ///   References - D version 1, PKT=XXXX
        ///
        /// D, PKT=XXXX should win because its referenced in the project.
        ///
        /// </summary>
        [Fact]
        public void ConflictingDependenciesWithNonMatchingNamesAndHardReferenceInProject()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A"),
                new TaskItem("C"),
                new TaskItem("D, Version=1.0.0.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa")
            };

            t.SearchPaths = new string[]
            {
                s_myLibrariesRootPath, s_myLibraries_V1Path, @"c:\RogueLibraries\v1"
            };

            Execute(t);

            Assert.Equal(3, t.ResolvedFiles.Length);
            Assert.True(ContainsItem(t.ResolvedFiles, s_myLibraries_V1_DDllPath)); // "Expected to find assembly, but didn't."
        }

        /// <summary>
        /// A reference with a bogus version is provided. However, the user has chosen
        /// SpecificVersion='false' so we match the first one we come across.
        /// </summary>
        [Fact]
        public void SpecificVersionFalse()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem(@"System.XML, Version=9.9.9999.9, Culture=neutral, PublicKeyToken=abababababababab")
            };

            t.Assemblies[0].SetMetadata("SpecificVersion", "false");

            t.SearchPaths = DefaultPaths;
            Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.Equal(Path.Combine(s_myVersion20Path, "System.XML.dll"), t.ResolvedFiles[0].ItemSpec);
        }

        /// <summary>
        /// A reference with a bogus version is provided and the user has chosen SpecificVersion=true.
        /// In this case, since there is no specific version that can be matched, no reference is returned.
        /// </summary>
        [Fact]
        public void SpecificVersionTrue()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] {
                new TaskItem(@"System.XML, Version=9.9.9999.9, Culture=neutral, PublicKeyToken=abababababababab")
            };

            t.Assemblies[0].SetMetadata("SpecificVersion", "true");

            t.SearchPaths = DefaultPaths;
            Execute(t);

            Assert.Empty(t.ResolvedFiles);
        }

        /// <summary>
        /// A reference with a bogus version is provided and the user has left off SpecificVersion.
        /// In this case assume SpecificVersion=true implicitly.
        /// </summary>
        [Fact]
        public void SpecificVersionAbsent()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[] {
                new TaskItem(@"System.XML, Version=9.9.9999.9, Culture=neutral, PublicKeyToken=abababababababab")
            };

            t.SearchPaths = DefaultPaths;
            Execute(t);

            Assert.Empty(t.ResolvedFiles);
        }

        /// <summary>
        /// Unresolved primary references should result in warnings.
        /// </summary>
        [Fact]
        public void Regress199998()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine m = new MockEngine(_output);
            t.BuildEngine = m;

            t.Assemblies = new ITaskItem[]
            {
                // An assembly that is unresolvable because it doesn't exist.
                new TaskItem(@"System.XML, Version=9.9.9999.9, Culture=neutral, PublicKeyToken=<PASSWORD>abababababab")
            };

            t.SearchPaths = DefaultPaths;
            Execute(t);

            Assert.Empty(t.ResolvedFiles);
            // One warning for the un-resolved reference and one warning saying you are trying to target an assembly higher than the current target
            // framework.
            Assert.Equal(1, m.Warnings);
        }

        /// <summary>
        /// In this case,
        /// - A single primary file reference to simple name "A".
        /// - The reference has an <ExecutableExtension>.exe</ExecutableExtension> tag.
        /// - Both a.exe and a.dll exist on disk.
        /// Expected:
        /// - The resulting assembly returned should be a.exe
        /// Rationale:
        /// The user browsed to an .exe, so that's what we should give them.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void ExecutableExtensionEXE()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A")
            };

            t.Assemblies[0].SetMetadata("ExecutableExtension", ".eXe");

            t.SearchPaths = new string[]
            {
                s_myLibrariesRootPath,
                @"c:\MyExecutableLibraries"
            };

            Execute(t);

            Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
            Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
            Assert.Single(t.ResolvedFiles);
            Assert.True(ContainsItem(t.ResolvedFiles, @"c:\MyExecutableLibraries\a.exe")); // "Expected to find assembly, but didn't."
        }

        /// <summary>
        /// In this case,
        /// - A single primary file reference to simple name "A".
        /// - The reference has an <ExecutableExtension>.dll</ExecutableExtension> tag.
        /// - Both a.exe and a.dll exist on disk.
        /// Expected:
        /// - The resulting assembly returned should be a.dll
        /// Rationale:
        /// The user browsed to a .dll, so that's what we should give them.
        /// </summary>
        [Fact]
        public void ExecutableExtensionDLL()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A")
            };

            t.Assemblies[0].SetMetadata("ExecutableExtension", ".DlL");

            t.SearchPaths = new string[]
            {
                @"c:\MyExecutableLibraries",
                s_myLibrariesRootPath
            };

            Execute(t);

            Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
            Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
            Assert.Single(t.ResolvedFiles);
            Assert.True(ContainsItem(t.ResolvedFiles, s_myLibraries_ADllPath)); // "Expected to find assembly, but didn't."
        }

        /// <summary>
        /// In this case,
        /// - A single primary file reference to simple name "A".
        /// - The reference has no <ExecutableExtension></ExecutableExtension> tag.
        /// - Both a.exe and a.dll exist on disk.
        /// - A.dll is first in the search order.
        /// Expected:
        /// - The resulting assembly returned should be a.dll
        /// Rationale:
        /// Without an ExecutableExtension the first assembly out of .dll,.exe wins.
        /// </summary>
        [Fact]
        public void ExecutableExtensionDefaultDLLFirst()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A")
            };

            t.SearchPaths = new string[]
            {
                s_myLibrariesRootPath,
                @"c:\MyExecutableLibraries"
            };

            Execute(t);

            Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
            Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
            Assert.Single(t.ResolvedFiles);
            Assert.True(ContainsItem(t.ResolvedFiles, s_myLibraries_ADllPath)); // "Expected to find assembly, but didn't."
        }

        /// <summary>
        /// In this case,
        /// - A single primary file reference to simple name "A".
        /// - The reference has no <ExecutableExtension></ExecutableExtension> tag.
        /// - Both a.exe and a.dll exist on disk.
        /// - A.exe is first in the search order.
        /// Expected:
        /// - The resulting assembly returned should be a.exe
        /// Rationale:
        /// Without an ExecutableExtension the first assembly out of .dll,.exe wins.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void ExecutableExtensionDefaultEXEFirst()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A")
            };

            t.SearchPaths = new string[]
            {
                @"c:\MyExecutableLibraries",
                s_myLibrariesRootPath
            };

            Execute(t);

            Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
            Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
            Assert.Single(t.ResolvedFiles);
            Assert.True(ContainsItem(t.ResolvedFiles, @"c:\MyExecutableLibraries\A.exe")); // "Expected to find assembly, but didn't."
        }

        /// <summary>
        /// In this case,
        /// - A single primary file reference to simple name "A".
        /// - The reference has <SpecificVersion>true</SpecificVersion> tag.
        /// - An assembly with a strong fusion name "A, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" exists first in the search order.
        /// - An assembly with a weak fusion name "A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" is second in the search order.
        /// Expected:
        /// - This is an unresolved reference.
        /// Rationale:
        /// If specific version is true, but the reference is a simple name like "A", then there is no way to do a specific version match.
        /// This is a corner case. Other solutions that might have been just as good:
        /// - Fall back to SpecificVersion=false behavior.
        /// - Only match "A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null". Note that all of our default VS projects have at least a version number.
        /// </summary>
        [Fact]
        public void SimpleNameWithSpecificVersionTrue()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A")
            };
            t.Assemblies[0].SetMetadata("SpecificVersion", "true");

            t.SearchPaths = new string[]
            {
                @"c:\MyStronglyNamed",
                s_myLibrariesRootPath
            };

            Execute(t);

            Assert.Equal(1, e.Warnings); // "No warnings expected in this scenario."
            Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
            Assert.Empty(t.ResolvedFiles);
        }

        /// <summary>
        /// In this case,
        /// - A single primary file reference to simple name "A".
        /// - The reference has <SpecificVersion>true</SpecificVersion> tag.
        /// - An assembly with a strong fusion name "A, PKT=..., Version=..., Culture=..." exists first in the search order.
        /// - An assembly with a weak fusion name "A, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" is second in the search order.
        /// Expected:
        /// - The resulting assembly returned should be the strongly named a.dll.
        /// Rationale:
        /// If specific version is false, then we should match the first "A" that we find.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void SimpleNameWithSpecificVersionFalse()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A")
            };
            t.Assemblies[0].SetMetadata("SpecificVersion", "false");

            t.SearchPaths = new string[]
            {
                @"c:\MyStronglyNamed",
                s_myLibrariesRootPath
            };

            Execute(t);

            Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
            Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
            Assert.Single(t.ResolvedFiles);
            Assert.True(ContainsItem(t.ResolvedFiles, @"c:\MyStronglyNamed\A.dll")); // "Expected to find assembly, but didn't."
        }

        /// <summary>
        /// Consider this situation:
        ///
        /// App
        ///   References - D, version 1, IrreleventKeyValue=poo.
        ///
        /// There's plenty of junk that might end up in a fusion name that have nothing to do with
        /// assembly resolution. Make sure we can tolerate this for primary references.
        /// </summary>
        [Fact]
        public void IrrelevantAssemblyNameElement()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("D, Version=1.0.0.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa, IrreleventKeyValue=poo"),
            };

            t.SearchPaths = new string[]
            {
                s_myLibrariesRootPath, s_myLibraries_V2Path, s_myLibraries_V1Path
            };

            t.TargetFrameworkDirectories = new string[] { s_myVersion20Path };

            bool result = Execute(t);

            Assert.Single(t.ResolvedFiles);
            Assert.True(ContainsItem(t.ResolvedFiles, s_myLibraries_V1_DDllPath)); // "Expected to find assembly, but didn't."
        }

        /// <summary>
        /// Regress EVERETT QFE 626
        /// Consider this dependency chain:
        ///
        /// App
        ///   References - A (Private=undefined)
        ///        Depends on D
        ///             Depends on E
        ///   References - D (Private=false)
        ///
        /// - Reference A does not have a Private attribute, but resolves to CopyLocal=true.
        /// - Reference D has explicit Private=false.
        /// - D would normally be CopyLocal=true.
        /// - E would normally be CopyLocal=true.
        ///
        /// Expected:
        /// - D should be CopyLocal=false because the of the matching Reference D which has explicit private=false.
        /// - E should be CopyLocal=false because it's a dependency of D which has explicit private=false.
        ///
        /// Rationale:
        /// This is QFE 626. If the user has set "Copy Local" to "false" in VS (means Private=false)
        /// then even if this turns out to be a dependency too, we still shouldn't copy.
        ///
        /// </summary>
        [Fact]
        public void RegressQFE626()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine engine = new MockEngine(_output);
            t.BuildEngine = engine;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A"),
                new TaskItem("D")
            };
            t.Assemblies[1].SetMetadata("Private", "false");

            t.SearchPaths = new string[]
            {
                s_myLibrariesRootPath, s_myLibraries_V1Path, s_myLibraries_V1_EPath
            };
            t.TargetFrameworkDirectories = new string[] { @"c:\myfx" };

            Execute(t);

            Assert.Equal(2, t.ResolvedFiles.Length);
            Assert.Single(t.ResolvedDependencyFiles); // Not 2 because D is treated as a primary reference.
            Assert.True(ContainsItem(t.ResolvedDependencyFiles, s_myLibraries_V1_E_EDllPath)); // "Expected to find assembly, but didn't."
            Assert.Equal(0, engine.Warnings);
            Assert.Equal(0, engine.Errors);

            foreach (ITaskItem item in t.ResolvedDependencyFiles)
            {
                if (String.Equals(item.ItemSpec, s_myLibraries_V1_E_EDllPath, StringComparison.OrdinalIgnoreCase))
                {
                    Assert.Equal("false", item.GetMetadata("CopyLocal"));
                }
            }
        }

        /// <summary>
        /// Consider this dependency chain:
        ///
        /// App
        ///   References - A (private=false)
        ///        Depends on D v1
        ///             Depends on E
        ///   References - B (private=true)
        ///        Depends on D v2
        ///             Depends on E
        ///
        /// Reference A is explicitly Private=false.
        /// Reference B is explicitly Private=true.
        /// Dependencies D and E would normally be CopyLocal=true.
        ///
        /// Expected:
        /// - D will be CopyLocal=false because it's dependency of A, which is private=false.
        /// - E will be CopyLocal=true because all source primary references aren't private=false.
        ///
        /// Rationale:
        /// Dependencies will be CopyLocal=false if all source primary references are Private=false.
        ///
        /// </summary>
        [Fact]
        public void Regress265054()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A"),
                new TaskItem("B")
            };
            t.Assemblies[0].SetMetadata("Private", "false");
            t.Assemblies[1].SetMetadata("Private", "true");

            t.SearchPaths = new string[]
            {
                s_myLibrariesRootPath, s_myLibraries_V1Path, s_myLibraries_V2Path, s_myLibraries_V1_EPath
            };
            t.TargetFrameworkDirectories = new string[] { @"c:\myfx" };

            Execute(t);

            Assert.Equal(2, t.ResolvedFiles.Length);

            Assert.Equal(4, t.ResolvedDependencyFiles.Length);
            Assert.True(ContainsItem(t.ResolvedDependencyFiles, s_myLibraries_V1_DDllPath));
            Assert.True(ContainsItem(t.ResolvedDependencyFiles, s_myLibraries_V2_DDllPath));
            Assert.True(ContainsItem(t.ResolvedDependencyFiles, s_myLibraries_V2_GDllPath));
            Assert.True(ContainsItem(t.ResolvedDependencyFiles, s_myLibraries_V1_E_EDllPath));

            foreach (ITaskItem item in t.ResolvedDependencyFiles)
            {
                if (String.Equals(item.ItemSpec, s_myLibraries_V1_DDllPath, StringComparison.OrdinalIgnoreCase))
                {
                    Assert.Equal("false", item.GetMetadata("CopyLocal"));
                }

                if (String.Equals(item.ItemSpec, s_myLibraries_V1_E_EDllPath, StringComparison.OrdinalIgnoreCase))
                {
                    Assert.Equal("true", item.GetMetadata("CopyLocal"));
                }
            }
        }

        /// <summary>
        /// Here's how you get into this situation:
        ///
        /// App
        ///   References - A
        ///   References - B
        ///        Depends on A
        ///
        ///    And, the following conditions.
        ///     Primary "A" has no explicit Version (i.e. it's a simple name)
        ///        Primary "A" *is not* resolved.
        ///        Dependency "A" *is* resolved.
        ///
        /// Expected result:
        /// * No exceptions.
        /// * Build error about unresolved primary reference.
        ///
        /// </summary>
        [Fact]
        public void Regress312873_UnresolvedPrimaryWithResolveDependency()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A"),
                new TaskItem("B"),

                // We need a one more "A" because the bug was in a Compare function
                // called by .Sort. We need enough items to guarantee that A with null version
                // will be on the left side of a compare.
                new TaskItem("A")
};

            t.Assemblies[1].SetMetadata("HintPath", @"C:\Regress312873\b.dll");
            t.Assemblies[2].SetMetadata("HintPath", @"C:\Regress312873-2\a.dll");

            t.SearchPaths = new string[]
            {
                @"{HintPathFromItem}"
            };

            Execute(t);
        }

        /// <summary>
        /// We weren't handling scatter assemblies.
        ///
        /// App
        ///   References - A
        ///
        ///    And, the following conditions.
        ///     Primary "A" has two scatter files "M1" and "M2"
        ///
        /// Expected result:
        /// * M1 and M2 should be output in ScatterFiles and CopyLocal.
        ///
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void Regress275161_ScatterAssemblies()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A")
            };

            t.Assemblies[0].SetMetadata("HintPath", @"C:\Regress275161\a.dll");

            t.SearchPaths = new string[]
            {
                @"{HintPathFromItem}"
            };

            t.TargetFrameworkDirectories = new string[] { @"c:\myfx" };

            Execute(t);

            Assert.True(ContainsItem(t.ScatterFiles, @"C:\Regress275161\m1.netmodule")); //                 "Expected to find scatter file m1."

            Assert.True(ContainsItem(t.ScatterFiles, @"C:\Regress275161\m2.netmodule")); //                 "Expected to find scatter file m2."

            Assert.True(ContainsItem(t.CopyLocalFiles, @"C:\Regress275161\m1.netmodule")); //                 "Expected to find scatter file m1 in CopyLocalFiles."

            Assert.True(ContainsItem(t.CopyLocalFiles, @"C:\Regress275161\m2.netmodule")); //                 "Expected to find scatter file m2 in CopyLocalFiles."
        }

        /// <summary>
        /// We weren't handling scatter assemblies.
        ///
        /// App
        ///   References - A
        ///        Depends on B v1.0.0.0
        ///   References - B v2.0.0.0
        ///
        ///
        ///    And, the following conditions.
        ///    * All assemblies are resolved.
        /// * All assemblies are CopyLocal=true.
        /// * Notice the conflict between versions of B.
        ///
        /// Expected result:
        /// * During conflict resolution, B v2.0.0.0 should win.
        /// * B v1.0.0.0 should still be listed in dependencies (there's not a strong case for this either way)
        /// * B v1.0.0.0 should be CopyLocal='false'
        ///
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void Regress317975_LeftoverLowerVersion()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A"),
                new TaskItem("B")
};

            t.Assemblies[0].SetMetadata("HintPath", @"C:\Regress317975\a.dll");
            t.Assemblies[1].SetMetadata("HintPath", @"C:\Regress317975\v2\b.dll");

            t.SearchPaths = new string[]
            {
                @"{HintPathFromItem}"
            };

            t.TargetFrameworkDirectories = new string[] { @"c:\myfx" };

            Execute(t);

            foreach (ITaskItem i in t.ResolvedDependencyFiles)
            {
                Assert.Equal(0, String.Compare(i.GetMetadata("CopyLocal"), "false", StringComparison.OrdinalIgnoreCase));
            }

            Assert.True(ContainsItem(t.ResolvedDependencyFiles, @"C:\Regress317975\B.dll")); //                 "Expected to find lower version listed in dependencies."
        }

        /// <summary>
        /// Mscorlib is special in that it doesn't always have complete metadata. For example,
        /// GetAssemblyName can return null. This was confusing the {RawFileName} resolution path,
        /// which is fairly different from the other code paths.
        ///
        /// App
        ///   References - "c:\path-to-mscorlib\mscorlib.dll" (Current FX)
        ///
        /// Expected result:
        /// * Even though mscorlib.dll doesn't have an assembly name, we should be able to return
        ///   a result.
        ///
        /// NOTES:
        /// * This test works because path-to-mscorlib is the same as the path to the FX folder.
        ///   Because of this, the hard-cache is used rather than actually calling GetAssemblyName
        ///   on mscorlib.dll. This isn't going to work in cases where mscorlib is from an FX other
        ///   than the current target. See the Part2 for a test that covers this other case.
        ///
        /// </summary>
        [Fact]
        public void Regress313086_Part1_MscorlibAsRawFilename()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem(typeof(object).Module.FullyQualifiedName.ToLower())
};

            t.SearchPaths = new string[]
            {
                @"{RawFileName}"
            };

            t.TargetFrameworkDirectories = new string[] { Path.GetDirectoryName(typeof(object).Module.FullyQualifiedName) };

            t.Execute();

            Assert.Single(t.ResolvedFiles);
        }

        /// <summary>
        /// Mscorlib is special in that it doesn't always have complete metadata. For example,
        /// GetAssemblyName can return null. This was confusing the {RawFileName} resolution path,
        /// which is fairly different from the other code paths.
        ///
        /// App
        ///   References - "c:\path-to-mscorlib\mscorlib.dll" (non-Current FX)
        ///
        /// Expected result:
        /// * Even though mscorlib.dll doesn't have an assembly name, we should be able to return
        ///   a result.
        ///
        /// NOTES:
        /// * This test is covering the case where mscorlib.dll is coming from somewhere besides
        ///   the main (ie Whidbey) FX.
        ///
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void Regress313086_Part2_MscorlibAsRawFilename()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem(@"c:\Regress313086\mscorlib.dll")
};

            t.SearchPaths = new string[]
            {
                @"{RawFileName}"
            };

            t.TargetFrameworkDirectories = new string[] { @"c:\myfx" };

            Execute(t);

            Assert.Single(t.ResolvedFiles);
        }

        /// <summary>
        /// If a directory path is passed into AssemblyFiles, then we should warn and continue on.
        /// </summary>
        [Fact]
        public void Regress284466_DirectoryIntoAssemblyFiles()
        {
            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            ITaskItem[] assemblyFiles = new TaskItem[]
                    {
                        new TaskItem(s_unifyMeDll_V10Path),
                        new TaskItem(Path.GetTempPath())
                    };

            // Now, pass feed resolved primary references into ResolveAssemblyReference.
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = engine;
            t.AssemblyFiles = assemblyFiles;
            t.SearchPaths = DefaultPaths;

            bool succeeded = Execute(t);

            Assert.True(succeeded);
            Assert.Single(t.ResolvedFiles);
            t.ResolvedFiles[0].GetMetadata("FusionName").ShouldBe("UnifyMe, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, ProcessorArchitecture=MSIL", StringCompareShould.IgnoreCase);
            Assert.Contains(
                String.Format(AssemblyResources.GetString("General.ExpectedFileGotDirectory"), Path.GetTempPath()),
                engine.Log);
        }

        /// <summary>
        /// If a relative assemblyFile is passed in resolve it as a full path.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void RelativeAssemblyFiles()
        {
            string testPath = Path.Combine(Path.GetTempPath(), @"RelativeAssemblyFiles");
            string previousCurrentDirectory = Directory.GetCurrentDirectory();

            Directory.CreateDirectory(testPath);
            Directory.SetCurrentDirectory(testPath);
            try
            {
                // Create the engine.
                MockEngine engine = new MockEngine(_output);

                ITaskItem[] assemblyFiles = new TaskItem[]
                    {
                        new TaskItem(@"..\RelativeAssemblyFiles\System.Xml.dll")
                    };

                // Now, pass feed resolved primary references into ResolveAssemblyReference.
                ResolveAssemblyReference t = new ResolveAssemblyReference();

                t.BuildEngine = engine;
                t.AssemblyFiles = assemblyFiles;
                t.SearchPaths = DefaultPaths;

                bool succeeded = Execute(t);

                Assert.True(succeeded);
                Assert.Single(t.ResolvedFiles);
                Assert.Equal(Path.Combine(testPath, "System.Xml.dll"), t.ResolvedFiles[0].ItemSpec);
            }
            finally
            {
                Directory.SetCurrentDirectory(previousCurrentDirectory);

                if (Directory.Exists(testPath))
                {
                    FileUtilities.DeleteWithoutTrailingBackslash(testPath);
                }
            }
        }

        /// <summary>
        /// Behave gracefully if a referenced assembly is inaccessible to the user.
        /// </summary>
        [Fact]
        public void Regress316906_UnauthorizedAccessViolation_PrimaryReferenceIsInaccessible()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A")
            };
            t.Assemblies[0].SetMetadata("SpecificVersion", "false");

            t.SearchPaths = new string[]
            {
                @"c:\MyInaccessible"
            };

            Execute(t);

            Assert.Equal(1, e.Warnings); // "One warning expected in this scenario."
            Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
            Assert.Empty(t.ResolvedFiles);
        }

        /// <summary>
        /// Behave gracefully if a referenced assembly is inaccessible to the user.
        /// In this case, the file is still resolved because it was passed in directly.
        /// There's no way to determine dependencies however.
        /// </summary>
        [Fact]
        public void Regress316906_UnauthorizedAccessViolation_PrimaryFileIsInaccessible()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.AssemblyFiles = new ITaskItem[]
            {
                new TaskItem(@"c:\MyInaccessible\A.dll")
            };

            Execute(t);

            Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
            Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
            Assert.Single(t.ResolvedFiles);
        }

        /// <summary>
        /// Behave gracefully if a referenced assembly is inaccessible to the user.
        /// </summary>
        [Fact]
        public void Regress316906_UnauthorizedAccessViolation_PrimaryAsRawFileIsInaccessible()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem(@"c:\MyInaccessible\A.dll")
            };
            t.SearchPaths = new string[] { "{RawFileName}" };

            Execute(t);

            Assert.Equal(1, e.Warnings); // "One warning expected in this scenario."
            Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
            Assert.Empty(t.ResolvedFiles);
        }

        /// <summary>
        /// If there's a SearhPath like {Registry:,,} then still behave nicely.
        /// </summary>
        [Fact]
        public void Regress269704_MissingRegistryElements()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A")
            };
            t.Assemblies[0].SetMetadata("SpecificVersion", "false");

            t.SearchPaths = new string[]
            {
                @"{Registry:,,}",
                @"c:\MyAssemblyDoesntExistHere"
            };

            Execute(t);

            Assert.Equal(1, e.Warnings); // "No warning expected in this scenario."
            Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
            Assert.Empty(t.ResolvedFiles);
        }

        /// <summary>
        /// 1.  Create a C# classlibrary, and build it.
        /// 2.  Go to disk, and rename ClassLibrary1.dll (or whatever it was) to Foo.dll
        /// 3.  Create a C# console application.
        /// 4.  In the console app, add a File reference to Foo.dll.
        /// 5.  Build the console app.
        ///
        /// RESULTS (before bugfix):
        /// ========================
        /// MSBUILD : warning : Couldn't resolve this reference.  Could not locate assembly "ClassLibrary1"
        ///
        /// EXPECTED (after bugfix):
        /// ========================
        /// We think it might be reasonable for the ResolveAssemblyReference task to correctly resolve
        /// this reference, especially given the fact that the HintPath was provided in the project file.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void Regress276548_AssemblyNameDifferentThanFusionName()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A")
            };
            t.Assemblies[0].SetMetadata
            (
                "HintPath",
                @"c:\MyNameMismatch\Foo.dll"
            );

            t.SearchPaths = new string[]
            {
                @"{HintPathFromItem}"
            };

            Execute(t);

            Assert.Equal(0, e.Warnings); // "One warning expected in this scenario."
            Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
            Assert.Single(t.ResolvedFiles);
        }

        /// <summary>
        /// When very long paths are passed in we should be robust.
        /// </summary>
        [Fact]
        public void Regress314573_VeryLongPaths()
        {
            string veryLongPath = @"C:\" + new String('a', 260);
            string veryLongFile = veryLongPath + "\\A.dll";

            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A")                    // Resolved by HintPath
            };
            t.Assemblies[0].SetMetadata
            (
                "HintPath",
                veryLongFile
            );

            t.SearchPaths = new string[]
            {
                "{HintPathFromItem}"
            };

            t.AssemblyFiles = new ITaskItem[]
            {
                new TaskItem(veryLongFile)            // Resolved as File Reference
            };

            Execute(t);

            Assert.Equal(1, e.Warnings); // "One warning expected in this scenario." // Couldn't find dependencies for {HintPathFromItem}-resolved item.
            Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
            Assert.Empty(t.ResolvedFiles);  // This test used to have 1 here. But that was because the mock GetAssemblyName was not accurately throwing an exception for non-existent files.
        }

        /// <summary>
        /// Need to be robust in the face of assembly names with special characters.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void Regress265003_EscapedCharactersInFusionName()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("\\=A\\=, Version=2.0.0.0, Culture=neUtral, PublicKeyToken=b77a5c561934e089"), // Characters that should be escaped in fusion names: \ , " ' =
                new TaskItem("__\\'ASP\\'dw0024ry")
            };

            t.Assemblies[0].SetMetadata("SpecificVersion", "false");    // Important to this bug.
            t.Assemblies[1].SetMetadata("HintPath", @"c:\MyEscapedName\__'ASP'dw0024ry.dll");
            t.TargetFrameworkDirectories = new string[] { Path.GetDirectoryName(typeof(object).Module.FullyQualifiedName) };

            t.SearchPaths = new string[]
            {
                @"{TargetFrameworkDirectory}",
                @"{HintPathFromItem}",
                @"c:\MyEscapedName"
            };

            Execute(t);

            Assert.Equal(0, e.Warnings); // "One warning expected in this scenario."
            Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
            Assert.Equal(2, t.ResolvedFiles.Length);
        }

        /// <summary>
        /// If we're given bogus Include (one with characters that would normally need escaping) but we also
        /// have a hintpath, then go ahead and resolve anyway because we know what the path should be.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void Regress284081_UnescapedCharactersInFusionNameWithHintPath()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("__'ASP'dw0024ry")    // Would normally require quoting for the tick marks.
            };

            t.Assemblies[0].SetMetadata("HintPath", @"c:\MyEscapedName\__'ASP'dw0024ry.dll");

            t.SearchPaths = new string[]
            {
                "{RawFileName}",
                "{CandidateAssemblyFiles}",
                s_myProjectPath,
                s_myVersion20Path,
                @"{Registry:Software\Microsoft\.NetFramework,v2.0,AssemblyFoldersEx}",
                "{AssemblyFolders}",
                "{HintPathFromItem}"
            };

            Execute(t);

            Assert.Equal(0, e.Warnings); // "No warning expected in this scenario."
            Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
            Assert.Single(t.ResolvedFiles);
        }

        /// <summary>
        /// Everett supported assembly names that had .dll at the end.
        /// </summary>
        [Fact]
        public void Regress366322_ReferencesWithFileExtensions()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A.dll")       // User really meant a fusion name here.
            };

            t.SearchPaths = new string[]
            {
                s_myLibrariesRootPath
            };

            Execute(t);

            Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
            Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
            Assert.Single(t.ResolvedFiles);
            Assert.True(ContainsItem(t.ResolvedFiles, s_myLibraries_ADllPath)); // "Expected to find assembly, but didn't."
        }

        /// <summary>
        /// Support for multiple framework directories.
        /// </summary>
        [Fact]
        public void Regress366814_MultipleFrameworksFolders()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A")
            };

            t.TargetFrameworkDirectories = new string[] { @"c:\boguslocation", s_myLibrariesRootPath };
            t.SearchPaths = new string[]
            {
                @"{TargetFrameworkDirectory}",
            };

            Execute(t);

            Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
            Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
            Assert.Single(t.ResolvedFiles);
            Assert.True(ContainsItem(t.ResolvedFiles, s_myLibraries_ADllPath)); // "Expected to find assembly, but didn't."
        }

        /// <summary>
        /// If the App.Config file has a bad .XML then handle it gracefully.
        /// (i.e. no exception is thrown from the task.
        /// </summary>
        [Fact]
        public void Regress271273_BogusAppConfig()
        {
            // Create the engine.
            MockEngine engine = new MockEngine(_output);

            ITaskItem[] assemblyFiles = new TaskItem[]
                    {
                        new TaskItem(s_unifyMeDll_V10Path)
                    };

            // Construct the app.config.
            string appConfigFile = WriteAppConfig
            (
                "        <dependentAssembly\n" +        // Intentionally didn't close this XML tag.
                "        </dependentAssembly>\n"
            );

            try
            {
                // Now, pass feed resolved primary references into ResolveAssemblyReference.
                ResolveAssemblyReference t = new ResolveAssemblyReference();

                t.BuildEngine = engine;
                t.AssemblyFiles = assemblyFiles;
                t.SearchPaths = DefaultPaths;
                t.AppConfigFile = appConfigFile;

                Execute(t);
            }
            finally
            {
                // Cleanup.
                File.Delete(appConfigFile);
            }
        }

        /// <summary>
        /// The user might pass in a HintPath that has a trailing slash. Need to not crash.
        ///
        /// </summary>
        [Fact]
        public void Regress354669_HintPathWithTrailingSlash()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A")
            };

            t.Assemblies[0].SetMetadata("HintPath", @"C:\Regress354669\");

            t.SearchPaths = new string[]
            {
                "{RawFileName}",
                "{CandidateAssemblyFiles}",
                s_myProjectPath,
                s_myVersion20Path,
                @"{Registry:Software\Microsoft\.NetFramework,v2.0,AssemblyFoldersEx}",
                "{AssemblyFolders}",
                "{HintPathFromItem}"
            };
            Execute(t);
        }

        /// <summary>
        /// The user might pass in a HintPath that has a trailing slash. Need to not crash.
        ///
        ///    Assembly A
        ///     References: C, version 2
        ///
        ///    Assembly B
        ///     References: C, version 1
        ///
        /// There is an App.Config file that redirects all versions of C to V2.
        /// Assemblies A and B are both located via their HintPath.
        ///
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void Regress339786_CrossVersionsWithAppConfig()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("B"),
                new TaskItem("A"),
            };

            t.Assemblies[0].SetMetadata("HintPath", @"C:\Regress339786\FolderB\B.dll");
            t.Assemblies[1].SetMetadata("HintPath", @"C:\Regress339786\FolderA\A.dll");

            // Construct the app.config.
            string appConfigFile = WriteAppConfig
            (
            "        <dependentAssembly>\n" +
            "            <assemblyIdentity name='C' PublicKeyToken='null' culture='neutral' />\n" +
            "            <bindingRedirect oldVersion='0.0.0.0-2.0.0.0' newVersion='2.0.0.0' />\n" +
            "        </dependentAssembly>\n"
            );
            t.AppConfigFile = appConfigFile;

            try
            {
                t.SearchPaths = new string[]
                {
                    "{HintPathFromItem}"
                };
                Execute(t);
            }
            finally
            {
                File.Delete(appConfigFile);
            }

            Assert.Single(t.ResolvedDependencyFiles);
        }

        /// <summary>
        /// An older LKG of the CLR could throw a FileLoadException if it doesn't recognize
        /// the assembly. We need to support this for dogfooding purposes.
        /// </summary>
        [Fact]
        public void Regress_DogfoodCLRThrowsFileLoadException()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("DependsMyFileLoadExceptionAssembly")
            };

            t.SearchPaths = new string[]
            {
                @"c:\OldClrBug"
            };
            Execute(t);
        }

        /// <summary>
        /// There was a bug in which any file mentioned in the InstalledAssemblyTables was automatically
        /// considered to be a file present in the framework directory. This assumption was originally true,
        /// but became false when Crystal Reports started putting their assemblies in this table.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void Regress407623_RedistListDoesNotImplyPresenceInFrameworks()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("CrystalReportsAssembly")
            };

            t.Assemblies[0].SetMetadata("SpecificVersion", "false");    // Important to this bug.
            t.TargetFrameworkDirectories = new string[] { @"r:\WINDOWS\Microsoft.NET\Framework\v2.0.myfx" };

            t.SearchPaths = new string[]
            {
                @"{TargetFrameworkDirectory}",        // Assembly is not here.
                @"c:\Regress407623"                    // Assembly is here.
            };

            string redistFile = FileUtilities.GetTemporaryFile();
            try
            {
                File.Delete(redistFile);
                File.WriteAllText
                (
                    redistFile,
                    "<FileList Redist='CrystalReports-Redist' >" +
                        "<File AssemblyName='CrystalReportsAssembly' Version='2.0.3600.0' PublicKeyToken='<KEY>' Culture='neutral' ProcessorArchitecture='MSIL' FileVersion='2.0.40824.0' InGAC='true' />" +
                    "</FileList >"
                );

                t.InstalledAssemblyTables = new TaskItem[] { new TaskItem(redistFile) };

                Execute(t);
            }
            finally
            {
                File.Delete(redistFile);
            }

            Assert.Equal(0, e.Warnings); // "No warnings expected in this scenario."
            Assert.Equal(0, e.Errors); // "No errors expected in this scenario."
            Assert.Single(t.ResolvedFiles);
            Assert.True(ContainsItem(t.ResolvedFiles, @"c:\Regress407623\CrystalReportsAssembly.dll")); // "Expected to find assembly, but didn't."
        }

        /// <summary>
        /// If an invalid file name is passed to InstalledAssemblyTables we expect a warning even if no other redist lists are passed.
        /// </summary>
        [Fact]
        public void InvalidCharsInInstalledAssemblyTable()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("SomeAssembly")
            };

            t.TargetFrameworkDirectories = new string[] { @"r:\WINDOWS\Microsoft.NET\Framework\v2.0.myfx" };
            t.InstalledAssemblyTables = new TaskItem[] { new TaskItem("asdfasdfasjr390rjfiogatg~~!@@##$%$%%^&**()") };

            Execute(t);
            e.AssertLogContains("MSB3250");
        }

        /// <summary>
        /// Here's how you get into this situation:
        ///
        /// App
        ///   References - Microsoft.Build.Engine
        ///     Hintpath = C:\Regress435487\microsoft.build.engine.dll
        ///
        ///    And, the following conditions.
        ///     microsoft.build.engine.dll has the redistlist InGac=true flag set.
        ///
        /// Expected result:
        /// * For the assembly to be CopyLocal=true
        ///
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void Regress435487_FxFileResolvedByHintPathShouldByCopyLocal()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("Microsoft.Build.Engine")
            };

            t.Assemblies[0].SetMetadata("HintPath", @"C:\Regress435487\microsoft.build.engine.dll");

            t.SearchPaths = new string[]
            {
                @"{HintPathFromItem}",
                @"{TargetFrameworkDirectory}"
            };
            t.TargetFrameworkDirectories = new string[] { @"r:\WINDOWS\Microsoft.NET\Framework\v2.0.myfx" };

            string redistFile = FileUtilities.GetTemporaryFile();

            try
            {
                File.Delete(redistFile);

                File.WriteAllText
                (
                    redistFile,
                    "<FileList Redist='MyFancy-Redist' >" +
                        "<File AssemblyName='Microsoft.Build.Engine' Version='0.0.0.0' PublicKeyToken='null' Culture='Neutral' FileVersion='2.0.40824.0' InGAC='true' />" +
                    "</FileList >"
                );

                t.InstalledAssemblyTables = new TaskItem[] { new TaskItem(redistFile) };

                Execute(t);
            }
            finally
            {
                File.Delete(redistFile);
            }

            Assert.Equal("true", t.ResolvedFiles[0].GetMetadata("CopyLocal")); // "Expected CopyLocal==true."
        }

        /// <summary>
        /// Verify when doing partial name matching with the assembly name that we also correctly do the partial name matching when trying to find
        /// assemblies from the redist list.
        /// </summary>
        [Fact]
        public void PartialNameMatchingFromRedist()
        {
            string redistFile = FileUtilities.GetTemporaryFile();

            try
            {
                File.Delete(redistFile);

                File.WriteAllText
                (
                    redistFile,
                    "<FileList Redist='MyFancy-Redist' >" +
                        // Simple name match where everything is the same except for version
                        "<File AssemblyName='A' Version='1.0.0.0' PublicKeyToken='a5d015c7d5a0b012' Culture='de-DE' FileVersion='2.0.40824.0' InGAC='true' />" +
                        "<File AssemblyName='A' Version='2.0.0.0' PublicKeyToken='a5d015c7d5a0b012' Culture='neutral' FileVersion='2.0.40824.0' InGAC='true' />" +
                        "<File AssemblyName='A' Version='3.0.0.0' PublicKeyToken='null' Culture='de-DE' FileVersion='2.0.40824.0' InGAC='true' />" +
                    "</FileList >"
                );

                AssemblyName v1 = new AssemblyName("A, Culture=de-DE, PublicKeyToken=a5d015c7d5a0b012, Version=1.0.0.0");
                AssemblyName v2 = new AssemblyName("A, Culture=Neutral, PublicKeyToken=a5d015c7d5a0b012, Version=2.0.0.0");
                AssemblyName v3 = new AssemblyName("A, Culture=de-DE, PublicKeyToken=null, Version=3.0.0.0");

                AssemblyNameExtension Av1 = new AssemblyNameExtension(v1);
                AssemblyNameExtension Av2 = new AssemblyNameExtension(v2);
                AssemblyNameExtension Av3 = new AssemblyNameExtension(v3);

                AssemblyTableInfo assemblyTableInfo = new AssemblyTableInfo(redistFile, "MyFrameworkDirectory");
                RedistList redistList = RedistList.GetRedistList(new AssemblyTableInfo[] { assemblyTableInfo });
                InstalledAssemblies installedAssemblies = new InstalledAssemblies(redistList);

                AssemblyNameExtension assemblyName = new AssemblyNameExtension("A");
                AssemblyNameExtension foundAssemblyName = FrameworkPathResolver.GetHighestVersionInRedist(installedAssemblies, assemblyName);
                Assert.Equal(Av3, foundAssemblyName);

                assemblyName = new AssemblyNameExtension("A, PublicKeyToken=a5d015c7d5a0b012");
                foundAssemblyName = FrameworkPathResolver.GetHighestVersionInRedist(installedAssemblies, assemblyName);
                Assert.Equal(Av2, foundAssemblyName);

                assemblyName = new AssemblyNameExtension("A, Culture=de-DE");
                foundAssemblyName = FrameworkPathResolver.GetHighestVersionInRedist(installedAssemblies, assemblyName);
                Assert.Equal(Av3, foundAssemblyName);

                assemblyName = new AssemblyNameExtension("A, PublicKeyToken=a5d015c7d5a0b012, Culture=de-DE");
                foundAssemblyName = FrameworkPathResolver.GetHighestVersionInRedist(installedAssemblies, assemblyName);
                Assert.Equal(Av1, foundAssemblyName);

                assemblyName = new AssemblyNameExtension("A, Version=17.0.0.0, PublicKeyToken=a5d015c7d5a0b012, Culture=de-DE");
                foundAssemblyName = FrameworkPathResolver.GetHighestVersionInRedist(installedAssemblies, assemblyName);
                Assert.Equal(assemblyName, foundAssemblyName);
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        [Fact]
        [Trait("Category", "mono-osx-failing")]
        [Trait("Category", "mono-windows-failing")]
        public void Regress46599_BogusInGACValueForAssemblyInRedistList()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("Microsoft.Build.Engine"),
                new TaskItem("System.Xml")
            };

            t.SearchPaths = new string[]
            {
                @"{TargetFrameworkDirectory}"
            };
            t.TargetFrameworkDirectories = new string[] { @"r:\WINDOWS\Microsoft.NET\Framework\v2.0.myfx" };

            FileExists cachedFileExists = fileExists;
            GetAssemblyName cachedGetAssemblyName = getAssemblyName;
            string redistFile = CreateGenericRedistList();

            bool success = false;
            try
            {
                fileExists = new FileExists(delegate (string path)
                {
                    if (String.Equals(path, @"r:\WINDOWS\Microsoft.NET\Framework\v2.0.myfx\Microsoft.Build.Engine.dll", StringComparison.OrdinalIgnoreCase) ||
                        String.Equals(path, @"r:\WINDOWS\Microsoft.NET\Framework\v2.0.myfx\System.Xml.dll", StringComparison.OrdinalIgnoreCase) ||
                        path.EndsWith("RarCache", StringComparison.OrdinalIgnoreCase))
                    {
                        return true;
                    }
                    return false;
                });
                t.InstalledAssemblyTables = new ITaskItem[] { new TaskItem(redistFile) };

                success = Execute(t);
            }
            finally
            {
                fileExists = cachedFileExists;
                getAssemblyName = cachedGetAssemblyName;
                File.Delete(redistFile);
            }

            Assert.True(success); // "Expected no errors."
            Assert.Equal(2, t.ResolvedFiles.Length); // "Expected two resolved assemblies."
        }

        [Fact]
        [Trait("Category", "mono-osx-failing")]
        [Trait("Category", "mono-windows-failing")]
        public void VerifyFrameworkFileMetadataFiles()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                // In framework directory and redist, should have metadata
                new TaskItem("Microsoft.Build.Engine"),
                new TaskItem("System.Xml"),
                // In framework directory, should have metadata
                new TaskItem("B"),
                // Not in framework directory but in redist, should have metadata
                new TaskItem("C"),
                // Not in framework directory and not in redist, should not have metadata
                new TaskItem("D")
            };

            t.SearchPaths = new string[]
            {
                @"{TargetFrameworkDirectory}",
                @"c:\Somewhere\"
            };
            t.TargetFrameworkDirectories = new string[] { @"r:\WINDOWS\Microsoft.NET\Framework\v2.0.myfx" };

            FileExists cachedFileExists = fileExists;
            GetAssemblyName cachedGetAssemblyName = getAssemblyName;

            // Create a redist list which will contains both of the assemblies to search for
            string redistListContents =
                    "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                        "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                         "<File AssemblyName='Microsoft.Build.Engine' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                         "<File AssemblyName='C' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                    "</FileList >";

            string redistFile = FileUtilities.GetTemporaryFile();
            File.WriteAllText(redistFile, redistListContents);

            bool success = false;
            try
            {
                fileExists = new FileExists(delegate (string path)
                {
                    if (String.Equals(path, @"r:\WINDOWS\Microsoft.NET\Framework\v2.0.myfx\Microsoft.Build.Engine.dll", StringComparison.OrdinalIgnoreCase) ||
                        String.Equals(path, @"r:\WINDOWS\Microsoft.NET\Framework\v2.0.myfx\System.Xml.dll", StringComparison.OrdinalIgnoreCase) ||
                        String.Equals(path, @"r:\WINDOWS\Microsoft.NET\Framework\v2.0.myfx\B.dll", StringComparison.OrdinalIgnoreCase) ||
                        String.Equals(path, @"c:\somewhere\c.dll", StringComparison.OrdinalIgnoreCase) ||
                        String.Equals(path, @"c:\somewhere\d.dll", StringComparison.OrdinalIgnoreCase) ||
                        path.EndsWith("RarCache", StringComparison.OrdinalIgnoreCase))
                    {
                        return true;
                    }
                    return false;
                });

                getAssemblyName = new GetAssemblyName(delegate (string path)
                {
                    if (String.Equals(path, @"r:\WINDOWS\Microsoft.NET\Framework\v2.0.myfx\B.dll", StringComparison.OrdinalIgnoreCase))
                    {
                        return new AssemblyNameExtension("B, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
                    }

                    if (String.Equals(path, @"c:\somewhere\d.dll", StringComparison.OrdinalIgnoreCase))
                    {
                        return new AssemblyNameExtension("D, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
                    }

                    return null;
                });
                t.InstalledAssemblyTables = new ITaskItem[] { new TaskItem(redistFile) };

                success = Execute(t);
            }
            finally
            {
                fileExists = cachedFileExists;
                getAssemblyName = cachedGetAssemblyName;
                File.Delete(redistFile);
            }

            Assert.True(success); // "Expected no errors."
            Assert.Equal(5, t.ResolvedFiles.Length); // "Expected two resolved assemblies."
            Assert.Equal("True", t.ResolvedFiles.Where(Item => Item.GetMetadata("OriginalItemSpec").Equals("Microsoft.Build.Engine", StringComparison.OrdinalIgnoreCase)).First().GetMetadata("FrameworkFile"), true);
            Assert.Equal("True", t.ResolvedFiles.Where(Item => Item.GetMetadata("OriginalItemSpec").Equals("System.Xml", StringComparison.OrdinalIgnoreCase)).First().GetMetadata("FrameworkFile"), true);
            Assert.Equal("True", t.ResolvedFiles.Where(Item => Item.GetMetadata("OriginalItemSpec").Equals("B", StringComparison.OrdinalIgnoreCase)).First().GetMetadata("FrameworkFile"), true);
            Assert.Equal("True", t.ResolvedFiles.Where(Item => Item.GetMetadata("OriginalItemSpec").Equals("C", StringComparison.OrdinalIgnoreCase)).First().GetMetadata("FrameworkFile"), true);
            Assert.Empty(t.ResolvedFiles.Where(Item => Item.GetMetadata("OriginalItemSpec").Equals("D", StringComparison.OrdinalIgnoreCase)).First().GetMetadata("FrameworkFile"));
        }

        /// <summary>
        /// Create a redist file which is used by many different tests
        /// </summary>
        /// <returns>Path to the redist list</returns>
        private static string CreateGenericRedistList()
        {
            // Create a redist list which will contains both of the assemblies to search for
            string redistListContents =
                    "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                        "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                        "<File AssemblyName='Microsoft.Build.Engine' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                    "</FileList >";

            string tempFile = FileUtilities.GetTemporaryFile();
            File.WriteAllText(tempFile, redistListContents);
            return tempFile;
        }

        [Fact]
        public void GetRedistListPathsFromDisk_ThrowsArgumentNullException()
        {
            bool caughtArgumentNullException = false;

            try
            {
                RedistList.GetRedistListPathsFromDisk(null);
            }
            catch (ArgumentNullException)
            {
                caughtArgumentNullException = true;
            }

            Assert.True(caughtArgumentNullException); // "Public method RedistList.GetRedistListPathsFromDisk should throw ArgumentNullException when its argument is null!"
        }

        /// <summary>
        /// Test the case where the redist list is empty and we pass in an empty set of white lists
        /// We should return null as there is no point generating a white list if there is nothing to subtract from.
        /// ResolveAssemblyReference will see this as null and log a warning indicating no redist assemblies were found therefore no black list could be
        /// generated
        /// </summary>
        [Fact]
        public void RedistListGenerateBlackListEmptyAssemblyInfoNoRedistAssemblies()
        {
            RedistList redistList = RedistList.GetRedistList(new AssemblyTableInfo[0]);
            List<Exception> whiteListErrors = new List<Exception>();
            List<string> whiteListErrorFileNames = new List<string>();
            Dictionary<string, string> blackList = redistList.GenerateBlackList(new AssemblyTableInfo[0], whiteListErrors, whiteListErrorFileNames);
            Assert.Null(blackList); // "Should return null if the AssemblyTableInfo is empty and the redist list is empty"
        }

        /// <summary>
        /// Verify that when we go to generate a black list but there were no subset list files passed in that we get NO black list generated as there is nothing to subtract.
        /// Nothing meaning, we don't have any matching subset list files to say there are no good files.
        /// </summary>
        [Fact]
        public void RedistListGenerateBlackListEmptyAssemblyInfoWithRedistAssemblies()
        {
            string redistFile = CreateGenericRedistList();
            try
            {
                AssemblyTableInfo redistListInfo = new AssemblyTableInfo(redistFile, "TargetFrameworkDirectory");
                RedistList redistList = RedistList.GetRedistList(new AssemblyTableInfo[] { redistListInfo });
                List<Exception> whiteListErrors = new List<Exception>();
                List<string> whiteListErrorFileNames = new List<string>();
                Dictionary<string, string> blackList = redistList.GenerateBlackList(new AssemblyTableInfo[0], whiteListErrors, whiteListErrorFileNames);

                // Since there were no white list expect the black list to return null
                Assert.Empty(blackList); // "Expected to have no assemblies in the black list"
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        /// <summary>
        /// Test the case where the subset lists cannot be read. The expectation is that the black list will be empty as we have no proper white lists to compare it to.
        /// </summary>
        [Fact]
        public void RedistListGenerateBlackListNotFoundSubsetFiles()
        {
            string redistFile = CreateGenericRedistList();
            try
            {
                AssemblyTableInfo redistListInfo = new AssemblyTableInfo(redistFile, "TargetFrameworkDirectory");
                RedistList redistList = RedistList.GetRedistList(new AssemblyTableInfo[] { redistListInfo });
                List<Exception> whiteListErrors = new List<Exception>();
                List<string> whiteListErrorFileNames = new List<string>();

                Dictionary<string, string> blackList = redistList.GenerateBlackList(
                                                                   new AssemblyTableInfo[]
                                                                                         {
                                                                                           new AssemblyTableInfo("c:\\RandomDirectory.xml", "TargetFrameworkDirectory"),
                                                                                           new AssemblyTableInfo("c:\\AnotherRandomDirectory.xml", "TargetFrameworkDirectory")
                                                                                          },
                                                                                          whiteListErrors,
                                                                                          whiteListErrorFileNames
                                                                   );

                // Since there were no white list expect the black list to return null
                Assert.Empty(blackList); // "Expected to have no assemblies in the black list"
                Assert.Equal(2, whiteListErrors.Count); // "Expected there to be two errors in the whiteListErrors, one for each missing file"
                Assert.Equal(2, whiteListErrorFileNames.Count); // "Expected there to be two errors in the whiteListErrorFileNames, one for each missing file"
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        /// <summary>
        /// Test the case where there is random goo in the subsetList file. Expect the file to not be read in and a warning indicating the file was skipped due to a read error.
        /// This should also cause the white list to be empty as the badly formatted file was the only whitelist subset file.
        /// </summary>
        [Fact]
        public void RedistListGenerateBlackListGarbageSubsetListFiles()
        {
            string redistFile = CreateGenericRedistList();
            string garbageSubsetFile = FileUtilities.GetTemporaryFile();
            try
            {
                File.WriteAllText
                (
                    garbageSubsetFile,
                    "RandomGarbage, i am a bad file with random goo rather than anything important"
                 );

                AssemblyTableInfo redistListInfo = new AssemblyTableInfo(redistFile, "TargetFrameworkDirectory");
                AssemblyTableInfo subsetListInfo = new AssemblyTableInfo(garbageSubsetFile, "TargetFrameworkDirectory");
                RedistList redistList = RedistList.GetRedistList(new AssemblyTableInfo[] { redistListInfo });
                List<Exception> whiteListErrors = new List<Exception>();
                List<string> whiteListErrorFileNames = new List<string>();
                Dictionary<string, string> blackList = redistList.GenerateBlackList(new AssemblyTableInfo[] { subsetListInfo }, whiteListErrors, whiteListErrorFileNames);

                Assert.Empty(blackList); // "Expected to have no assemblies in the black list"
                Assert.Single(whiteListErrors); // "Expected there to be an error in the whiteListErrors"
                Assert.Single(whiteListErrorFileNames); // "Expected there to be an error in the whiteListErrorFileNames"
                Assert.DoesNotContain("MSB3257", ((Exception)whiteListErrors[0]).Message); // "Expect to not have the null redist warning"
            }
            finally
            {
                File.Delete(redistFile);
                File.Delete(garbageSubsetFile);
            }
        }

        /// <summary>
        /// Inputs:
        ///     Redist list which has entries and has a redist name
        ///     Subset list which has no redist name but has entries
        ///
        /// Expected:
        ///     Expect a warning that a redist list or subset list has no redist name.
        ///     There should be no black list generated as no sub set lists were read in.
        ///
        /// Rational:
        ///     If we have no redist name to compare to the redist list redist name we cannot subtract the lists correctly.
        /// </summary>
        [Fact]
        public void RedistListNoSubsetListName()
        {
            string redistFile = CreateGenericRedistList();
            string subsetFile = FileUtilities.GetTemporaryFile();
            try
            {
                string subsetListContents =
                   "<FileList>" +
                       "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                        "<File AssemblyName='Microsoft.Build.Engine' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                   "</FileList >";
                File.WriteAllText(subsetFile, subsetListContents);

                AssemblyTableInfo redistListInfo = new AssemblyTableInfo(redistFile, "TargetFrameworkDirectory");
                AssemblyTableInfo subsetListInfo = new AssemblyTableInfo(subsetFile, "TargetFrameworkDirectory");
                RedistList redistList = RedistList.GetRedistList(new AssemblyTableInfo[] { redistListInfo });
                List<Exception> whiteListErrors = new List<Exception>();
                List<string> whiteListErrorFileNames = new List<string>();
                Dictionary<string, string> blackList = redistList.GenerateBlackList(new AssemblyTableInfo[] { subsetListInfo }, whiteListErrors, whiteListErrorFileNames);

                // If the names do not match then i expect there to be no black list items
                Assert.Empty(blackList); // "Expected to have no assembly in the black list"
                Assert.Single(whiteListErrors); // "Expected there to be one error in the whiteListErrors"
                Assert.Single(whiteListErrorFileNames); // "Expected there to be one error in the whiteListErrorFileNames"
                string message = ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveAssemblyReference.NoSubSetRedistListName", subsetFile);
                Assert.Contains(message, ((Exception)whiteListErrors[0]).Message); // "Expected assertion to contain correct error code"
            }
            finally
            {
                File.Delete(redistFile);
                File.Delete(subsetFile);
            }
        }

        /// <summary>
        /// Inputs:
        ///     Redist list which has entries but no redist name
        ///     Subset list which has a redist name and entries
        ///
        /// Expected:
        ///     Expect no black list to be generated and no warnings to be emitted
        ///
        /// Rational:
        ///     Since the redist list name is null or empty we have no way of matching any subset list up to it.
        /// </summary>
        [Fact]
        public void RedistListNullkRedistListName()
        {
            string redistFile = FileUtilities.GetTemporaryFile();
            string subsetFile = FileUtilities.GetTemporaryFile();
            try
            {
                string subsetListContents =
                   "<FileList Redist='MyRedistListFile'>" +
                       "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                        "<File AssemblyName='Microsoft.Build.Engine' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                   "</FileList >";
                File.WriteAllText(subsetFile, subsetListContents);

                string redistListContents =
                  "<FileList>" +
                      "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                       "<File AssemblyName='Microsoft.Build.Engine' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                  "</FileList >";
                File.WriteAllText(redistFile, redistListContents);

                AssemblyTableInfo redistListInfo = new AssemblyTableInfo(redistFile, "TargetFrameworkDirectory");
                AssemblyTableInfo subsetListInfo = new AssemblyTableInfo(subsetFile, "TargetFrameworkDirectory");
                RedistList redistList = RedistList.GetRedistList(new AssemblyTableInfo[] { redistListInfo });
                List<Exception> whiteListErrors = new List<Exception>();
                List<string> whiteListErrorFileNames = new List<string>();
                Dictionary<string, string> blackList = redistList.GenerateBlackList(new AssemblyTableInfo[] { subsetListInfo }, whiteListErrors, whiteListErrorFileNames);

                // If the names do not match then i expect there to be no black list items
                Assert.Empty(blackList); // "Expected to have no assembly in the black list"
                Assert.Empty(whiteListErrors); // "Expected there to be no errors in the whiteListErrors"
                Assert.Empty(whiteListErrorFileNames); // "Expected there to be no errors in the whiteListErrorFileNames"
            }
            finally
            {
                File.Delete(redistFile);
                File.Delete(subsetFile);
            }
        }

        /// <summary>
        /// Inputs:
        ///     Redist list which has entries and has a redist name
        ///     Subset list which has entries but has a different redist name than the redist list
        ///
        /// Expected:
        ///     There should be no black list generated as no sub set lists with matching names were found.
        ///
        /// Rational:
        ///     If the redist name does not match then that subset list should not be subtracted from the redist list.
        ///     We only add assemblies to the black list if there is a corosponding white list even if it is empty to inform us what assemblies are good and which are not.
        /// </summary>
        [Fact]
        public void RedistListDifferentNameToSubSet()
        {
            string redistFile = CreateGenericRedistList();
            string subsetFile = FileUtilities.GetTemporaryFile();
            try
            {
                string subsetListContents =
                   "<FileList Redist='IAMREALLYREALLYDIFFERNT' >" +
                       "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                        "<File AssemblyName='Microsoft.Build.Engine' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                   "</FileList >";
                File.WriteAllText(subsetFile, subsetListContents);

                AssemblyTableInfo redistListInfo = new AssemblyTableInfo(redistFile, "TargetFrameworkDirectory");
                AssemblyTableInfo subsetListInfo = new AssemblyTableInfo(subsetFile, "TargetFrameworkDirectory");
                RedistList redistList = RedistList.GetRedistList(new AssemblyTableInfo[] { redistListInfo });
                List<Exception> whiteListErrors = new List<Exception>();
                List<string> whiteListErrorFileNames = new List<string>();
                Dictionary<string, string> blackList = redistList.GenerateBlackList(new AssemblyTableInfo[] { subsetListInfo }, whiteListErrors, whiteListErrorFileNames);

                // If the names do not match then i expect there to be no black list items
                Assert.Empty(blackList); // "Expected to have no assembly in the black list"
                Assert.Empty(whiteListErrors); // "Expected there to be no error in the whiteListErrors"
                Assert.Empty(whiteListErrorFileNames); // "Expected there to be no error in the whiteListErrorFileNames"
            }
            finally
            {
                File.Delete(redistFile);
                File.Delete(subsetFile);
            }
        }

        /// <summary>
        /// Test the case where the subset list has the same name as the redist list but it has no entries In this case
        /// the black list should contain ALL redist list entries because there are no white list files to remove from the black list.
        /// </summary>
        [Fact]
        public void RedistListEmptySubsetMatchingName()
        {
            string redistFile = CreateGenericRedistList();
            string subsetFile = FileUtilities.GetTemporaryFile();
            try
            {
                string subsetListContents =
                    "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                   "</FileList >";
                File.WriteAllText(subsetFile, subsetListContents);

                AssemblyTableInfo redistListInfo = new AssemblyTableInfo(redistFile, "TargetFrameworkDirectory");
                AssemblyTableInfo subsetListInfo = new AssemblyTableInfo(subsetFile, "TargetFrameworkDirectory");
                RedistList redistList = RedistList.GetRedistList(new AssemblyTableInfo[] { redistListInfo });
                List<Exception> whiteListErrors = new List<Exception>();
                List<string> whiteListErrorFileNames = new List<string>();
                Dictionary<string, string> blackList = redistList.GenerateBlackList(new AssemblyTableInfo[] { subsetListInfo }, whiteListErrors, whiteListErrorFileNames);

                // If the names do not match then i expect there to be no black list items
                Assert.Equal(2, blackList.Count); // "Expected to have two assembly in the black list"
                Assert.Empty(whiteListErrors); // "Expected there to be no error in the whiteListErrors"
                Assert.Empty(whiteListErrorFileNames); // "Expected there to be no error in the whiteListErrorFileNames"

                ArrayList whiteListErrors2 = new ArrayList();
                ArrayList whiteListErrorFileNames2 = new ArrayList();
                Dictionary<string, string> blackList2 = redistList.GenerateBlackList(new AssemblyTableInfo[] { subsetListInfo }, whiteListErrors, whiteListErrorFileNames);
                Assert.Same(blackList, blackList2);
            }
            finally
            {
                File.Delete(redistFile);
                File.Delete(subsetFile);
            }
        }

        /// <summary>
        /// Test the case where, no redist assemblies are read in.
        /// In this case no blacklist can be generated.
        /// We should get a warning informing us that we could not create a black list.
        /// </summary>
        [Fact]
        public void RedistListNoAssembliesinRedistList()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            string microsoftBuildEnginePath = Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5\\Microsoft.Build.Engine.dll");
            string systemXmlPath = Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5\\System.Xml.dll");
            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("Microsoft.Build.Engine"),
                new TaskItem("System.Xml")
            };

            t.SearchPaths = new string[]
            {
                @"{TargetFrameworkDirectory}"
            };

            string redistListPath = FileUtilities.GetTemporaryFile();
            string subsetListPath = FileUtilities.GetTemporaryFile();
            File.WriteAllText(subsetListPath, _xmlOnlySubset);
            try
            {
                File.WriteAllText
                (
                    redistListPath,
                   "RANDOMBOOOOOGOOGOOG"
                );

                t.InstalledAssemblyTables = new ITaskItem[] { new TaskItem(redistListPath) };
                t.IgnoreDefaultInstalledAssemblyTables = true;
                t.InstalledAssemblySubsetTables = new ITaskItem[] { new TaskItem(subsetListPath) };

                Execute(t);
                MockEngine engine = (MockEngine)t.BuildEngine;
                engine.AssertLogContains(t.Log.FormatResourceString("ResolveAssemblyReference.NoRedistAssembliesToGenerateExclusionList"));
            }
            finally
            {
                File.Delete(redistListPath);
                File.Delete(subsetListPath);
            }
        }

        /// <summary>
        /// Test the case where the subset list is a subset of the redist list. Make sure that
        /// even though there are two files in the redist list that only one shows up in the black list.
        /// </summary>
        [Fact]
        public void RedistListGenerateBlackListGoodListsSubsetIsSubsetOfRedist()
        {
            string redistFile = CreateGenericRedistList(); 
            string goodSubsetFile = FileUtilities.GetTemporaryFile();
            try
            {
                File.WriteAllText(goodSubsetFile, _engineOnlySubset);

                AssemblyTableInfo redistListInfo = new AssemblyTableInfo(redistFile, "TargetFrameworkDirectory");
                AssemblyTableInfo subsetListInfo = new AssemblyTableInfo(goodSubsetFile, "TargetFrameworkDirectory");
                RedistList redistList = RedistList.GetRedistList(new AssemblyTableInfo[] { redistListInfo });
                List<Exception> whiteListErrors = new List<Exception>();
                List<string> whiteListErrorFileNames = new List<string>();
                Dictionary<string, string> blackList = redistList.GenerateBlackList(new AssemblyTableInfo[] { subsetListInfo }, whiteListErrors, whiteListErrorFileNames);

                Assert.Single(blackList); // "Expected to have one assembly in the black list"
                Assert.True(blackList.ContainsKey("System.Xml, Version=2.0.0.0, Culture=Neutral, PublicKeyToken=<KEY>")); // "Expected System.xml to be in the black list"
                Assert.Empty(whiteListErrors); // "Expected there to be no error in the whiteListErrors"
                Assert.Empty(whiteListErrorFileNames); // "Expected there to be no error in the whiteListErrorFileNames"
            }
            finally
            {
                File.Delete(redistFile);
                File.Delete(goodSubsetFile);
            }
        }

        /// <summary>
        /// Test the case where we generate a black list based on a set of subset file paths, and then ask for
        /// another black list using the same file paths. We expect to get the exact same Dictionary out
        /// as it should be pulled from the cache.
        /// </summary>
        [Fact]
        public void RedistListGenerateBlackListVerifyBlackListCache()
        {
            string redistFile = CreateGenericRedistList();
            string goodSubsetFile = FileUtilities.GetTemporaryFile();
            try
            {
                File.WriteAllText(goodSubsetFile, _engineOnlySubset);

                AssemblyTableInfo redistListInfo = new AssemblyTableInfo(redistFile, "TargetFrameworkDirectory");
                AssemblyTableInfo subsetListInfo = new AssemblyTableInfo(goodSubsetFile, "TargetFrameworkDirectory");
                RedistList redistList = RedistList.GetRedistList(new AssemblyTableInfo[] { redistListInfo });
                List<Exception> whiteListErrors = new List<Exception>();
                List<string> whiteListErrorFileNames = new List<string>();
                Dictionary<string, string> blackList = redistList.GenerateBlackList(new AssemblyTableInfo[] { subsetListInfo }, whiteListErrors, whiteListErrorFileNames);

                // Since there were no white list expect the black list to return null
                Assert.Single(blackList); // "Expected to have one assembly in the black list"
                Assert.True(blackList.ContainsKey("System.Xml, Version=2.0.0.0, Culture=Neutral, PublicKeyToken=<KEY>")); // "Expected System.xml to be in the black list"
                Assert.Empty(whiteListErrors); // "Expected there to be no error in the whiteListErrors"
                Assert.Empty(whiteListErrorFileNames); // "Expected there to be no error in the whiteListErrorFileNames"

                List<Exception> whiteListErrors2 = new List<Exception>();
                List<string> whiteListErrorFileNames2 = new List<string>();
                Dictionary<string, string> blackList2 = redistList.GenerateBlackList(new AssemblyTableInfo[] { subsetListInfo }, whiteListErrors2, whiteListErrorFileNames2);
                Assert.Same(blackList, blackList2);
            }
            finally
            {
                File.Delete(redistFile);
                File.Delete(goodSubsetFile);
            }
        }

        /// <summary>
        /// Test the case where the white list and the redist list are identical
        /// In this case the black list should be empty.
        ///
        /// We are also in a way testing the combining of subset files as we read in one assembly from two
        /// different subset lists while the redist list already contains both assemblies.
        /// </summary>
        [Fact]
        public void RedistListGenerateBlackListGoodListsSubsetIsSameAsRedistList()
        {
            string redistFile = CreateGenericRedistList();
            string goodSubsetFile = FileUtilities.GetTemporaryFile();
            string goodSubsetFile2 = FileUtilities.GetTemporaryFile();
            try
            {
                File.WriteAllText(goodSubsetFile, _engineOnlySubset);
                File.WriteAllText(goodSubsetFile2, _xmlOnlySubset);

                AssemblyTableInfo redistListInfo = new AssemblyTableInfo(redistFile, "TargetFrameworkDirectory");
                AssemblyTableInfo subsetListInfo = new AssemblyTableInfo(goodSubsetFile, "TargetFrameworkDirectory");
                AssemblyTableInfo subsetListInfo2 = new AssemblyTableInfo(goodSubsetFile2, "TargetFrameworkDirectory");
                RedistList redistList = RedistList.GetRedistList(new AssemblyTableInfo[] { redistListInfo });

                List<Exception> whiteListErrors = new List<Exception>();
                List<string> whiteListErrorFileNames = new List<string>();
                Dictionary<string, string> blackList = redistList.GenerateBlackList(new AssemblyTableInfo[] { subsetListInfo, subsetListInfo2 }, whiteListErrors, whiteListErrorFileNames);
                // Since there were no white list expect the black list to return null
                Assert.Empty(blackList); // "Expected to have no assemblies in the black list"
                Assert.Empty(whiteListErrors); // "Expected there to be no error in the whiteListErrors"
                Assert.Empty(whiteListErrorFileNames); // "Expected there to be no error in the whiteListErrorFileNames"
            }
            finally
            {
                File.Delete(redistFile);
                File.Delete(goodSubsetFile);
            }
        }

        /// <summary>
        /// Test the case where the white list is a superset of the redist list.
        /// This means there are more assemblies in the white list than in the black list.
        ///
        /// The black list should be empty.
        /// </summary>
        [Fact]
        public void RedistListGenerateBlackListGoodListsSubsetIsSuperSet()
        {
            string redistFile = CreateGenericRedistList();
            string goodSubsetFile = FileUtilities.GetTemporaryFile();
            try
            {
                File.WriteAllText
                (
                    goodSubsetFile,
                  "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                       "<File AssemblyName='Microsoft.Build.Engine' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='false' />" +
                       "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                       "<File AssemblyName='System.Data' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                  "</FileList >"
                 );

                AssemblyTableInfo redistListInfo = new AssemblyTableInfo(redistFile, "TargetFrameworkDirectory");
                AssemblyTableInfo subsetListInfo = new AssemblyTableInfo(goodSubsetFile, "TargetFrameworkDirectory");
                RedistList redistList = RedistList.GetRedistList(new AssemblyTableInfo[] { redistListInfo });
                List<Exception> whiteListErrors = new List<Exception>();
                List<string> whiteListErrorFileNames = new List<string>();
                Dictionary<string, string> blackList = redistList.GenerateBlackList(new AssemblyTableInfo[] { subsetListInfo }, whiteListErrors, whiteListErrorFileNames);

                // Since there were no white list expect the black list to return null
                Assert.Empty(blackList); // "Expected to have no assemblies in the black list"
                Assert.Empty(whiteListErrors); // "Expected there to be no error in the whiteListErrors"
                Assert.Empty(whiteListErrorFileNames); // "Expected there to be no error in the whiteListErrorFileNames"
            }
            finally
            {
                File.Delete(redistFile);
                File.Delete(goodSubsetFile);
            }
        }

        /// <summary>
        /// Check to see if comparing the assemblies in the redist list to the ones in the subset
        /// list are case sensitive or not, they should not be case sensitive.
        /// </summary>
        [Fact]
        public void RedistListGenerateBlackListGoodListsCheckCaseInsensitive()
        {
            string redistFile = CreateGenericRedistList();
            string goodSubsetFile = FileUtilities.GetTemporaryFile();
            try
            {
                File.WriteAllText(goodSubsetFile, _engineAndXmlSubset.ToUpperInvariant());

                AssemblyTableInfo redistListInfo = new AssemblyTableInfo(redistFile, "TargetFrameworkDirectory");
                AssemblyTableInfo subsetListInfo = new AssemblyTableInfo(goodSubsetFile, "TargetFrameworkDirectory");
                RedistList redistList = RedistList.GetRedistList(new AssemblyTableInfo[] { redistListInfo });
                List<Exception> whiteListErrors = new List<Exception>();
                List<string> whiteListErrorFileNames = new List<string>();
                Dictionary<string, string> blackList = redistList.GenerateBlackList(new AssemblyTableInfo[] { subsetListInfo }, whiteListErrors, whiteListErrorFileNames);

                // Since there were no white list expect the black list to return null
                Assert.Empty(blackList); // "Expected to have no assemblies in the black list"
                Assert.Empty(whiteListErrors); // "Expected there to be no error in the whiteListErrors"
                Assert.Empty(whiteListErrorFileNames); // "Expected there to be no error in the whiteListErrorFileNames"
            }
            finally
            {
                File.Delete(redistFile);
                File.Delete(goodSubsetFile);
            }
        }

        /// <summary>
        /// Verify that when we go to generate a black list but there were no subset list files passed in that we get NO black list generated as there is nothing to subtract.
        /// Nothing meaning, we don't have any matching subset list files to say there are no good files.
        /// </summary>
        [Fact]
        public void RedistListGenerateBlackListGoodListsMultipleIdenticalAssembliesInRedistList()
        {
            string redistFile = FileUtilities.GetTemporaryFile();
            string goodSubsetFile = FileUtilities.GetTemporaryFile();
            try
            {
                // Create a redist list which will contains both of the assemblies to search for
                string redistListContents =
                        "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                            "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                             "<File AssemblyName='Microsoft.Build.Engine' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                             "<File AssemblyName='Microsoft.Build.Engine' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                        "</FileList >";

                File.WriteAllText(redistFile, redistListContents);
                File.WriteAllText(goodSubsetFile, _engineAndXmlSubset);

                AssemblyTableInfo redistListInfo = new AssemblyTableInfo(redistFile, "TargetFrameworkDirectory");
                AssemblyTableInfo subsetListInfo = new AssemblyTableInfo(goodSubsetFile, "TargetFrameworkDirectory");
                RedistList redistList = RedistList.GetRedistList(new AssemblyTableInfo[] { redistListInfo });
                List<Exception> whiteListErrors = new List<Exception>();
                List<string> whiteListErrorFilesNames = new List<string>();
                Dictionary<string, string> blackList = redistList.GenerateBlackList(new AssemblyTableInfo[] { subsetListInfo }, whiteListErrors, whiteListErrorFilesNames);

                // Since there were no white list expect the black list to return null
                Assert.Empty(blackList); // "Expected to have no assemblies in the black list"
                Assert.Empty(whiteListErrors); // "Expected there to be no error in the whiteListErrors"
                Assert.Empty(whiteListErrorFilesNames); // "Expected there to be no error in the whiteListErrorFileNames"
            }
            finally
            {
                File.Delete(redistFile);
                File.Delete(goodSubsetFile);
            }
        }

        /// <summary>
        /// Test the case where the framework directory is passed in as null
        /// </summary>
        [Fact]
        public void SubsetListFinderNullFrameworkDirectory()
        {
            Assert.Throws<ArgumentNullException>(() =>
            {
                SubsetListFinder finder = new SubsetListFinder(new string[0]);
                finder.GetSubsetListPathsFromDisk(null);
            }
           );
        }
        /// <summary>
        /// Test the case where the subsetsToSearchFor are passed in as null
        /// </summary>
        [Fact]
        public void SubsetListFinderNullSubsetToSearchFor()
        {
            Assert.Throws<ArgumentNullException>(() =>
            {
                SubsetListFinder finder = new SubsetListFinder(null);
            }
           );
        }
        /// <summary>
        /// Test the case where the subsetsToSearchFor are an empty array
        /// </summary>
        [Fact]
        public void SubsetListFinderEmptySubsetToSearchFor()
        {
            SubsetListFinder finder = new SubsetListFinder(new string[0]);
            string[] returnArray = finder.GetSubsetListPathsFromDisk("FrameworkDirectory");
            Assert.Empty(returnArray); // "Expected the array returned to be 0 length"
        }

        /// <summary>
        /// Verify that the method will not crash if there are empty string array elements
        /// </summary>
        [Fact]
        public void SubsetListFinderVerifyEmptyInSubsetsToSearchFor()
        {
            // Verify the program will not crash when an empty string is passed in
            SubsetListFinder finder = new SubsetListFinder(new string[] { "Clent", string.Empty, "Bar" });
            string[] returnArray = finder.GetSubsetListPathsFromDisk("FrameworkDirectory");
            string[] returnArray2 = finder.GetSubsetListPathsFromDisk("FrameworkDirectory");

            Assert.Empty(returnArray);
            Assert.Equal(returnArray.Length, returnArray2.Length);
        }

        /// <summary>
        /// Verify when we have valid subset files and their names are in the subsets to search for that we correctly find the files
        /// </summary>
        [Fact]
        public void SubsetListFinderSubsetExists()
        {
            string frameworkDirectory = Path.Combine(ObjectModelHelpers.TempProjectDir, "SubsetListsTestExists");
            string subsetDirectory = Path.Combine(frameworkDirectory, SubsetListFinder.SubsetListFolder);
            string clientXml = Path.Combine(subsetDirectory, "Client.xml");
            string fooXml = Path.Combine(subsetDirectory, "Foo.xml");

            try
            {
                Directory.CreateDirectory(subsetDirectory);
                File.WriteAllText(clientXml, "Random File Contents");
                File.WriteAllText(fooXml, "Random File Contents");
                SubsetListFinder finder = new SubsetListFinder(new string[] { "Client", "Foo" });
                string[] returnArray = finder.GetSubsetListPathsFromDisk(frameworkDirectory);
                Assert.Contains("Client.xml", returnArray[0]); // "Expected first element to contain Client.xml"
                Assert.Contains("Foo.xml", returnArray[1]); // "Expected first element to contain Foo.xml"
                Assert.Equal(2, returnArray.Length); // "Expected there to be two elements in the array"
            }
            finally
            {
                FileUtilities.DeleteWithoutTrailingBackslash(frameworkDirectory, true);
            }
        }

        /// <summary>
        /// Verify that if there are files of the correct name but of the wrong extension that they are not found.
        /// </summary>
        [Fact]
        public void SubsetListFinderNullSubsetExistsButNotXml()
        {
            string frameworkDirectory = Path.Combine(ObjectModelHelpers.TempProjectDir, "SubsetListsTestExistsNotXml");
            string subsetDirectory = Path.Combine(frameworkDirectory, SubsetListFinder.SubsetListFolder);
            string clientXml = Path.Combine(subsetDirectory, "Clent.Notxml");
            string fooXml = Path.Combine(subsetDirectory, "Foo.Notxml");

            try
            {
                Directory.CreateDirectory(subsetDirectory);
                File.WriteAllText(clientXml, "Random File Contents");
                File.WriteAllText(fooXml, "Random File Contents");
                SubsetListFinder finder = new SubsetListFinder(new string[] { "Client", "Foo" });
                string[] returnArray = finder.GetSubsetListPathsFromDisk(frameworkDirectory);
                Assert.Empty(returnArray); // "Expected there to be two elements in the array"
            }
            finally
            {
                FileUtilities.DeleteWithoutTrailingBackslash(frameworkDirectory, true);
            }
        }

        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void IgnoreDefaultInstalledAssemblyTables()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("Microsoft.Build.Engine"),
                new TaskItem("System.Xml")
            };

            t.SearchPaths = new string[]
            {
                @"{TargetFrameworkDirectory}"
            };
            t.TargetFrameworkDirectories = new string[] { Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5") };

            string implicitRedistListContents =
                    "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                        "<File AssemblyName='Microsoft.Build.Engine' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                    "</FileList >";
            string implicitRedistListPath = ObjectModelHelpers.CreateFileInTempProjectDirectory("v3.5\\RedistList\\ImplicitList.xml", implicitRedistListContents);
            string microsoftBuildEnginePath = Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5\\Microsoft.Build.Engine");

            string explicitRedistListContents =
                    "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                        "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                    "</FileList >";
            string explicitRedistListPath = ObjectModelHelpers.CreateFileInTempProjectDirectory("v3.5\\RedistList\\ExplicitList.xml", explicitRedistListContents);
            string systemXmlPath = Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5\\System.Xml.dll");

            t.InstalledAssemblyTables = new ITaskItem[] { new TaskItem(explicitRedistListPath) };

            // Only the explicitly specified redist list should be used
            t.IgnoreDefaultInstalledAssemblyTables = true;

            FileExists cachedFileExists = fileExists;
            GetAssemblyName cachedGetAssemblyName = getAssemblyName;

            fileExists = new FileExists(delegate (string path)
            {
                if (String.Equals(path, microsoftBuildEnginePath, StringComparison.OrdinalIgnoreCase) ||
                    String.Equals(path, systemXmlPath, StringComparison.OrdinalIgnoreCase) ||
                    path.EndsWith("RarCache", StringComparison.OrdinalIgnoreCase))
                {
                    return true;
                }
                return false;
            });

            getAssemblyName = new GetAssemblyName(delegate (string path)
            {
                if (String.Equals(path, microsoftBuildEnginePath, StringComparison.OrdinalIgnoreCase))
                {
                    return new AssemblyNameExtension("Microsoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
                }
                else if (String.Equals(path, systemXmlPath, StringComparison.OrdinalIgnoreCase))
                {
                    return new AssemblyNameExtension("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
                }

                return null;
            });

            bool success;
            try
            {
                success = Execute(t);
            }
            finally
            {
                fileExists = cachedFileExists;
                getAssemblyName = cachedGetAssemblyName;
            }

            Assert.True(success); // "Expected no errors."
            Assert.Single(t.ResolvedFiles); // "Expected one resolved assembly."
            Assert.Contains("System.Xml", t.ResolvedFiles[0].ItemSpec); // "Expected System.Xml to resolve."
        }

        /// <summary>
        /// A null black list should be the same as an empty one.
        /// </summary>
        [Fact]
        public void ReferenceTableNullBlackList()
        {
            TaskLoggingHelper log = new TaskLoggingHelper(new ResolveAssemblyReference());
            ReferenceTable referenceTable = MakeEmptyReferenceTable(log);
            Dictionary<AssemblyNameExtension, Reference> table = referenceTable.References;

            AssemblyNameExtension engineAssemblyName = new AssemblyNameExtension("Microsoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension xmlAssemblyName = new AssemblyNameExtension("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");

            table.Add(engineAssemblyName, new Reference(isWinMDFile, fileExists, getRuntimeVersion));
            table.Add(xmlAssemblyName, new Reference(isWinMDFile, fileExists, getRuntimeVersion));

            referenceTable.MarkReferencesForExclusion(null);
            referenceTable.RemoveReferencesMarkedForExclusion(false, String.Empty);
            Dictionary<AssemblyNameExtension, Reference> table2 = referenceTable.References;
            Assert.False(Object.ReferenceEquals(table, table2)); // "Expected Dictionary to be a different instance"
            Assert.Equal(2, table2.Count); // "Expected there to be two elements in the Dictionary"
            Assert.True(table2.ContainsKey(engineAssemblyName)); // "Expected to find the engineAssemblyName in the referenceList"
            Assert.True(table2.ContainsKey(xmlAssemblyName)); // "Expected to find the xmlssemblyName in the referenceList"
        }

        /// <summary>
        /// Test the case where the blacklist is empty.
        /// </summary>
        [Fact]
        public void ReferenceTableEmptyBlackList()
        {
            TaskLoggingHelper log = new TaskLoggingHelper(new ResolveAssemblyReference());
            ReferenceTable referenceTable = MakeEmptyReferenceTable(log);
            Dictionary<AssemblyNameExtension, Reference> table = referenceTable.References;

            AssemblyNameExtension engineAssemblyName = new AssemblyNameExtension("Microsoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension xmlAssemblyName = new AssemblyNameExtension("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");

            table.Add(engineAssemblyName, new Reference(isWinMDFile, fileExists, getRuntimeVersion));
            table.Add(xmlAssemblyName, new Reference(isWinMDFile, fileExists, getRuntimeVersion));

            referenceTable.MarkReferencesForExclusion(new Dictionary<string, string>());
            referenceTable.RemoveReferencesMarkedForExclusion(false, String.Empty);
            Dictionary<AssemblyNameExtension, Reference> table2 = referenceTable.References;
            Assert.False(Object.ReferenceEquals(table, table2)); // "Expected Dictionary to be a different instance"
            Assert.Equal(2, table2.Count); // "Expected there to be two elements in the Dictionary"
            Assert.True(table2.ContainsKey(engineAssemblyName)); // "Expected to find the engineAssemblyName in the referenceList"
            Assert.True(table2.ContainsKey(xmlAssemblyName)); // "Expected to find the xmlssemblyName in the referenceList"
        }

        /// <summary>
        /// Verify the case where there are primary references in the reference table which are also in the black list
        /// </summary>
        [Fact]
        public void ReferenceTablePrimaryItemInBlackList()
        {
            MockEngine mockEngine = new MockEngine(_output);
            ResolveAssemblyReference rar = new ResolveAssemblyReference();
            rar.BuildEngine = mockEngine;

            ReferenceTable referenceTable = MakeEmptyReferenceTable(rar.Log);
            Dictionary<AssemblyNameExtension, Reference> table = referenceTable.References;

            AssemblyNameExtension engineAssemblyName = new AssemblyNameExtension("Microsoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension xmlAssemblyName = new AssemblyNameExtension("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");

            Reference reference = new Reference(isWinMDFile, fileExists, getRuntimeVersion);
            TaskItem taskItem = new TaskItem("Microsoft.Build.Engine");
            reference.MakePrimaryAssemblyReference(taskItem, false, ".dll");
            table.Add(engineAssemblyName, reference);
            table.Add(xmlAssemblyName, new Reference(isWinMDFile, fileExists, getRuntimeVersion));

            var blackList = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            blackList[engineAssemblyName.FullName] = null;
            string[] targetFrameworks = new string[] { "Client", "Web" };
            string subSetName = ResolveAssemblyReference.GenerateSubSetName(targetFrameworks, null);

            referenceTable.MarkReferencesForExclusion(blackList);
            referenceTable.RemoveReferencesMarkedForExclusion(false, subSetName);

            Dictionary<AssemblyNameExtension, Reference> table2 = referenceTable.References;
            string warningMessage = rar.Log.FormatResourceString("ResolveAssemblyReference.FailedToResolveReferenceBecausePrimaryAssemblyInExclusionList", taskItem.ItemSpec, subSetName);
            Assert.False(Object.ReferenceEquals(table, table2)); // "Expected dictionary to be a different instance"
            Assert.Single(table2); // "Expected there to be one elements in the dictionary"
            Assert.False(table2.ContainsKey(engineAssemblyName)); // "Expected to not find the engineAssemblyName in the referenceList"
            Assert.True(table2.ContainsKey(xmlAssemblyName)); // "Expected to find the xmlssemblyName in the referenceList"
            mockEngine.AssertLogContains(warningMessage);
        }

        /// <summary>
        /// Verify the case where there are primary references in the reference table which are also in the black list
        /// </summary>
        [Fact]
        public void ReferenceTablePrimaryItemInBlackListSpecificVersionTrue()
        {
            MockEngine mockEngine = new MockEngine(_output);
            ResolveAssemblyReference rar = new ResolveAssemblyReference();
            rar.BuildEngine = mockEngine;

            ReferenceTable referenceTable = MakeEmptyReferenceTable(rar.Log);
            Dictionary<AssemblyNameExtension, Reference> table = referenceTable.References;

            AssemblyNameExtension engineAssemblyName = new AssemblyNameExtension("Microsoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension xmlAssemblyName = new AssemblyNameExtension("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");

            Reference reference = new Reference(isWinMDFile, fileExists, getRuntimeVersion);
            TaskItem taskItem = new TaskItem("Microsoft.Build.Engine");
            taskItem.SetMetadata("SpecificVersion", "true");
            reference.MakePrimaryAssemblyReference(taskItem, true, ".dll");
            table.Add(engineAssemblyName, reference);
            table.Add(xmlAssemblyName, new Reference(isWinMDFile, fileExists, getRuntimeVersion));

            var blackList = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            blackList[engineAssemblyName.FullName] = null;
            string[] targetFrameworks = new string[] { "Client", "Web" };
            string subSetName = ResolveAssemblyReference.GenerateSubSetName(targetFrameworks, null);
            referenceTable.MarkReferencesForExclusion(blackList);
            referenceTable.RemoveReferencesMarkedForExclusion(false, subSetName);

            Dictionary<AssemblyNameExtension, Reference> table2 = referenceTable.References;
            string warningMessage = rar.Log.FormatResourceString("ResolveAssemblyReference.FailedToResolveReferenceBecausePrimaryAssemblyInExclusionList", taskItem.ItemSpec, subSetName);
            Assert.False(Object.ReferenceEquals(table, table2)); // "Expected dictionary to be a different instance"
            Assert.Equal(2, table2.Count); // "Expected there to be two elements in the dictionary"
            Assert.True(table2.ContainsKey(engineAssemblyName)); // "Expected to find the engineAssemblyName in the referenceList"
            Assert.True(table2.ContainsKey(xmlAssemblyName)); // "Expected to find the xmlssemblyName in the referenceList"
            mockEngine.AssertLogDoesntContain(warningMessage);
        }

        /// <summary>
        /// Verify the generation of the targetFrameworkSubSetName
        /// </summary>
        [Fact]
        public void TestGenerateFrameworkName()
        {
            string[] targetFrameworks = new string[] { "Client" };
            Assert.Equal("Client", ResolveAssemblyReference.GenerateSubSetName(targetFrameworks, null));

            targetFrameworks = new string[] { "Client", "Framework" };
            Assert.Equal("Client, Framework", ResolveAssemblyReference.GenerateSubSetName(targetFrameworks, null));

            targetFrameworks = new string[0];
            Assert.True(String.IsNullOrEmpty(ResolveAssemblyReference.GenerateSubSetName(targetFrameworks, null)));

            targetFrameworks = null;
            Assert.True(String.IsNullOrEmpty(ResolveAssemblyReference.GenerateSubSetName(targetFrameworks, null)));

            ITaskItem[] installedSubSetTable = new ITaskItem[] { new TaskItem("c:\\foo\\Client.xml") };
            Assert.Equal("Client", ResolveAssemblyReference.GenerateSubSetName(null, installedSubSetTable));

            installedSubSetTable = new ITaskItem[] { new TaskItem("c:\\foo\\Client.xml"), new TaskItem("D:\\foo\\bar\\Framework.xml") };
            Assert.Equal("Client, Framework", ResolveAssemblyReference.GenerateSubSetName(null, installedSubSetTable));

            installedSubSetTable = new ITaskItem[] { new TaskItem("c:\\foo\\Client.xml"), new TaskItem("D:\\foo\\bar\\Framework2\\"), new TaskItem("D:\\foo\\bar\\Framework"), new TaskItem("Nothing") };
            Assert.Equal("Client, Framework, Nothing", ResolveAssemblyReference.GenerateSubSetName(null, installedSubSetTable));

            installedSubSetTable = new ITaskItem[0];
            Assert.True(String.IsNullOrEmpty(ResolveAssemblyReference.GenerateSubSetName(null, installedSubSetTable)));

            installedSubSetTable = null;
            Assert.True(String.IsNullOrEmpty(ResolveAssemblyReference.GenerateSubSetName(null, installedSubSetTable)));

            targetFrameworks = new string[] { "Client", "Framework" };
            installedSubSetTable = new ITaskItem[] { new TaskItem("c:\\foo\\Mouse.xml"), new TaskItem("D:\\foo\\bar\\Man.xml") };
            Assert.Equal("Client, Framework, Mouse, Man", ResolveAssemblyReference.GenerateSubSetName(targetFrameworks, installedSubSetTable));
        }

        /// <summary>
        /// Verify the case where we just want to remove the references before conflict resolution and not print out the warning.
        /// </summary>
        [Fact]
        public void ReferenceTablePrimaryItemInBlackListRemoveOnlyNoWarn()
        {
            MockEngine mockEngine = new MockEngine(_output);
            ResolveAssemblyReference rar = new ResolveAssemblyReference();
            rar.BuildEngine = mockEngine;

            ReferenceTable referenceTable = MakeEmptyReferenceTable(rar.Log);
            Dictionary<AssemblyNameExtension, Reference> table = referenceTable.References;

            AssemblyNameExtension engineAssemblyName = new AssemblyNameExtension("Microsoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension xmlAssemblyName = new AssemblyNameExtension("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");

            Reference reference = new Reference(isWinMDFile, fileExists, getRuntimeVersion);
            TaskItem taskItem = new TaskItem("Microsoft.Build.Engine");
            reference.MakePrimaryAssemblyReference(taskItem, false, ".dll");
            table.Add(engineAssemblyName, reference);
            table.Add(xmlAssemblyName, new Reference(isWinMDFile, fileExists, getRuntimeVersion));

            var blackList = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            blackList[engineAssemblyName.FullName] = null;
            referenceTable.MarkReferencesForExclusion(blackList);
            referenceTable.RemoveReferencesMarkedForExclusion(true, String.Empty);

            Dictionary<AssemblyNameExtension, Reference> table2 = referenceTable.References;
            string subSetName = ResolveAssemblyReference.GenerateSubSetName(new string[] { }, null);
            string warningMessage = rar.Log.FormatResourceString("ResolveAssemblyReference.FailedToResolveReferenceBecausePrimaryAssemblyInExclusionList", taskItem.ItemSpec, subSetName);
            Assert.False(Object.ReferenceEquals(table, table2)); // "Expected dictionary to be a different instance"
            Assert.Single(table2); // "Expected there to be one elements in the dictionary"
            Assert.False(table2.ContainsKey(engineAssemblyName)); // "Expected to not find the engineAssemblyName in the referenceList"
            Assert.True(table2.ContainsKey(xmlAssemblyName)); // "Expected to find the xmlssemblyName in the referenceList"
            Assert.True(String.IsNullOrEmpty(mockEngine.Log));
        }

        /// <summary>
        /// Testing case  enginePrimary -> dataDependencyReference->sqlDependencyReference : sqlDependencyReference is in black list
        /// expect to see one dependency warning message
        /// </summary>
        [Fact]
        public void ReferenceTableDependentItemsInBlackList()
        {
            ReferenceTable referenceTable;
            MockEngine mockEngine;
            ResolveAssemblyReference rar;
            Dictionary<string, string> blackList;
            AssemblyNameExtension engineAssemblyName = new AssemblyNameExtension("Microsoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension dataAssemblyName = new AssemblyNameExtension("System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
            AssemblyNameExtension sqlclientAssemblyName = new AssemblyNameExtension("System.SqlClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension xmlAssemblyName = new AssemblyNameExtension("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            Reference enginePrimaryReference;
            Reference dataDependencyReference;
            Reference sqlDependencyReference;
            Reference xmlPrimaryReference;

            GenerateNewReferences(out enginePrimaryReference, out dataDependencyReference, out sqlDependencyReference, out xmlPrimaryReference);

            TaskItem taskItem = new TaskItem("Microsoft.Build.Engine");
            enginePrimaryReference.MakePrimaryAssemblyReference(taskItem, false, ".dll");
            enginePrimaryReference.FullPath = "FullPath";
            dataDependencyReference.MakeDependentAssemblyReference(enginePrimaryReference);
            dataDependencyReference.FullPath = "FullPath";
            sqlDependencyReference.MakeDependentAssemblyReference(dataDependencyReference);
            sqlDependencyReference.AddError(new Exception("CouldNotResolveSQLDependency"));
            xmlPrimaryReference.FullPath = "FullPath";
            xmlPrimaryReference.MakeDependentAssemblyReference(enginePrimaryReference);

            InitializeMockEngine(out referenceTable, out mockEngine, out rar);
            AddReferencesToReferenceTable(referenceTable, engineAssemblyName, dataAssemblyName, sqlclientAssemblyName, xmlAssemblyName, enginePrimaryReference, dataDependencyReference, sqlDependencyReference, xmlPrimaryReference);
            InitializeExclusionList(referenceTable, new AssemblyNameExtension[] { sqlclientAssemblyName }, out blackList);

            string subsetName = ResolveAssemblyReference.GenerateSubSetName(new string[] { "Client" }, null);
            string warningMessage = rar.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", taskItem.ItemSpec, sqlclientAssemblyName.FullName, subsetName);
            VerifyReferenceTable(referenceTable, mockEngine, engineAssemblyName, dataAssemblyName, sqlclientAssemblyName, xmlAssemblyName, new string[] { warningMessage });
        }

        /// <summary>
        /// Testing case  enginePrimary -> dataDependencyReference->sqlDependencyReference
        /// and enginePrimary->sqlDependencyReference: sqlDependencyReference is in black list
        /// and systemxml->enginePrimary
        /// expect to see one dependency warning message
        /// </summary>
        [Fact]
        public void ReferenceTableDependentItemsInBlackList2()
        {
            ReferenceTable referenceTable;
            MockEngine mockEngine;
            ResolveAssemblyReference rar;
            Dictionary<string, string> blackList;
            AssemblyNameExtension engineAssemblyName = new AssemblyNameExtension("Microsoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension dataAssemblyName = new AssemblyNameExtension("System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension sqlclientAssemblyName = new AssemblyNameExtension("System.SqlClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension xmlAssemblyName = new AssemblyNameExtension("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            Reference enginePrimaryReference;
            Reference dataDependencyReference;
            Reference sqlDependencyReference;
            Reference xmlPrimaryReference;

            GenerateNewReferences(out enginePrimaryReference, out dataDependencyReference, out sqlDependencyReference, out xmlPrimaryReference);

            ITaskItem taskItem = new TaskItem("Microsoft.Build.Engine");
            enginePrimaryReference.MakePrimaryAssemblyReference(taskItem, false, ".dll");
            enginePrimaryReference.FullPath = "FullPath";
            dataDependencyReference.FullPath = "FullPath";
            sqlDependencyReference.FullPath = "FullPath";
            xmlPrimaryReference.FullPath = "FullPath";
            dataDependencyReference.MakeDependentAssemblyReference(enginePrimaryReference);
            sqlDependencyReference.MakeDependentAssemblyReference(enginePrimaryReference);
            sqlDependencyReference.MakeDependentAssemblyReference(dataDependencyReference);
            xmlPrimaryReference.MakeDependentAssemblyReference(enginePrimaryReference);

            InitializeMockEngine(out referenceTable, out mockEngine, out rar);
            AddReferencesToReferenceTable(referenceTable, engineAssemblyName, dataAssemblyName, sqlclientAssemblyName, xmlAssemblyName, enginePrimaryReference, dataDependencyReference, sqlDependencyReference, xmlPrimaryReference);
            InitializeExclusionList(referenceTable, new AssemblyNameExtension[] { sqlclientAssemblyName }, out blackList);

            string subsetName = ResolveAssemblyReference.GenerateSubSetName(new string[] { "Client" }, null);
            string warningMessage = rar.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", taskItem.ItemSpec, sqlclientAssemblyName.FullName, subsetName);
            VerifyReferenceTable(referenceTable, mockEngine, engineAssemblyName, dataAssemblyName, sqlclientAssemblyName, xmlAssemblyName, new string[] { warningMessage });
        }

        /// <summary>
        /// Testing case  enginePrimary->XmlPrimary with XMLPrimary in the BL
        /// </summary>
        [Fact]
        public void ReferenceTablePrimaryToPrimaryDependencyWithOneInBlackList()
        {
            ReferenceTable referenceTable;
            MockEngine mockEngine;
            ResolveAssemblyReference rar;
            Dictionary<string, string> blackList;
            AssemblyNameExtension engineAssemblyName = new AssemblyNameExtension("Microsoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension xmlAssemblyName = new AssemblyNameExtension("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            Reference enginePrimaryReference = new Reference(isWinMDFile, fileExists, getRuntimeVersion);
            Reference xmlPrimaryReference = new Reference(isWinMDFile, fileExists, getRuntimeVersion);

            TaskItem taskItem = new TaskItem("Microsoft.Build.Engine");
            enginePrimaryReference.MakePrimaryAssemblyReference(taskItem, false, ".dll");
            enginePrimaryReference.FullPath = "FullPath";

            ITaskItem taskItem2 = new TaskItem("System.Xml");
            xmlPrimaryReference.FullPath = "FullPath";
            xmlPrimaryReference.MakePrimaryAssemblyReference(taskItem2, false, ".dll");
            // Make engine depend on xml primary when xml primary is a primary reference as well
            xmlPrimaryReference.AddSourceItems(enginePrimaryReference.GetSourceItems());
            xmlPrimaryReference.AddDependee(enginePrimaryReference);

            InitializeMockEngine(out referenceTable, out mockEngine, out rar);
            AddReferencesToReferenceTable(referenceTable, engineAssemblyName, null, null, xmlAssemblyName, enginePrimaryReference, null, null, xmlPrimaryReference);

            InitializeExclusionList(referenceTable, new AssemblyNameExtension[] { xmlAssemblyName }, out blackList);
            string subsetName = ResolveAssemblyReference.GenerateSubSetName(new string[] { "Client" }, null);
            string warningMessage = rar.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", taskItem.ItemSpec, xmlAssemblyName.FullName, subsetName);
            string warningMessage2 = rar.Log.FormatResourceString("ResolveAssemblyReference.FailedToResolveReferenceBecausePrimaryAssemblyInExclusionList", taskItem2.ItemSpec, subsetName);
            mockEngine.AssertLogContains(warningMessage);
            mockEngine.AssertLogContains(warningMessage2);

            Dictionary<AssemblyNameExtension, Reference> table = referenceTable.References;
            Assert.False(table.ContainsKey(xmlAssemblyName)); // "Expected to not find the xmlAssemblyName in the referenceList"
            Assert.False(table.ContainsKey(engineAssemblyName)); // "Expected to not find the engineAssemblyName in the referenceList"
        }

        /// <summary>
        /// Testing case  enginePrimary->XmlPrimary->dataDependency with dataDependency in the BL
        /// </summary>
        [Fact]
        public void ReferenceTablePrimaryToPrimaryToDependencyWithOneInBlackList()
        {
            ReferenceTable referenceTable;
            MockEngine mockEngine;
            ResolveAssemblyReference rar;
            Dictionary<string, string> blackList;
            AssemblyNameExtension engineAssemblyName = new AssemblyNameExtension("Microsoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension xmlAssemblyName = new AssemblyNameExtension("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension dataAssemblyName = new AssemblyNameExtension("System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            Reference enginePrimaryReference = new Reference(isWinMDFile, fileExists, getRuntimeVersion);
            Reference xmlPrimaryReference = new Reference(isWinMDFile, fileExists, getRuntimeVersion);
            Reference dataDependencyReference = new Reference(isWinMDFile, fileExists, getRuntimeVersion);

            TaskItem taskItem = new TaskItem("Microsoft.Build.Engine");
            enginePrimaryReference.MakePrimaryAssemblyReference(taskItem, false, ".dll");
            enginePrimaryReference.FullPath = "FullPath";

            ITaskItem taskItem2 = new TaskItem("System.Xml");
            xmlPrimaryReference.FullPath = "FullPath";
            xmlPrimaryReference.MakePrimaryAssemblyReference(taskItem2, false, ".dll");
            // Make engine depend on xml primary when xml primary is a primary reference as well
            xmlPrimaryReference.AddSourceItems(enginePrimaryReference.GetSourceItems());
            xmlPrimaryReference.AddDependee(enginePrimaryReference);

            dataDependencyReference.FullPath = "FullPath";
            dataDependencyReference.MakeDependentAssemblyReference(xmlPrimaryReference);

            InitializeMockEngine(out referenceTable, out mockEngine, out rar);
            AddReferencesToReferenceTable(referenceTable, engineAssemblyName, dataAssemblyName, null, xmlAssemblyName, enginePrimaryReference, dataDependencyReference, null, xmlPrimaryReference);

            InitializeExclusionList(referenceTable, new AssemblyNameExtension[] { dataAssemblyName }, out blackList);

            string subsetName = ResolveAssemblyReference.GenerateSubSetName(new string[] { "Client" }, null);
            string warningMessage = rar.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", taskItem.ItemSpec, dataAssemblyName.FullName, subsetName);
            string warningMessage2 = rar.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", taskItem2.ItemSpec, dataAssemblyName.FullName, subsetName);
            mockEngine.AssertLogContains(warningMessage);
            mockEngine.AssertLogContains(warningMessage2);

            Dictionary<AssemblyNameExtension, Reference> table = referenceTable.References;
            Assert.False(table.ContainsKey(xmlAssemblyName)); // "Expected to not find the xmlAssemblyName in the referenceList"
            Assert.False(table.ContainsKey(engineAssemblyName)); // "Expected to not find the engineAssemblyName in the referenceList"
            Assert.False(table.ContainsKey(dataAssemblyName)); // "Expected to not find the dataAssemblyName in the referenceList"
        }

        /// <summary>
        /// Testing case  enginePrimary -> dataDependencyReference->sqlDependencyReference
        /// and xmlPrimary->sqlDependencyReference: sqlDependencyReference is in black list
        /// expect to see one dependency warning message
        /// </summary>
        [Fact]
        public void ReferenceTableDependentItemsInBlackList3()
        {
            ReferenceTable referenceTable;
            MockEngine mockEngine;
            ResolveAssemblyReference rar;
            Dictionary<string, string> blackList;
            AssemblyNameExtension engineAssemblyName = new AssemblyNameExtension("Microsoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension dataAssemblyName = new AssemblyNameExtension("System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension sqlclientAssemblyName = new AssemblyNameExtension("System.SqlClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension xmlAssemblyName = new AssemblyNameExtension("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            Reference enginePrimaryReference;
            Reference dataDependencyReference;
            Reference sqlDependencyReference;
            Reference xmlPrimaryReference;

            GenerateNewReferences(out enginePrimaryReference, out dataDependencyReference, out sqlDependencyReference, out xmlPrimaryReference);

            ITaskItem taskItem = new TaskItem("Microsoft.Build.Engine");
            ITaskItem taskItem2 = new TaskItem("System.Xml");
            xmlPrimaryReference.MakePrimaryAssemblyReference(taskItem2, false, ".dll");
            enginePrimaryReference.MakePrimaryAssemblyReference(taskItem, false, ".dll");
            enginePrimaryReference.FullPath = "FullPath";
            dataDependencyReference.FullPath = "FullPath";
            xmlPrimaryReference.FullPath = "FullPath";
            sqlDependencyReference.FullPath = "FullPath";
            dataDependencyReference.MakeDependentAssemblyReference(enginePrimaryReference);
            sqlDependencyReference.MakeDependentAssemblyReference(xmlPrimaryReference);
            sqlDependencyReference.MakeDependentAssemblyReference(dataDependencyReference);

            InitializeMockEngine(out referenceTable, out mockEngine, out rar);
            AddReferencesToReferenceTable(referenceTable, engineAssemblyName, dataAssemblyName, sqlclientAssemblyName, xmlAssemblyName, enginePrimaryReference, dataDependencyReference, sqlDependencyReference, xmlPrimaryReference);

            InitializeExclusionList(referenceTable, new AssemblyNameExtension[] { sqlclientAssemblyName }, out blackList);

            string subsetName = ResolveAssemblyReference.GenerateSubSetName(new string[] { "Client" }, null);
            string warningMessage = rar.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", taskItem.ItemSpec, sqlclientAssemblyName.FullName, subsetName);
            string warningMessage2 = rar.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", taskItem2.ItemSpec, sqlclientAssemblyName.FullName, subsetName);
            VerifyReferenceTable(referenceTable, mockEngine, engineAssemblyName, dataAssemblyName, sqlclientAssemblyName, xmlAssemblyName, new string[] { warningMessage, warningMessage2 });
        }

        /// <summary>
        /// Testing case  enginePrimary -> dataDependencyReference->sqlDependencyReference
        /// and xmlPrimary->dataDependencyReference: sqlDependencyReference is in black list
        /// expect to see one dependency warning message
        /// </summary>
        [Fact]
        public void ReferenceTableDependentItemsInBlackList4()
        {
            ReferenceTable referenceTable = new ReferenceTable(null, false, false, false, false, new string[0], null, null, null, null, null, null, SystemProcessorArchitecture.None, fileExists, null, null, null,
#if FEATURE_WIN32_REGISTRY
                null, null, null,
#endif
                null, null, null, new Version("4.0"), null, null, null, true, false, null, null, false, null, WarnOrErrorOnTargetArchitectureMismatchBehavior.None, false, false, null);
            MockEngine mockEngine;
            ResolveAssemblyReference rar;
            Dictionary<string, string> blackList;
            AssemblyNameExtension engineAssemblyName = new AssemblyNameExtension("Microsoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension dataAssemblyName = new AssemblyNameExtension("System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension sqlclientAssemblyName = new AssemblyNameExtension("System.SqlClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension xmlAssemblyName = new AssemblyNameExtension("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            Reference enginePrimaryReference;
            Reference dataDependencyReference;
            Reference sqlDependencyReference;
            Reference xmlPrimaryReference;

            GenerateNewReferences(out enginePrimaryReference, out dataDependencyReference, out sqlDependencyReference, out xmlPrimaryReference);

            ITaskItem taskItem = new TaskItem("Microsoft.Build.Engine");
            ITaskItem taskItem2 = new TaskItem("System.Xml");
            xmlPrimaryReference.MakePrimaryAssemblyReference(taskItem2, false, ".dll");
            enginePrimaryReference.MakePrimaryAssemblyReference(taskItem, false, ".dll");
            enginePrimaryReference.FullPath = "FullPath";
            xmlPrimaryReference.FullPath = "FullPath";
            dataDependencyReference.FullPath = "FullPath";
            sqlDependencyReference.FullPath = "FullPath";
            dataDependencyReference.MakeDependentAssemblyReference(enginePrimaryReference);
            dataDependencyReference.MakeDependentAssemblyReference(xmlPrimaryReference);
            sqlDependencyReference.MakeDependentAssemblyReference(dataDependencyReference);

            InitializeMockEngine(out referenceTable, out mockEngine, out rar);
            AddReferencesToReferenceTable(referenceTable, engineAssemblyName, dataAssemblyName, sqlclientAssemblyName, xmlAssemblyName, enginePrimaryReference, dataDependencyReference, sqlDependencyReference, xmlPrimaryReference);

            InitializeExclusionList(referenceTable, new AssemblyNameExtension[] { sqlclientAssemblyName }, out blackList);

            string subsetName = ResolveAssemblyReference.GenerateSubSetName(new string[] { "Client" }, null);
            string warningMessage = rar.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", taskItem.ItemSpec, sqlclientAssemblyName.FullName, subsetName);
            string warningMessage2 = rar.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", taskItem2.ItemSpec, sqlclientAssemblyName.FullName, subsetName);
            VerifyReferenceTable(referenceTable, mockEngine, engineAssemblyName, dataAssemblyName, sqlclientAssemblyName, xmlAssemblyName, new string[] { warningMessage, warningMessage2 });
        }

        /// <summary>
        /// Testing case  enginePrimary -> dataDependencyReference->sqlDependencyReference
        /// enginePrimary -> dataDependencyReference
        /// xmlPrimaryReference ->DataDependency
        /// dataDependencyReference and sqlDependencyReference are in black list
        /// expect to see two dependency warning messages in the enginePrimaryCase and one in the xmlPrimarycase
        /// </summary>
        [Fact]
        public void ReferenceTableDependentItemsInBlackList5()
        {
            ReferenceTable referenceTable;
            MockEngine mockEngine;
            ResolveAssemblyReference rar;
            Dictionary<string, string> blackList;
            AssemblyNameExtension engineAssemblyName = new AssemblyNameExtension("Microsoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension dataAssemblyName = new AssemblyNameExtension("System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension sqlclientAssemblyName = new AssemblyNameExtension("System.SqlClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension xmlAssemblyName = new AssemblyNameExtension("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            Reference enginePrimaryReference;
            Reference dataDependencyReference;
            Reference sqlDependencyReference;
            Reference xmlPrimaryReference;

            GenerateNewReferences(out enginePrimaryReference, out dataDependencyReference, out sqlDependencyReference, out xmlPrimaryReference);

            ITaskItem taskItem = new TaskItem("Microsoft.Build.Engine");
            ITaskItem taskItem2 = new TaskItem("System.Xml");
            xmlPrimaryReference.MakePrimaryAssemblyReference(taskItem2, false, ".dll");
            enginePrimaryReference.MakePrimaryAssemblyReference(taskItem, false, ".dll");
            enginePrimaryReference.FullPath = "FullPath";
            xmlPrimaryReference.FullPath = "FullPath";
            dataDependencyReference.FullPath = "FullPath";
            sqlDependencyReference.FullPath = "FullPath";
            dataDependencyReference.MakeDependentAssemblyReference(enginePrimaryReference);
            sqlDependencyReference.MakeDependentAssemblyReference(enginePrimaryReference);
            dataDependencyReference.MakeDependentAssemblyReference(xmlPrimaryReference);

            InitializeMockEngine(out referenceTable, out mockEngine, out rar);
            AddReferencesToReferenceTable(referenceTable, engineAssemblyName, dataAssemblyName, sqlclientAssemblyName, xmlAssemblyName, enginePrimaryReference, dataDependencyReference, sqlDependencyReference, xmlPrimaryReference);

            InitializeExclusionList(referenceTable, new AssemblyNameExtension[] { sqlclientAssemblyName, dataAssemblyName }, out blackList);

            string subsetName = ResolveAssemblyReference.GenerateSubSetName(new string[] { "Client" }, null);
            string warningMessage = rar.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", taskItem.ItemSpec, sqlclientAssemblyName.FullName, subsetName);
            string warningMessage2 = rar.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", taskItem.ItemSpec, dataAssemblyName.FullName, subsetName);
            string warningMessage3 = rar.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", taskItem2.ItemSpec, dataAssemblyName.FullName, subsetName);

            Dictionary<AssemblyNameExtension, Reference> table = referenceTable.References;
            Assert.Empty(table); // "Expected there to be two elements in the dictionary"
            Assert.False(table.ContainsKey(sqlclientAssemblyName)); // "Expected to not find the sqlclientAssemblyName in the referenceList"
            Assert.False(table.ContainsKey(dataAssemblyName)); // "Expected to not to find the dataAssemblyName in the referenceList"
            Assert.False(table.ContainsKey(xmlAssemblyName)); // "Expected to find the xmlssemblyName in the referenceList"
            Assert.False(table.ContainsKey(engineAssemblyName)); // "Expected to find the engineAssemblyName in the referenceList"

            string[] warningMessages = new string[] { warningMessage, warningMessage2, warningMessage3 };
            foreach (string message in warningMessages)
            {
                Console.Out.WriteLine("WarningMessageToAssert:" + message);
                mockEngine.AssertLogContains(message);
            }
            table.Clear();
        }

        /// <summary>
        /// Testing case
        /// enginePrimary -> dataDependencyReference   also enginePrimary->sqlDependencyReference   specific version = true on the primary
        /// xmlPrimaryReference ->dataDependencyReference specific version = false on the primary
        /// dataDependencyReference and sqlDependencyReference is in the black list.
        /// Expect to see one dependency warning messages xmlPrimarycase and no message for enginePrimary
        /// Also expect to resolve all files except for xmlPrimaryReference
        /// </summary>
        [Fact]
        public void ReferenceTableDependentItemsInBlackListPrimaryWithSpecificVersion()
        {
            ReferenceTable referenceTable;
            MockEngine mockEngine;
            ResolveAssemblyReference rar;
            Dictionary<string, string> blackList;
            AssemblyNameExtension engineAssemblyName = new AssemblyNameExtension("Microsoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension dataAssemblyName = new AssemblyNameExtension("System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension sqlclientAssemblyName = new AssemblyNameExtension("System.SqlClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            AssemblyNameExtension xmlAssemblyName = new AssemblyNameExtension("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
            Reference enginePrimaryReference;
            Reference dataDependencyReference;
            Reference sqlDependencyReference;
            Reference xmlPrimaryReference;

            GenerateNewReferences(out enginePrimaryReference, out dataDependencyReference, out sqlDependencyReference, out xmlPrimaryReference);

            ITaskItem taskItem = new TaskItem("Microsoft.Build.Engine");
            taskItem.SetMetadata("SpecificVersion", "true");

            ITaskItem taskItem2 = new TaskItem("System.Xml");
            taskItem2.SetMetadata("SpecificVersion", "false");

            xmlPrimaryReference.MakePrimaryAssemblyReference(taskItem2, false, ".dll");
            enginePrimaryReference.MakePrimaryAssemblyReference(taskItem, true, ".dll");
            enginePrimaryReference.FullPath = "FullPath";
            xmlPrimaryReference.FullPath = "FullPath";
            dataDependencyReference.FullPath = "FullPath";
            sqlDependencyReference.FullPath = "FullPath";
            dataDependencyReference.MakeDependentAssemblyReference(enginePrimaryReference);
            sqlDependencyReference.MakeDependentAssemblyReference(enginePrimaryReference);
            dataDependencyReference.MakeDependentAssemblyReference(xmlPrimaryReference);

            InitializeMockEngine(out referenceTable, out mockEngine, out rar);
            AddReferencesToReferenceTable(referenceTable, engineAssemblyName, dataAssemblyName, sqlclientAssemblyName, xmlAssemblyName, enginePrimaryReference, dataDependencyReference, sqlDependencyReference, xmlPrimaryReference);

            InitializeExclusionList(referenceTable, new AssemblyNameExtension[] { sqlclientAssemblyName, dataAssemblyName }, out blackList);

            string subsetName = ResolveAssemblyReference.GenerateSubSetName(new string[] { "Client" }, null);
            string warningMessage = rar.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", taskItem2.ItemSpec, dataAssemblyName.FullName, subsetName);
            string notExpectedwarningMessage = rar.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", taskItem.ItemSpec, dataAssemblyName.FullName, subsetName);
            string notExpectedwarningMessage2 = rar.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", taskItem.ItemSpec, sqlclientAssemblyName.FullName, subsetName);

            Dictionary<AssemblyNameExtension, Reference> table = referenceTable.References;
            Assert.Equal(3, table.Count); // "Expected there to be three elements in the dictionary"
            Assert.True(table.ContainsKey(sqlclientAssemblyName)); // "Expected to find the sqlclientAssemblyName in the referenceList"
            Assert.True(table.ContainsKey(dataAssemblyName)); // "Expected to find the dataAssemblyName in the referenceList"
            Assert.False(table.ContainsKey(xmlAssemblyName)); // "Expected not to find the xmlssemblyName in the referenceList"
            Assert.True(table.ContainsKey(engineAssemblyName)); // "Expected to find the engineAssemblyName in the referenceList"

            string[] warningMessages = new string[] { warningMessage };
            foreach (string message in warningMessages)
            {
                Console.Out.WriteLine("WarningMessageToAssert:" + message);
                mockEngine.AssertLogContains(message);
            }

            mockEngine.AssertLogDoesntContain(notExpectedwarningMessage);
            mockEngine.AssertLogDoesntContain(notExpectedwarningMessage2);
            table.Clear();
        }

        private static ReferenceTable MakeEmptyReferenceTable(TaskLoggingHelper log)
        {
            ReferenceTable referenceTable = new ReferenceTable(null, false, false, false, false, new string[0], null, null, null, null, null, null, SystemProcessorArchitecture.None, fileExists, null, null, null, null,
#if FEATURE_WIN32_REGISTRY
                null, null, null,
#endif
                null, null, new Version("4.0"), null, log, null, true, false, null, null, false, null, WarnOrErrorOnTargetArchitectureMismatchBehavior.None, false, false, null);
            return referenceTable;
        }

        /// <summary>
        /// Verify the correct references are still in the references table and that references which are in the black list are not in the references table
        /// Also verify any expected warning messages are seen in the log.
        /// </summary>
        private static void VerifyReferenceTable(ReferenceTable referenceTable, MockEngine mockEngine, AssemblyNameExtension engineAssemblyName, AssemblyNameExtension dataAssemblyName, AssemblyNameExtension sqlclientAssemblyName, AssemblyNameExtension xmlAssemblyName, string[] warningMessages)
        {
            Dictionary<AssemblyNameExtension, Reference> table = referenceTable.References;
            Assert.Empty(table); // "Expected there to be zero elements in the dictionary"

            if (warningMessages != null)
            {
                foreach (string warningMessage in warningMessages)
                {
                    Console.Out.WriteLine("WarningMessageToAssert:" + warningMessages);
                    mockEngine.AssertLogContains(warningMessage);
                }
            }

            table.Clear();
        }

        /// <summary>
        /// Make sure we get an argument null exception when the profileName is set to null
        /// </summary>
        [Fact]
        public void TestProfileNameNull()
        {
            Assert.Throws<ArgumentNullException>(() =>
            {
                ResolveAssemblyReference rar = new ResolveAssemblyReference();
                rar.ProfileName = null;
            }
           );
        }
        /// <summary>
        /// Make sure we get an argument null exception when the ProfileFullFrameworkFolders is set to null
        /// </summary>
        [Fact]
        public void TestProfileFullFrameworkFoldersFoldersNull()
        {
            Assert.Throws<ArgumentNullException>(() =>
            {
                ResolveAssemblyReference rar = new ResolveAssemblyReference();
                rar.FullFrameworkFolders = null;
            }
           );
        }
        /// <summary>
        /// Make sure we get an argument null exception when the ProfileFullFrameworkAssemblyTables is set to null
        /// </summary>
        [Fact]
        public void TestProfileFullFrameworkAssemblyTablesNull()
        {
            Assert.Throws<ArgumentNullException>(() =>
            {
                ResolveAssemblyReference rar = new ResolveAssemblyReference();
                rar.FullFrameworkAssemblyTables = null;
            }
           );
        }
        /// <summary>
        /// Verify that setting a subset and a profile at the same time will cause an error to be logged and rar to return false
        /// </summary>
        [Fact]
        public void TestProfileAndSubset1()
        {
            MockEngine mockEngine;
            ResolveAssemblyReference rar;
            InitializeRARwithMockEngine(_output, out mockEngine, out rar);

            rar.TargetFrameworkSubsets = new string[] { "Client" };
            rar.ProfileName = "Client";
            rar.FullFrameworkFolders = new string[] { "Client" };
            Assert.False(rar.Execute());
            mockEngine.AssertLogContains(rar.Log.FormatResourceString("ResolveAssemblyReference.CannotSetProfileAndSubSet"));
        }

        /// <summary>
        /// Verify that setting a subset and a profile at the same time will cause an error to be logged and rar to return false
        /// </summary>
        [Fact]
        public void TestProfileAndSubset2()
        {
            MockEngine mockEngine;
            ResolveAssemblyReference rar;
            InitializeRARwithMockEngine(_output, out mockEngine, out rar);

            rar.InstalledAssemblySubsetTables = new ITaskItem[] { new TaskItem("Client.xml") };
            rar.ProfileName = "Client";
            rar.FullFrameworkFolders = new string[] { "Client" };
            Assert.False(rar.Execute());
            mockEngine.AssertLogContains(rar.Log.FormatResourceString("ResolveAssemblyReference.CannotSetProfileAndSubSet"));
        }

        /// <summary>
        /// Verify setting certain combinations of Profile parameters will case an error to be logged and rar to fail execution.
        ///
        /// Test the case where the profile name is not set and ProfileFullFrameworkFolders is set.
        ///</summary>
        [Fact]
        public void TestProfileParameterCombinations()
        {
            MockEngine mockEngine;
            ResolveAssemblyReference rar;
            InitializeRARwithMockEngine(_output, out mockEngine, out rar);
            rar.ProfileName = "Client";
            Assert.False(rar.Execute());
            mockEngine.AssertLogContains(rar.Log.FormatResourceString("ResolveAssemblyReference.MustSetProfileNameAndFolderLocations"));
        }

        /// <summary>
        /// Verify when the frameworkdirectory metadata is not set on the ProfileFullFrameworkAssemblyTables that an
        /// error is logged and rar fails.
        ///</summary>
        [Fact]
        public void TestFrameworkDirectoryMetadata()
        {
            MockEngine mockEngine;
            ResolveAssemblyReference rar;
            InitializeRARwithMockEngine(_output, out mockEngine, out rar);
            TaskItem item = new TaskItem("Client.xml");
            rar.ProfileName = "Client";
            rar.FullFrameworkAssemblyTables = new ITaskItem[] { item };
            Assert.False(rar.Execute());
            mockEngine.AssertLogContains(rar.Log.FormatResourceString("ResolveAssemblyReference.FrameworkDirectoryOnProfiles", item.ItemSpec));
        }

        private static void InitializeRARwithMockEngine(ITestOutputHelper output, out MockEngine mockEngine, out ResolveAssemblyReference rar)
        {
            mockEngine = new MockEngine(output);
            rar = new ResolveAssemblyReference();
            rar.BuildEngine = mockEngine;
        }

        /// <summary>
        /// Add a set of references and their names to the reference table.
        /// </summary>
        private static void AddReferencesToReferenceTable(ReferenceTable referenceTable, AssemblyNameExtension engineAssemblyName, AssemblyNameExtension dataAssemblyName, AssemblyNameExtension sqlclientAssemblyName, AssemblyNameExtension xmlAssemblyName, Reference enginePrimaryReference, Reference dataDependencyReference, Reference sqlDependencyReference, Reference xmlPrimaryReference)
        {
            Dictionary<AssemblyNameExtension, Reference> table = referenceTable.References;
            if (enginePrimaryReference != null)
            {
                table.Add(engineAssemblyName, enginePrimaryReference);
            }

            if (dataDependencyReference != null)
            {
                table.Add(dataAssemblyName, dataDependencyReference);
            }
            if (sqlDependencyReference != null)
            {
                table.Add(sqlclientAssemblyName, sqlDependencyReference);
            }

            if (xmlPrimaryReference != null)
            {
                table.Add(xmlAssemblyName, xmlPrimaryReference);
            }
        }

        /// <summary>
        /// Initialize the mock engine so we can look at the warning messages, also put the assembly name which is to be in the black list into the black list.
        /// Call remove references so that we can then validate the results.
        /// </summary>
        private void InitializeMockEngine(out ReferenceTable referenceTable, out MockEngine mockEngine, out ResolveAssemblyReference rar)
        {
            mockEngine = new MockEngine(_output);
            rar = new ResolveAssemblyReference();
            rar.BuildEngine = mockEngine;

            referenceTable = MakeEmptyReferenceTable(rar.Log);
        }

        /// <summary>
        ///Initialize the black list and use it to remove references from the reference table
        /// </summary>
        private void InitializeExclusionList(ReferenceTable referenceTable, AssemblyNameExtension[] assembliesForBlackList, out Dictionary<string, string> blackList)
        {
            blackList = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            foreach (AssemblyNameExtension assemblyName in assembliesForBlackList)
            {
                blackList[assemblyName.FullName] = null;
            }

            referenceTable.MarkReferencesForExclusion(blackList);
            referenceTable.RemoveReferencesMarkedForExclusion(false, "Client");
        }

        /// <summary>
        /// Before each test to validate the references are correctly removed from the reference table we need to make new instances of them
        /// </summary>
        /// <param name="enginePrimaryReference"></param>
        /// <param name="dataDependencyReference"></param>
        /// <param name="sqlDependencyReference"></param>
        /// <param name="xmlPrimaryReference"></param>
        private static void GenerateNewReferences(out Reference enginePrimaryReference, out Reference dataDependencyReference, out Reference sqlDependencyReference, out Reference xmlPrimaryReference)
        {
            enginePrimaryReference = new Reference(isWinMDFile, fileExists, getRuntimeVersion);
            dataDependencyReference = new Reference(isWinMDFile, fileExists, getRuntimeVersion);
            sqlDependencyReference = new Reference(isWinMDFile, fileExists, getRuntimeVersion);
            xmlPrimaryReference = new Reference(isWinMDFile, fileExists, getRuntimeVersion);
        }

        /// <summary>
        /// This test will verify the IgnoreDefaultInstalledSubsetTables property on the RAR task.
        /// The property determines whether or not RAR will search the target framework directories under the subsetList folder for
        /// xml files matching the client subset names passed into the TargetFrameworkSubset property.
        ///
        /// The default for the property is false, when the value is false RAR will search the SubsetList folder under the TargetFramework directories
        /// for the xml files with names in the TargetFrameworkSubset property.  When the value is true, RAR will not search the SubsetList directory. The only
        /// way to specify a TargetFrameworkSubset is to pass one to the InstalledAssemblySubsetTables property.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void IgnoreDefaultInstalledSubsetTables()
        {
            string redistListPath = CreateGenericRedistList();
            try
            {
                string subsetListClientPath = ObjectModelHelpers.CreateFileInTempProjectDirectory("v3.5\\SubsetList\\Client.xml", _engineOnlySubset);
                string explicitSubsetListPath = ObjectModelHelpers.CreateFileInTempProjectDirectory("v3.5\\SubsetList\\ExplicitList.xml", _xmlOnlySubset);
                ResolveAssemblyReference t = new ResolveAssemblyReference();
                t.BuildEngine = new MockEngine(_output);
                t.Assemblies = new ITaskItem[] { new TaskItem("Microsoft.Build.Engine"), new TaskItem("System.Xml") };
                t.SearchPaths = new string[] { @"{TargetFrameworkDirectory}" };

                // This is a TargetFrameworkSubset that would be searched by RAR if IgnoreDefaultINstalledAssemblySubsetTables does not work.
                t.TargetFrameworkSubsets = new string[] { "Client" };
                t.TargetFrameworkDirectories = new string[] { Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5") };
                t.InstalledAssemblyTables = new ITaskItem[] { new TaskItem(redistListPath) };
                t.IgnoreDefaultInstalledAssemblyTables = true;
                t.InstalledAssemblySubsetTables = new ITaskItem[] { new TaskItem(explicitSubsetListPath) };
                t.IgnoreDefaultInstalledAssemblySubsetTables = true;

                string microsoftBuildEnginePath = Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5\\Microsoft.Build.Engine.dll");
                string systemXmlPath = Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5\\System.Xml.dll");

                bool success = GenerateHelperDelegatesAndExecuteTask(t, microsoftBuildEnginePath, systemXmlPath);

                Assert.True(success); // "Expected no errors."
                Assert.Single(t.ResolvedFiles); // "Expected one resolved assembly."
                Assert.Contains("System.Xml", t.ResolvedFiles[0].ItemSpec); // "Expected System.Xml to resolve."
            }
            finally
            {
                File.Delete(redistListPath);
            }
        }

        /// <summary>
        /// Generate helper delegates for returning the file existence and the assembly name.
        /// Also run the rest and return the result.
        /// </summary>
        private bool GenerateHelperDelegatesAndExecuteTask(ResolveAssemblyReference t, string microsoftBuildEnginePath, string systemXmlPath)
        {
            FileExists cachedFileExists = fileExists;
            GetAssemblyName cachedGetAssemblyName = getAssemblyName;
            fileExists = new FileExists(delegate (string path)
            {
                if (String.Equals(path, microsoftBuildEnginePath, StringComparison.OrdinalIgnoreCase) ||
                    String.Equals(path, systemXmlPath, StringComparison.OrdinalIgnoreCase) ||
                    path.EndsWith("RarCache", StringComparison.OrdinalIgnoreCase))
                {
                    return true;
                }
                return false;
            });

            getAssemblyName = new GetAssemblyName(delegate (string path)
            {
                if (String.Equals(path, microsoftBuildEnginePath, StringComparison.OrdinalIgnoreCase))
                {
                    return new AssemblyNameExtension("Microsoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
                }
                else if (String.Equals(path, systemXmlPath, StringComparison.OrdinalIgnoreCase))
                {
                    return new AssemblyNameExtension("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
                }

                return null;
            });

            bool success;
            try
            {
                success = Execute(t);
            }
            finally
            {
                fileExists = cachedFileExists;
                getAssemblyName = cachedGetAssemblyName;
            }
            return success;
        }

        /// <summary>
        /// Test the case where there are no client subset names passed in but an InstalledDefaultSubsetTable
        /// is passed in. We expect to use that.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void NoClientSubsetButInstalledSubTables()
        {
            string redistListPath = CreateGenericRedistList();
            try
            {
                ResolveAssemblyReference t = new ResolveAssemblyReference();
                t.BuildEngine = new MockEngine(_output);
                // These are the assemblies we are going to try and resolve
                t.Assemblies = new ITaskItem[] { new TaskItem("Microsoft.Build.Engine"), new TaskItem("System.Xml") };
                t.SearchPaths = new string[] { @"{TargetFrameworkDirectory}" };
                t.TargetFrameworkDirectories = new string[] { Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5") };
                t.InstalledAssemblyTables = new ITaskItem[] { new TaskItem(redistListPath) };
                // Only the explicitly specified redist list should be used
                t.TargetFrameworkSubsets = new string[0];

                // Create a subset list which should be read in
                string explicitSubsetListContents =
                        "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                            "<File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' />" +
                        "</FileList >";

                string explicitSubsetListPath = ObjectModelHelpers.CreateFileInTempProjectDirectory("v3.5\\SubsetList\\ExplicitList.xml", explicitSubsetListContents);
                t.InstalledAssemblySubsetTables = new ITaskItem[] { new TaskItem(explicitSubsetListPath) };
                t.IgnoreDefaultInstalledAssemblySubsetTables = true;

                string microsoftBuildEnginePath = Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5\\Microsoft.Build.Engine.dll");
                string systemXmlPath = Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5\\System.Xml.dll");
                bool success = GenerateHelperDelegatesAndExecuteTask(t, microsoftBuildEnginePath, systemXmlPath);

                Assert.True(success); // "Expected no errors."
                Assert.Single(t.ResolvedFiles); // "Expected one resolved assembly."
                Assert.Contains("System.Xml", t.ResolvedFiles[0].ItemSpec); // "Expected System.Xml to resolve."
                MockEngine engine = ((MockEngine)t.BuildEngine);
                engine.AssertLogContains(t.Log.FormatResourceString("ResolveAssemblyReference.UsingExclusionList"));
            }
            finally
            {
                File.Delete(redistListPath);
            }
        }

        /// <summary>
        /// Verify the case where the installedSubsetTables are null
        /// </summary>
        [Fact]
        public void NullInstalledSubsetTables()
        {
            Assert.Throws<ArgumentNullException>(() =>
            {
                ResolveAssemblyReference reference = new ResolveAssemblyReference();
                reference.InstalledAssemblySubsetTables = null;
            }
           );
        }
        /// <summary>
        /// Verify the case where the targetFrameworkSubsets are null
        /// </summary>
        [Fact]
        public void NullTargetFrameworkSubsets()
        {
            Assert.Throws<ArgumentNullException>(() =>
            {
                ResolveAssemblyReference reference = new ResolveAssemblyReference();
                reference.TargetFrameworkSubsets = null;
            }
           );
        }
        /// <summary>
        /// Verify the case where the FulltargetFrameworkSubsetNames are null
        /// </summary>
        [Fact]
        public void NullFullTargetFrameworkSubsetNames()
        {
            Assert.Throws<ArgumentNullException>(() =>
            {
                ResolveAssemblyReference reference = new ResolveAssemblyReference();
                reference.FullTargetFrameworkSubsetNames = null;
            }
           );
        }
        /// <summary>
        /// Test the case where a non existent subset list path is used and no additional subsets are passed in.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void FakeSubsetListPathsNoAdditionalSubsets()
        {
            string redistListPath = CreateGenericRedistList();
            try
            {
                ResolveAssemblyReference t = new ResolveAssemblyReference();
                t.BuildEngine = new MockEngine(_output);
                // These are the assemblies we are going to try and resolve
                t.Assemblies = new ITaskItem[] { new TaskItem("Microsoft.Build.Engine"), new TaskItem("System.Xml") };
                t.SearchPaths = new string[] { @"{TargetFrameworkDirectory}" };

                t.TargetFrameworkSubsets = new string[] { "NOTTOEXIST" };
                t.TargetFrameworkDirectories = new string[] { Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5") };
                t.InstalledAssemblyTables = new ITaskItem[] { new TaskItem(redistListPath) };

                // Only the explicitly specified redist list should be used
                t.IgnoreDefaultInstalledAssemblyTables = true;

                string microsoftBuildEnginePath = Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5\\Microsoft.Build.Engine.dll");
                string systemXmlPath = Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5\\System.Xml.dll");
                bool success = GenerateHelperDelegatesAndExecuteTask(t, microsoftBuildEnginePath, systemXmlPath);
                Assert.True(success); // "Expected no errors."
                MockEngine engine = ((MockEngine)t.BuildEngine);
                engine.AssertLogContains(t.Log.FormatResourceString("ResolveAssemblyReference.UsingExclusionList"));
                engine.AssertLogContains(t.Log.FormatResourceString("ResolveAssemblyReference.NoSubsetsFound"));
                Assert.Equal(2, t.ResolvedFiles.Length); // "Expected one resolved assembly."
                Assert.Contains("System.Xml", t.ResolvedFiles[1].ItemSpec); // "Expected System.Xml to resolve."
                Assert.Contains("Microsoft.Build.Engine", t.ResolvedFiles[0].ItemSpec); // "Expected Microsoft.Build.Engine to resolve."
            }
            finally
            {
                File.Delete(redistListPath);
            }
        }

        /// <summary>
        /// This test will verify when the full client name is passed in and it appears in the TargetFrameworkSubsetList, that the
        /// black list is not used.
        /// </summary>
        [Fact]
        public void ResolveAssemblyReferenceVerifyFullClientName()
        {
            string redistListPath = CreateGenericRedistList();
            try
            {
                ResolveAssemblyReference t = new ResolveAssemblyReference();
                t.BuildEngine = new MockEngine(_output);

                // These are the assemblies we are going to try and resolve
                t.Assemblies = new ITaskItem[] { new TaskItem("System.Xml") };

                // This is a TargetFrameworkSubset that would be searched by RAR if IgnoreDefaultINstalledAssemblySubsetTables does not work.
                t.TargetFrameworkSubsets = new string[] { "Client", "Full" };
                t.FullTargetFrameworkSubsetNames = new string[] { "Full" };
                t.TargetFrameworkDirectories = new string[] { Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5") };
                t.InstalledAssemblyTables = new ITaskItem[] { new TaskItem(redistListPath) };
                t.IgnoreDefaultInstalledAssemblyTables = true;

                Execute(t);
                MockEngine engine = (MockEngine)t.BuildEngine;
                engine.AssertLogContains(t.Log.FormatResourceString("ResolveAssemblyReference.NoExclusionListBecauseofFullClientName", "Full"));
            }
            finally
            {
                File.Delete(redistListPath);
            }
        }

        /// <summary>
        /// This test will verify when the full client name is passed in and it appears in the TargetFrameworkSubsetList, that the
        /// black list is not used.
        /// </summary>
        [Fact]
        public void ResolveAssemblyReferenceVerifyFullClientNameWithSubsetTables()
        {
            string redistListPath = CreateGenericRedistList();
            try
            {
                ResolveAssemblyReference t = new ResolveAssemblyReference();
                t.BuildEngine = new MockEngine(_output);
                // These are the assemblies we are going to try and resolve
                t.Assemblies = new ITaskItem[] { new TaskItem("System.Xml") };

                // This is a TargetFrameworkSubset that would be searched by RAR if IgnoreDefaultINstalledAssemblySubsetTables does not work.
                t.TargetFrameworkSubsets = new string[] { "Client", "Full" };
                t.FullTargetFrameworkSubsetNames = new string[] { "Full" };
                t.TargetFrameworkDirectories = new string[] { Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5") };
                t.IgnoreDefaultInstalledAssemblySubsetTables = true;
                t.InstalledAssemblyTables = new ITaskItem[] { new TaskItem(redistListPath) };
                t.InstalledAssemblySubsetTables = new ITaskItem[] { new TaskItem(@"C:\LocationOfSubset.xml") };
                t.IgnoreDefaultInstalledAssemblyTables = true;

                Execute(t);

                MockEngine engine = (MockEngine)t.BuildEngine;
                engine.AssertLogContains(t.Log.FormatResourceString("ResolveAssemblyReference.NoExclusionListBecauseofFullClientName", "Full"));
            }
            finally
            {
                File.Delete(redistListPath);
            }
        }

        /// <summary>
        /// This test will verify when the full client name is passed in and it appears in the TargetFrameworkSubsetList, that the
        /// black list is not used.
        /// </summary>
        [Fact]
        public void ResolveAssemblyReferenceVerifyFullClientNameNoTablesPassedIn()
        {
            string redistListPath = CreateGenericRedistList();
            try
            {
                ResolveAssemblyReference t = new ResolveAssemblyReference();
                t.BuildEngine = new MockEngine(_output);
                // These are the assemblies we are going to try and resolve
                t.Assemblies = new ITaskItem[] { new TaskItem("System.Xml") };

                // This is a TargetFrameworkSubset that would be searched by RAR if IgnoreDefaultINstalledAssemblySubsetTables does not work.
                t.TargetFrameworkSubsets = new string[] { "Client", "Full" };
                t.FullTargetFrameworkSubsetNames = new string[] { "Full" };
                t.TargetFrameworkDirectories = new string[] { Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5") };
                t.IgnoreDefaultInstalledAssemblySubsetTables = true;
                t.InstalledAssemblyTables = new ITaskItem[] { new TaskItem(redistListPath) };
                t.IgnoreDefaultInstalledAssemblyTables = true;

                Execute(t);

                MockEngine engine = (MockEngine)t.BuildEngine;
                engine.AssertLogContains(t.Log.FormatResourceString("ResolveAssemblyReference.NoExclusionListBecauseofFullClientName", "Full"));
            }
            finally
            {
                File.Delete(redistListPath);
            }
        }

        /// <summary>
        /// Verify the correct references are still in the references table and that references which are in the black list are not in the references table
        /// Also verify any expected warning messages are seen in the log.
        /// </summary>
        private static void VerifyReferenceTable(ReferenceTable referenceTable, MockEngine mockEngine, AssemblyNameExtension engineAssemblyName, AssemblyNameExtension dataAssemblyName, AssemblyNameExtension sqlclientAssemblyName, AssemblyNameExtension xmlAssemblyName, string warningMessage, string warningMessage2)
        {
            IDictionary<AssemblyNameExtension, Reference> table = referenceTable.References;
            Assert.Equal(3, table.Count); // "Expected there to be three elements in the dictionary"
            Assert.False(table.ContainsKey(sqlclientAssemblyName)); // "Expected to not find the sqlclientAssemblyName in the referenceList"
            Assert.True(table.ContainsKey(xmlAssemblyName)); // "Expected to find the xmlssemblyName in the referenceList"
            Assert.True(table.ContainsKey(dataAssemblyName)); // "Expected to find the dataAssemblyName in the referenceList"
            Assert.True(table.ContainsKey(engineAssemblyName)); // "Expected to find the engineAssemblyName in the referenceList"
            if (warningMessage != null)
            {
                mockEngine.AssertLogContains(warningMessage);
            }
            if (warningMessage2 != null)
            {
                mockEngine.AssertLogContains(warningMessage2);
            }
            table.Clear();
        }

        /// <summary>
        /// Generate helper delegates for returning the file existence and the assembly name.
        /// Also run the rest and return the result.
        /// </summary>
        private bool GenerateHelperDelegatesAndExecuteTask(ResolveAssemblyReference t)
        {
            FileExists cachedFileExists = fileExists;
            GetAssemblyName cachedGetAssemblyName = getAssemblyName;
            string microsoftBuildEnginePath = Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5\\Microsoft.Build.Engine.dll");
            string systemXmlPath = Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5\\System.Xml.dll");
            fileExists = new FileExists(delegate (string path)
{
    if (String.Equals(path, microsoftBuildEnginePath, StringComparison.OrdinalIgnoreCase) ||
                    String.Equals(path, systemXmlPath, StringComparison.OrdinalIgnoreCase) ||
                    path.EndsWith("RarCache", StringComparison.OrdinalIgnoreCase))
    {
        return true;
    }
    return false;
});

            getAssemblyName = new GetAssemblyName(delegate (string path)
            {
                if (String.Equals(path, microsoftBuildEnginePath, StringComparison.OrdinalIgnoreCase))
                {
                    return new AssemblyNameExtension("Microsoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
                }
                else if (String.Equals(path, systemXmlPath, StringComparison.OrdinalIgnoreCase))
                {
                    return new AssemblyNameExtension("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
                }

                return null;
            });

            bool success;
            try
            {
                success = Execute(t);
            }
            finally
            {
                fileExists = cachedFileExists;
                getAssemblyName = cachedGetAssemblyName;
            }
            return success;
        }

        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void DoNotAssumeFilesDescribedByRedistListExistOnDisk()
        {
            string redistListPath = CreateGenericRedistList();
            try
            {
                ResolveAssemblyReference t = new ResolveAssemblyReference();

                t.BuildEngine = new MockEngine(_output);

                t.Assemblies = new ITaskItem[]
            {
                new TaskItem("Microsoft.Build.Engine"),
                new TaskItem("System.Xml")
            };

                t.SearchPaths = new string[]
            {
                @"{TargetFrameworkDirectory}"
            };
                t.TargetFrameworkDirectories = new string[] { Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5") };
                string microsoftBuildEnginePath = Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5\\Microsoft.Build.Engine");
                string systemXmlPath = Path.Combine(ObjectModelHelpers.TempProjectDir, "v3.5\\System.Xml.dll");

                t.InstalledAssemblyTables = new ITaskItem[] { new TaskItem(redistListPath) };

                FileExists cachedFileExists = fileExists;
                GetAssemblyName cachedGetAssemblyName = getAssemblyName;

                // Note that Microsoft.Build.Engine.dll does not exist
                fileExists = new FileExists(delegate (string path)
                {
                    if (String.Equals(path, systemXmlPath, StringComparison.OrdinalIgnoreCase) || path.EndsWith("RarCache", StringComparison.OrdinalIgnoreCase))
                    {
                        return true;
                    }
                    return false;
                });

                getAssemblyName = new GetAssemblyName(delegate (string path)
                {
                    if (String.Equals(path, microsoftBuildEnginePath, StringComparison.OrdinalIgnoreCase))
                    {
                        return new AssemblyNameExtension("Microsoft.Build.Engine, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
                    }
                    else if (String.Equals(path, systemXmlPath, StringComparison.OrdinalIgnoreCase))
                    {
                        return new AssemblyNameExtension("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=<KEY>");
                    }

                    return null;
                });

                bool success;
                try
                {
                    success = Execute(t);
                }
                finally
                {
                    fileExists = cachedFileExists;
                    getAssemblyName = cachedGetAssemblyName;
                }

                Assert.True(success); // "Expected no errors."
                Assert.Single(t.ResolvedFiles); // "Expected one resolved assembly."
                Assert.Contains("System.Xml", t.ResolvedFiles[0].ItemSpec); // "Expected System.Xml to resolve."
            }
            finally
            {
                File.Delete(redistListPath);
            }
        }

        /// <summary>
        /// Here's how you get into this situation:
        ///
        /// App
        ///   References - A
        ///
        ///    And, the following conditions.
        ///     $(ReferencePath) = c:\apath;:
        ///
        /// Expected result:
        /// * Invalid paths should be ignored.
        ///
        /// </summary>
        [Fact]
        public void Regress397129_HandleInvalidDirectoriesAndFiles_Case1()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A")
            };

            t.SearchPaths = new string[]
            {
                @"c:\apath",
                @":"
            };

            Execute(t); // Expect no exception.
        }

        /// <summary>
        /// Here's how you get into this situation:
        ///
        /// App
        ///   References - A
        ///        Hintpath=||invalidpath||
        ///
        /// Expected result:
        /// * No exceptions.
        ///
        /// </summary>
        [Fact]
        public void Regress397129_HandleInvalidDirectoriesAndFiles_Case2()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A")
            };

            t.Assemblies[0].SetMetadata("HintPath", @"||invalidpath||");

            t.SearchPaths = new string[]
            {
                @"{HintPathFromItem}"
            };

            Execute(t);
        }

        /// Consider this dependency chain:
        ///
        /// App
        ///   References - A
        ///        Depends on B
        ///        Will be found by hintpath.
        ///   References -B
        ///        No hintpath
        ///        Exists in A.dll's folder.
        ///
        /// B.dll should be unresolved even though its in A's folder because primary resolution needs to work
        /// without looking at dependencies because of the load-time perf scenarios don't look at dependencies.
        /// We must be consistent between primaries resolved with FindDependencies=true and FindDependencies=false.
        [Fact]
        public void ByDesignRelatedTo454863_PrimaryReferencesDontResolveToParentFolders()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A"),
                new TaskItem("B")
            };
            t.Assemblies[0].SetMetadata("HintPath", s_regress454863_ADllPath);

            t.SearchPaths = new string[]
            {
                "{HintPathFromItem}"
            };

            Execute(t);

            Assert.True(ContainsItem(t.ResolvedFiles, s_regress454863_ADllPath), "Expected A.dll to be resolved.");
            Assert.True(!ContainsItem(t.ResolvedFiles, s_regress454863_BDllPath), "Expected B.dll to be *not* be resolved.");
        }

        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void Regress393931_AllowAlternateAssemblyExtensions_Case1()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A")
            };

            t.SearchPaths = new string[]
            {
                @"C:\Regress393931"
            };
            t.AllowedAssemblyExtensions = new string[]
            {
                ".metaData_dll"
            };

            Execute(t);

            // Expect a suggested redirect plus a warning
            Assert.True(ContainsItem(t.ResolvedFiles, @"C:\Regress393931\A.metadata_dll")); // "Expected A.dll to be resolved."
        }

        /// <summary>
        /// Allow alternate extension values to be passed in.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void Regress393931_AllowAlternateAssemblyExtensions()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A")
            };

            t.SearchPaths = new string[]
            {
                @"C:\Regress393931"
            };
            t.AllowedAssemblyExtensions = new string[]
            {
                ".metaData_dll"
            };

            Execute(t);

            // Expect a suggested redirect plus a warning
            Assert.True(ContainsItem(t.ResolvedFiles, @"C:\Regress393931\A.metadata_dll")); // "Expected A.dll to be resolved."
        }

        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void SGenDependeicies()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.Assemblies = new TaskItem[]
            {
                new TaskItem("mycomponent"),
                new TaskItem("mycomponent2")
            };

            t.AssemblyFiles = new TaskItem[]
            {
                new TaskItem(@"c:\SGenDependeicies\mycomponent.dll"),
                new TaskItem(@"c:\SGenDependeicies\mycomponent2.dll")
            };

            t.SearchPaths = new string[]
            {
                @"c:\SGenDependeicies"
            };

            t.FindSerializationAssemblies = true;

            Execute(t);

            Assert.True(t.FindSerializationAssemblies); // "Expected to find serialization assembly."
            Assert.True(ContainsItem(t.SerializationAssemblyFiles, @"c:\SGenDependeicies\mycomponent.XmlSerializers.dll")); // "Expected to find serialization assembly, but didn't."
            Assert.True(ContainsItem(t.SerializationAssemblyFiles, @"c:\SGenDependeicies\mycomponent2.XmlSerializers.dll")); // "Expected to find serialization assembly, but didn't."
        }

        /// <summary>
        /// Consider this dependency chain:
        ///
        /// App
        ///   Has project reference to c:\Regress315619\A\MyAssembly.dll
        ///   Has project reference to c:\Regress315619\B\MyAssembly.dll
        ///
        /// These two project references have different versions. Important: PKT is null.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void Regress315619_TwoWeaklyNamedPrimariesIsInsoluble()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            MockEngine e = new MockEngine(_output);
            t.BuildEngine = e;

            t.AssemblyFiles = new ITaskItem[]
            {
                new TaskItem(@"c:\Regress315619\A\MyAssembly.dll"),
                new TaskItem(@"c:\Regress315619\B\MyAssembly.dll")
            };

            t.SearchPaths = new string[]
            {
                @"c:\Regress315619\A",
                @"c:\Regress315619\B"
            };

            Execute(t);

            e.AssertLogContains
            (
                String.Format(AssemblyResources.GetString("ResolveAssemblyReference.ConflictUnsolvable"), @"MyAssembly, Version=2.0.0.0, Culture=Neutral, PublicKeyToken=null", "MyAssembly, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=null")
            );
        }

        /// <summary>
        /// This is a fix to help ClickOnce folks correctly display information about which
        /// redist components can be deployed.
        ///
        /// Two new attributes are added to resolved references:
        /// (1) IsRedistRoot (bool) -- The flag from the redist *.xml file. If there is no
        /// flag in the file then there will be no flag on the resulting item. This flag means
        /// "I am the UI representative for this entire redist". ClickOnce will use this to hide
        /// all other redist items and to show only this item.
        ///
        /// (2) Redist (string) -- This the value of FileList Redist from the *.xml file.
        /// This string means "I am the unique name of this entire redist".
        ///
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void ForwardRedistRoot()
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();

            t.BuildEngine = new MockEngine(_output);

            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("MyRedistRootAssembly"),
                new TaskItem("MyOtherAssembly"),
                new TaskItem("MyThirdAssembly")
            };

            t.SearchPaths = new string[]
            {
                @"c:\MyRedist"
            };

            string redistFile = FileUtilities.GetTemporaryFile();

            try
            {
                File.Delete(redistFile);
                File.WriteAllText
(
                    redistFile,
                    "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                        "<File IsRedistRoot='true' AssemblyName='MyRedistRootAssembly' Version='0.0.0.0' PublicKeyToken='null' Culture='Neutral' FileVersion='2.0.40824.0' InGAC='true'/>" +
                        "<File IsRedistRoot='false' AssemblyName='MyOtherAssembly' Version='0.0.0.0' PublicKeyToken='null' Culture='Neutral' FileVersion='2.0.40824.0' InGAC='true'/>" +
                        "<File AssemblyName='MyThirdAssembly' Version='0.0.0.0' PublicKeyToken='null' Culture='Neutral' FileVersion='2.0.40824.0' InGAC='true'/>" +
                    "</FileList >"
                );

                t.InstalledAssemblyTables = new TaskItem[] { new TaskItem(redistFile) };

                Execute(t);
            }
            finally
            {
                File.Delete(redistFile);
            }

            Assert.Equal(3, t.ResolvedFiles.Length); // "Expected three assemblies to be found."
            Assert.Equal("true", t.ResolvedFiles[1].GetMetadata("IsRedistRoot"));
            Assert.Equal("false", t.ResolvedFiles[0].GetMetadata("IsRedistRoot"));
            Assert.Equal("", t.ResolvedFiles[2].GetMetadata("IsRedistRoot"));

            Assert.Equal("Microsoft-Windows-CLRCoreComp", t.ResolvedFiles[0].GetMetadata("Redist"));
            Assert.Equal("Microsoft-Windows-CLRCoreComp", t.ResolvedFiles[1].GetMetadata("Redist"));
            Assert.Equal("Microsoft-Windows-CLRCoreComp", t.ResolvedFiles[2].GetMetadata("Redist"));
        }

        /// <summary>
        /// helper for  TargetFrameworkFiltering
        /// </summary>
        private int RunTargetFrameworkFilteringTest(string projectTargetFramework)
        {
            ResolveAssemblyReference t = new ResolveAssemblyReference();
            t.BuildEngine = new MockEngine(_output);
            t.Assemblies = new ITaskItem[]
            {
                new TaskItem("A"),
                new TaskItem("B"),
                new TaskItem("C")
            };

            t.SearchPaths = new string[]
            {
                s_myLibrariesRootPath
            };

            t.Assemblies[1].SetMetadata("RequiredTargetFramework", "3.0");
            t.Assemblies[2].SetMetadata("RequiredTargetFramework", "3.5");
            t.TargetFrameworkVersion = projectTargetFramework;

            Execute(t);

            int set = 0;
            foreach (ITaskItem item in t.ResolvedFiles)
            {
                int mask = 0;
                if (item.ItemSpec.EndsWith(@"\A.dll"))
                {
                    mask = 1;
                }
                else if (item.ItemSpec.EndsWith(@"\B.dll"))
                {
                    mask = 2;
                }
                else if (item.ItemSpec.EndsWith(@"\C.dll"))
                {
                    mask = 4;
                }
                Assert.NotEqual(0, mask); // "Unexpected assembly in resolved list."
                Assert.Equal(0, mask & set); // "Assembly found twice in resolved list."
                set |= mask;
            }
            return set;
        }

        /// <summary>
        /// Make sure the reverse assembly name comparer correctly sorts the assembly names in reverse order
        /// </summary>
        [Fact]
        public void ReverseAssemblyNameExtensionComparer()
        {
            IComparer sortByVersionDescending = new RedistList.SortByVersionDescending();
            AssemblyEntry a1 = new AssemblyEntry("Microsoft.Build.Engine", "1.0.0.0", "b03f5f7f11d50a3a", "neutral", true, true, "Foo", "none", true);
            AssemblyEntry a2 = new AssemblyEntry("Microsoft.Build.Engine", "2.0.0.0", "b03f5f7f11d50a3a", "neutral", true, true, "Foo", "none", false);
            AssemblyEntry a3 = new AssemblyEntry("Microsoft.Build.Engine", "3.0.0.0", "b03f5f7f11d50a3a", "neutral", true, true, "Foo", "none", true);
            AssemblyEntry a4 = new AssemblyEntry("A", "3.0.0.0", "b03f5f7f11d50a3a", "neutral", true, true, "Foo", "none", true);
            AssemblyEntry a5 = new AssemblyEntry("B", "3.0.0.0", "b03f5f7f11d50a3a", "neutral", true, true, "Foo", "none", true);

            // Verify versions sort correctly when simple name is same
            Assert.Equal(0, sortByVersionDescending.Compare(a1, a1));
            Assert.Equal(1, sortByVersionDescending.Compare(a1, a2));
            Assert.Equal(1, sortByVersionDescending.Compare(a1, a3));
            Assert.Equal(-1, sortByVersionDescending.Compare(a2, a1));
            Assert.Equal(1, sortByVersionDescending.Compare(a2, a3));

            // Verify the names sort alphabetically
            Assert.Equal(-1, sortByVersionDescending.Compare(a4, a5));
        }

        /// <summary>
        /// Check the Filtering based on Target Framework.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TargetFrameworkFiltering()
        {
            int resultSet = RunTargetFrameworkFilteringTest("3.0");
            Assert.Equal(0x3, resultSet); // "Expected assemblies A & B to be found."

            resultSet = RunTargetFrameworkFilteringTest("3.5");
            Assert.Equal(0x7, resultSet); // "Expected assemblies A, B & C to be found."

            resultSet = RunTargetFrameworkFilteringTest(null);
            Assert.Equal(0x7, resultSet); // "Expected assemblies A, B & C to be found."

            resultSet = RunTargetFrameworkFilteringTest("2.0");
            Assert.Equal(0x1, resultSet); // "Expected only assembly A to be found."
        }

        /// <summary>
        /// Verify the when a simple name is asked for that the assemblies are returned in sorted order by version.
        /// </summary>
        [Fact]
        public void VerifyGetSimpleNamesIsSorted()
        {
            string redistFile = FileUtilities.GetTemporaryFile();
            try
            {
                File.Delete(redistFile);
                File.WriteAllText
                (
                    redistFile,
                    "<FileList Redist='Random' >" +
                        "<File AssemblyName='System' Version='10.0.0.0' PublicKeyToken='b77a5c561934e089' Culture='neutral' ProcessorArchitecture='MSIL' FileVersion='4.0.0.0' InGAC='true' />" +
                        "<File AssemblyName='System' Version='4.0.0.0' PublicKeyToken='b77a5c561934e089' Culture='neutral' ProcessorArchitecture='MSIL' FileVersion='4.0.0.0' InGAC='true' />" +
                        "<File AssemblyName='System' Version='3.0.0.0' PublicKeyToken='b77a5c561934e089' Culture='neutral' ProcessorArchitecture='MSIL' FileVersion='4.0.0.0' InGAC='true' />" +
                        "<File AssemblyName='System' Version='192.168.127.12' PublicKeyToken='b77a5c561934e089' Culture='neutral' ProcessorArchitecture='MSIL' FileVersion='4.0.0.0' InGAC='true' />" +
                        "<File AssemblyName='System' Version='1.0.0.0' PublicKeyToken='b77a5c561934e089' Culture='neutral' ProcessorArchitecture='MSIL' FileVersion='4.0.0.0' InGAC='true' />" +
                        "<File AssemblyName='System' Version='2.0.0.0' PublicKeyToken='b77a5c561934e089' Culture='neutral' ProcessorArchitecture='MSIL' FileVersion='4.0.0.0' InGAC='true' />" +
                    "</FileList >"
                );

                AssemblyTableInfo tableInfo = new AssemblyTableInfo(redistFile, "DoesNotExist");
                RedistList redist = RedistList.GetRedistList(new AssemblyTableInfo[] { tableInfo });

                List<AssemblyEntry> entryArray = redist.FindAssemblyNameFromSimpleName("System").ToList();
                Assert.Equal(6, entryArray.Count);
                AssemblyNameExtension a1 = new AssemblyNameExtension(entryArray[0].FullName);
                AssemblyNameExtension a2 = new AssemblyNameExtension(entryArray[1].FullName);
                AssemblyNameExtension a3 = new AssemblyNameExtension(entryArray[2].FullName);
                AssemblyNameExtension a4 = new AssemblyNameExtension(entryArray[3].FullName);
                AssemblyNameExtension a5 = new AssemblyNameExtension(entryArray[4].FullName);
                AssemblyNameExtension a6 = new AssemblyNameExtension(entryArray[5].FullName);

                Assert.Equal(new Version("192.168.127.12"), a1.Version);
                Assert.Equal(new Version("10.0.0.0"), a2.Version);
                Assert.Equal(new Version("4.0.0.0"), a3.Version);
                Assert.Equal(new Version("3.0.0.0"), a4.Version);
                Assert.Equal(new Version("2.0.0.0"), a5.Version);
                Assert.Equal(new Version("1.0.0.0"), a6.Version);
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        /// <summary>
        /// If the assembly was found in a redis list which does not have the correct redist name , Microsoft-Windows-CLRCoreComp then we should not consider it a framework assembly.
        /// </summary>
        [Fact]
        public void VerifyAssemblyInRedistListNonWindowsRedistName()
        {
            string redistFile = FileUtilities.GetTemporaryFile();
            try
            {
                File.Delete(redistFile);
                File.WriteAllText
                (
                    redistFile,
                    "<FileList Redist='Random' >" +
                        "<File AssemblyName='System' Version='10.0.0.0' PublicKeyToken='b77a5c561934e089' Culture='neutral' ProcessorArchitecture='MSIL' FileVersion='4.0.0.0' InGAC='true' />" +
                    "</FileList >"
                );

                AssemblyTableInfo tableInfo = new AssemblyTableInfo(redistFile, "DoesNotExist");
                RedistList redist = RedistList.GetRedistList(new AssemblyTableInfo[] { tableInfo });

                AssemblyNameExtension a1 = new AssemblyNameExtension("System, Version=10.0.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089");
                bool inRedistList = redist.FrameworkAssemblyEntryInRedist(a1);
                Assert.False(inRedistList);
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        /// <summary>
        /// If the assembly was found in a redis list which does have the correct redist name , Microsoft-Windows-CLRCoreComp then we should consider it a framework assembly.
        /// </summary>
        [Fact]
        public void VerifyAssemblyInRedistListWindowsRedistName()
        {
            string redistFile = FileUtilities.GetTemporaryFile();
            try
            {
                File.Delete(redistFile);
                File.WriteAllText
                (
                    redistFile,
                    "<FileList Redist='Microsoft-Windows-CLRCoreComp-Something' >" +
                        "<File AssemblyName='System' Version='10.0.0.0' PublicKeyToken='b77a5c561934e089' Culture='neutral' ProcessorArchitecture='MSIL' FileVersion='4.0.0.0' InGAC='true' />" +
                    "</FileList >"
                );

                AssemblyTableInfo tableInfo = new AssemblyTableInfo(redistFile, "DoesNotExist");
                RedistList redist = RedistList.GetRedistList(new AssemblyTableInfo[] { tableInfo });

                AssemblyNameExtension a1 = new AssemblyNameExtension("System, Version=10.0.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089");
                bool inRedistList = redist.FrameworkAssemblyEntryInRedist(a1);
                Assert.True(inRedistList);
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        /// <summary>
        /// If the assembly was found in a redis list which does have the correct redist name , Microsoft-Windows-CLRCoreComp then we should consider it a framework assembly taking into account including partial matching
        /// </summary>
        [Fact]
        public void VerifyAssemblyInRedistListPartialMatches()
        {
            string redistFile = FileUtilities.GetTemporaryFile();
            try
            {
                File.Delete(redistFile);
                File.WriteAllText
                (
                    redistFile,
                    "<FileList Redist='Microsoft-Windows-CLRCoreComp-Random' >" +
                        "<File AssemblyName='System' Version='10.0.0.0' PublicKeyToken='b77a5c561934e089' Culture='neutral' ProcessorArchitecture='MSIL' FileVersion='4.0.0.0' InGAC='true' />" +
                    "</FileList >"
                );

                AssemblyTableInfo tableInfo = new AssemblyTableInfo(redistFile, "DoesNotExist");
                RedistList redist = RedistList.GetRedistList(new AssemblyTableInfo[] { tableInfo });

                AssemblyNameExtension a1 = new AssemblyNameExtension("System, Version=10.0.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089");
                bool inRedistList = redist.FrameworkAssemblyEntryInRedist(a1);
                Assert.True(inRedistList);

                a1 = new AssemblyNameExtension("System, Culture=Neutral, PublicKeyToken=b77a5c561934e089");
                inRedistList = redist.FrameworkAssemblyEntryInRedist(a1);
                Assert.True(inRedistList);

                a1 = new AssemblyNameExtension("System, PublicKeyToken=b77a5c561934e089");
                inRedistList = redist.FrameworkAssemblyEntryInRedist(a1);
                Assert.True(inRedistList);

                a1 = new AssemblyNameExtension("System");
                inRedistList = redist.FrameworkAssemblyEntryInRedist(a1);
                Assert.True(inRedistList);
            }
            finally
            {
                File.Delete(redistFile);
            }
        }
        /// <summary>
        /// Verify when we ask if an assembly is in the redist list we get the right answer.
        /// The version should not be compared
        /// </summary>
        [Fact]
        public void VerifyAssemblyInRedistListDiffVersion()
        {
            string redistFile = FileUtilities.GetTemporaryFile();
            try
            {
                File.Delete(redistFile);
                File.WriteAllText
                (
                    redistFile,
                    "<FileList Redist='Microsoft-Windows-CLRCoreComp-Random' >" +
                        "<File AssemblyName='System' Version='10.0.0.0' PublicKeyToken='b77a5c561934e089' Culture='neutral' ProcessorArchitecture='MSIL' FileVersion='4.0.0.0' InGAC='true' />" +
                    "</FileList >"
                );

                AssemblyTableInfo tableInfo = new AssemblyTableInfo(redistFile, "DoesNotExist");
                RedistList redist = RedistList.GetRedistList(new AssemblyTableInfo[] { tableInfo });

                AssemblyNameExtension a1 = new AssemblyNameExtension("System, Version=5.0.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089");
                bool inRedistList = redist.FrameworkAssemblyEntryInRedist(a1);
                Assert.True(inRedistList);
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        /// <summary>
        /// Verify when we ask if an assembly is in the redist list we get the right answer.
        /// The public key is significant and should make the match not work
        /// </summary>
        [Fact]
        public void VerifyAssemblyInRedistListDiffPublicKey()
        {
            string redistFile = FileUtilities.GetTemporaryFile();
            try
            {
                File.Delete(redistFile);
                File.WriteAllText
                (
                    redistFile,
                    "<FileList Redist='Microsoft-Windows-CLRCoreComp-Random' >" +
                        "<File AssemblyName='System' Version='10.0.0.0' PublicKeyToken='b77a5c561934e089' Culture='neutral' ProcessorArchitecture='MSIL' FileVersion='4.0.0.0' InGAC='true' />" +
                    "</FileList >"
                );

                AssemblyTableInfo tableInfo = new AssemblyTableInfo(redistFile, "DoesNotExist");
                RedistList redist = RedistList.GetRedistList(new AssemblyTableInfo[] { tableInfo });

                AssemblyNameExtension a1 = new AssemblyNameExtension("System, Version=5.0.0.0, Culture=Neutral, PublicKeyToken=b67a5c561934e089");
                bool inRedistList = redist.FrameworkAssemblyEntryInRedist(a1);
                Assert.False(inRedistList);
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        /// <summary>
        /// Verify when we ask if an assembly is in the redist list we get the right answer.
        /// The Culture is significant and should make the match not work
        /// </summary>
        [Fact]
        public void VerifyAssemblyInRedistListDiffCulture()
        {
            string redistFile = FileUtilities.GetTemporaryFile();
            try
            {
                File.Delete(redistFile);
                File.WriteAllText
                (
                    redistFile,
                    "<FileList Redist='Microsoft-Windows-CLRCoreComp-Random' >" +
                        "<File AssemblyName='System' Version='10.0.0.0' PublicKeyToken='b77a5c561934e089' Culture='FR-fr' ProcessorArchitecture='MSIL' FileVersion='4.0.0.0' InGAC='true' />" +
                    "</FileList >"
                );

                AssemblyTableInfo tableInfo = new AssemblyTableInfo(redistFile, "DoesNotExist");
                RedistList redist = RedistList.GetRedistList(new AssemblyTableInfo[] { tableInfo });

                AssemblyNameExtension a1 = new AssemblyNameExtension("System, Version=10.0.0.0, Culture=Neutral, PublicKeyToken=b67a5c561934e089");
                bool inRedistList = redist.FrameworkAssemblyEntryInRedist(a1);
                Assert.False(inRedistList);
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        /// <summary>
        /// Verify when we ask if an assembly is in the redist list we get the right answer.
        /// The SimpleName is significant and should make the match not work
        /// </summary>
        [Fact]
        public void VerifyAssemblyInRedistListDiffSimpleName()
        {
            string redistFile = FileUtilities.GetTemporaryFile();
            try
            {
                File.Delete(redistFile);
                File.WriteAllText
                (
                    redistFile,
                    "<FileList Redist='Microsoft-Windows-CLRCoreComp-Random' >" +
                        "<File AssemblyName='System' Version='10.0.0.0' PublicKeyToken='b77a5c561934e089' Culture='neutral' ProcessorArchitecture='MSIL' FileVersion='4.0.0.0' InGAC='true' />" +
                    "</FileList >"
                );

                AssemblyTableInfo tableInfo = new AssemblyTableInfo(redistFile, "DoesNotExist");
                RedistList redist = RedistList.GetRedistList(new AssemblyTableInfo[] { tableInfo });

                AssemblyNameExtension a1 = new AssemblyNameExtension("Something, Version=10.0.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089");
                bool inRedistList = redist.FrameworkAssemblyEntryInRedist(a1);
                Assert.False(inRedistList);
            }
            finally
            {
                File.Delete(redistFile);
            }
        }

        /// <summary>
        /// Verify when a p2p (assemblies in the AssemblyFiles property) are passed to rar that we properly un-resolve them if they depend on references which are in the black list for the profile.
        /// </summary>
        [Fact]
        public void Verifyp2pAndProfile()
        {
            string fullFrameworkDirectory = Path.Combine(Path.GetTempPath(), "Verifyp2pAndProfile");
            string targetFrameworkDirectory = Path.Combine(fullFrameworkDirectory, "Profiles", "Client");

            string fullRedistListContents =
            "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                "<File AssemblyName='System' Version='9.0.0.0' PublicKeyToken='b77a5c561934e089' Culture='Neutral'/>" +
            "</FileList >";

            try
            {
                // Create a generic redist list with system.xml and microsoft.build.engine.
                string profileRedistList;
                string fullRedistList;
                GenerateRedistAndProfileXmlLocations(fullRedistListContents, _engineOnlySubset, out profileRedistList, out fullRedistList, fullFrameworkDirectory, targetFrameworkDirectory);

                ResolveAssemblyReference t = new ResolveAssemblyReference();
                MockEngine e = new MockEngine(_output);
                t.BuildEngine = e;
                t.AssemblyFiles = new ITaskItem[] { new TaskItem(Path.Combine(s_myComponentsMiscPath, "DependsOn9Also.dll")) };
                t.SearchPaths = new string[] { @"{TargetFrameworkDirectory}", fullFrameworkDirectory };
                t.TargetFrameworkDirectories = new string[] { targetFrameworkDirectory };
                t.InstalledAssemblyTables = new ITaskItem[] { new TaskItem(profileRedistList) };
                t.IgnoreDefaultInstalledAssemblyTables = true;
                t.FullFrameworkFolders = new string[] { fullFrameworkDirectory };
                t.ProfileName = "Client";
                t.TargetFrameworkMoniker = ".Net Framework, Version=v4.0";

                bool success = Execute(t, false);
                Assert.True(success); // "Expected no errors."
                Assert.Empty(t.ResolvedFiles); // "Expected no resolved assemblies."
                string warningMessage = t.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", Path.Combine(s_myComponentsMiscPath, "DependsOn9Also.dll"), "System, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", t.TargetFrameworkMoniker);
                e.AssertLogContains(warningMessage);
            }
            finally
            {
                if (Directory.Exists(fullFrameworkDirectory))
                {
                    FileUtilities.DeleteWithoutTrailingBackslash(fullFrameworkDirectory, true);
                }
            }
        }

        /// <summary>
        /// Verify when a p2p (assemblies in the AssemblyFiles property) are passed to rar that we properly resolve them if they depend on references which are in the black list for the profile but have specific version set to true.
        /// </summary>
        [Fact]
        public void Verifyp2pAndProfile2()
        {
            string fullFrameworkDirectory = Path.Combine(Path.GetTempPath(), "Verifyp2pAndProfile");
            string targetFrameworkDirectory = Path.Combine(fullFrameworkDirectory, "Profiles", "Client");

            string fullRedistListContents =
            "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                "<File AssemblyName='System' Version='9.0.0.0' PublicKeyToken='b77a5c561934e089' Culture='Neutral'/>" +
            "</FileList >";

            try
            {
                // Create a generic redist list with system.xml and microsoft.build.engine.
                string profileRedistList;
                string fullRedistList;
                GenerateRedistAndProfileXmlLocations(fullRedistListContents, _engineOnlySubset, out profileRedistList, out fullRedistList, fullFrameworkDirectory, targetFrameworkDirectory);

                ResolveAssemblyReference t = new ResolveAssemblyReference();
                MockEngine e = new MockEngine(_output);
                t.BuildEngine = e;
                TaskItem item = new TaskItem(Path.Combine(s_myComponentsMiscPath, "DependsOn9Also.dll"));
                item.SetMetadata("SpecificVersion", "true");
                t.AssemblyFiles = new ITaskItem[] { item };
                t.SearchPaths = new string[] { @"{TargetFrameworkDirectory}", fullFrameworkDirectory };
                t.TargetFrameworkDirectories = new string[] { targetFrameworkDirectory };
                t.InstalledAssemblyTables = new ITaskItem[] { new TaskItem(profileRedistList) };
                t.IgnoreDefaultInstalledAssemblyTables = true;
                t.FullFrameworkFolders = new string[] { fullFrameworkDirectory };
                t.ProfileName = "Client";

                bool success = Execute(t);
                Assert.True(success); // "Expected no errors."
                Assert.Single(t.ResolvedFiles); // "Expected no resolved assemblies."
                string warningMessage = t.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", Path.Combine(s_myComponentsMiscPath, "DependsOn9Also.dll"), "System, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "Client");
                e.AssertLogDoesntContain(warningMessage);
            }
            finally
            {
                if (Directory.Exists(fullFrameworkDirectory))
                {
                    FileUtilities.DeleteWithoutTrailingBackslash(fullFrameworkDirectory, true);
                }
            }
        }

        /// <summary>
        /// Verify when a profile is used that assemblies not in the profile are excluded or have metadata attached to indicate there are dependencies
        /// which are not in the profile.
        /// </summary>
        [Fact]
        public void VerifyClientProfileRedistListAndProfileList()
        {
            string fullFrameworkDirectory = Path.Combine(Path.GetTempPath(), "VerifyClientProfileRedistListAndProfileList");
            string targetFrameworkDirectory = Path.Combine(fullFrameworkDirectory, "Profiles", "Client");
            try
            {
                // Create a generic redist list with system.xml and microsoft.build.engine.
                string profileRedistList;
                string fullRedistList;
                GenerateRedistAndProfileXmlLocations(_fullRedistListContents, _engineOnlySubset, out profileRedistList, out fullRedistList, fullFrameworkDirectory, targetFrameworkDirectory);

                ResolveAssemblyReference t = new ResolveAssemblyReference();
                MockEngine e = new MockEngine(_output);
                t.BuildEngine = e;
                t.Assemblies = new ITaskItem[] { new TaskItem("Microsoft.Build.Engine"), new TaskItem("System.Xml") };
                t.SearchPaths = new string[] { @"{TargetFrameworkDirectory}", fullFrameworkDirectory };
                t.TargetFrameworkDirectories = new string[] { targetFrameworkDirectory };
                t.InstalledAssemblyTables = new ITaskItem[] { new TaskItem(profileRedistList) };
                t.IgnoreDefaultInstalledAssemblyTables = true;
                t.FullFrameworkFolders = new string[] { fullFrameworkDirectory };
                t.ProfileName = "Client";

                string microsoftBuildEnginePath = Path.Combine(fullFrameworkDirectory, "Microsoft.Build.Engine.dll");
                string systemXmlPath = Path.Combine(targetFrameworkDirectory, "System.Xml.dll");

                bool success = GenerateHelperDelegatesAndExecuteTask(t, microsoftBuildEnginePath, systemXmlPath);
                Assert.True(success); // "Expected no errors."
                Assert.Single(t.ResolvedFiles); // "Expected one resolved assembly."
                Assert.Contains("Microsoft.Build.Engine", t.ResolvedFiles[0].ItemSpec); // "Expected Engine to resolve."
                e.AssertLogContains("MSB3252");
            }
            finally
            {
                if (Directory.Exists(fullFrameworkDirectory))
                {
                    FileUtilities.DeleteWithoutTrailingBackslash(fullFrameworkDirectory, true);
                }
            }
        }

        /// <summary>
        /// Verify when a profile is used that assemblies not in the profile are excluded or have metadata attached to indicate there are dependencies
        /// which are not in the profile.
        ///
        /// Make sure the ProfileFullFrameworkAssemblyTable parameter works.
        /// </summary>
        [Fact]
        public void VerifyClientProfileRedistListAndProfileList2()
        {
            string fullFrameworkDirectory = Path.Combine(Path.GetTempPath(), "VerifyClientProfileRedistListAndProfileList2");
            string targetFrameworkDirectory = Path.Combine(fullFrameworkDirectory, "Profiles", "Client");
            try
            {
                // Create a generic redist list with system.xml and microsoft.build.engine.
                string profileRedistList;
                string fullRedistList;
                GenerateRedistAndProfileXmlLocations(_fullRedistListContents, _engineOnlySubset, out profileRedistList, out fullRedistList, fullFrameworkDirectory, targetFrameworkDirectory);

                ResolveAssemblyReference t = new ResolveAssemblyReference();
                MockEngine e = new MockEngine(_output);
                t.BuildEngine = e;
                t.Assemblies = new ITaskItem[] { new TaskItem("Microsoft.Build.Engine"), new TaskItem("System.Xml") };
                t.SearchPaths = new string[] { @"{TargetFrameworkDirectory}", fullFrameworkDirectory };
                t.TargetFrameworkDirectories = new string[] { targetFrameworkDirectory };
                t.InstalledAssemblyTables = new ITaskItem[] { new TaskItem(profileRedistList) };
                t.IgnoreDefaultInstalledAssemblyTables = true;

                ITaskItem item = new TaskItem(fullRedistList);
                item.SetMetadata("FrameworkDirectory", Path.GetDirectoryName(fullRedistList));
                t.FullFrameworkAssemblyTables = new ITaskItem[] { item };
                t.ProfileName = "Client";

                string microsoftBuildEnginePath = Path.Combine(fullFrameworkDirectory, "Microsoft.Build.Engine.dll");
                string systemXmlPath = Path.Combine(targetFrameworkDirectory, "System.Xml.dll");

                bool success = GenerateHelperDelegatesAndExecuteTask(t, microsoftBuildEnginePath, systemXmlPath);
                Assert.True(success); // "Expected no errors."
                Assert.Single(t.ResolvedFiles); // "Expected one resolved assembly."
                Assert.Contains("Microsoft.Build.Engine", t.ResolvedFiles[0].ItemSpec); // "Expected Engine to resolve."
                e.AssertLogContains("MSB3252");
            }
            finally
            {
                if (Directory.Exists(fullFrameworkDirectory))
                {
                    FileUtilities.DeleteWithoutTrailingBackslash(fullFrameworkDirectory, true);
                }
            }
        }

        /// <summary>
        /// When targeting a profile make sure that we do not resolve the assembly if we reference something from the full framework which is in the GAC.
        /// This will cover the same where we are referencing a full framework assembly.
        /// </summary>
        [Fact]
        public void VerifyAssemblyInGacButNotInProfileIsNotResolved()
        {
            string fullFrameworkDirectory = Path.Combine(Path.GetTempPath(), "VerifyAssemblyInGacButNotInProfileIsNotResolved");
            string targetFrameworkDirectory = Path.Combine(fullFrameworkDirectory, "Profiles", "Client");
            useFrameworkFileExists = true;
            string fullRedistListContents =
            "<FileList Redist='Microsoft-Windows-CLRCoreComp' >" +
                "<File AssemblyName='System' Version='9.0.0.0' PublicKeyToken='b77a5c561934e089' Culture='Neutral'/>" +
            "</FileList >";

            try
            {
                // Create a generic redist list with system.xml and microsoft.build.engine.
                string profileRedistList;
                string fullRedistList;
                GenerateRedistAndProfileXmlLocations(fullRedistListContents, _engineOnlySubset, out profileRedistList, out fullRedistList, fullFrameworkDirectory, targetFrameworkDirectory);

                ResolveAssemblyReference t = new ResolveAssemblyReference();
                MockEngine e = new MockEngine(_output);
                t.BuildEngine = e;
                TaskItem item = new TaskItem(@"DependsOnOnlyv4Assemblies, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089");
                t.Assemblies = new ITaskItem[] { item };
                t.SearchPaths = new string[] { s_myComponents40ComponentPath, "{GAC}" };
                t.TargetFrameworkDirectories = new string[] { targetFrameworkDirectory };
                t.InstalledAssemblyTables = new ITaskItem[] { new TaskItem(profileRedistList) };
                t.IgnoreDefaultInstalledAssemblyTables = true;
                t.FullFrameworkFolders = new string[] { fullFrameworkDirectory };
                t.LatestTargetFrameworkDirectories = new string[] { fullFrameworkDirectory };
                t.ProfileName = "Client";
                t.TargetFrameworkMoniker = ".NETFramework, Version=4.0";

                bool success = Execute(t, false);
                Console.Out.WriteLine(e.Log);
                Assert.True(success); // "Expected no errors."
                Assert.Empty(t.ResolvedFiles); // "Expected no files to resolved."
                string warningMessage = t.Log.FormatResourceString("ResolveAssemblyReference.FailBecauseDependentAssemblyInExclusionList", "DependsOnOnlyv4Assemblies, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089", "SysTem, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", t.TargetFrameworkMoniker);
                e.AssertLogContains(warningMessage);
            }
            finally
            {
                useFrameworkFileExists = false;
                if (Directory.Exists(fullFrameworkDirectory))
                {
                    FileUtilities.DeleteWithoutTrailingBackslash(fullFrameworkDirectory, true);
                }
            }
        }

        /// <summary>
        /// Make sure when reading in the full framework redist list or when reading in the white list xml files.
        /// Errors in reading the file should be logged as warnings and no assemblies should be excluded.
        ///
        /// </summary>
        [Fact]
        public void VerifyProfileErrorsAreLogged()
        {
            string fullFrameworkDirectory = Path.Combine(Path.GetTempPath(), "VerifyProfileErrorsAreLogged");
            string targetFrameworkDirectory = Path.Combine(fullFrameworkDirectory, "Profiles", "Client");
            try
            {
                string fullRedistListContentsErrors =
                  "<FileList Redist='Microsoft-Windows-CLRCoreComp'>" +
                        "File AssemblyName='System.Xml' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' >" +
                        "File AssemblyName='Microsoft.Build.Engine' Version='2.0.0.0' PublicKeyToken='<KEY>' Culture='Neutral' FileVersion='2.0.50727.208' InGAC='true' >" +
                   "";

                // Create a generic redist list with system.xml and microsoft.build.engine.
                string profileRedistList;
                string fullRedistList;
                GenerateRedistAndProfileXmlLocations(fullRedistListContentsErrors, _engineOnlySubset, out profileRedistList, out fullRedistList, fullFrameworkDirectory, targetFrameworkDirectory);

                ResolveAssemblyReference t = new ResolveAssemblyReference();
                MockEngine e = new MockEngine(_output);
                t.BuildEngine = e;
                t.Assemblies = new ITaskItem[] { new TaskItem("Microsoft.Build.Engine"), new TaskItem("System.Xml") };
                t.SearchPaths = new string[] { @"{TargetFrameworkDirectory}", fullFrameworkDirectory };
                t.TargetFrameworkDirectories = new string[] { targetFrameworkDirectory };
                t.InstalledAssemblyTables = new ITaskItem[] { new TaskItem(profileRedistList) };
                t.IgnoreDefaultInstalledAssemblyTables = true;

                ITaskItem item = new TaskItem(fullRedistList);
                item.SetMetadata("FrameworkDirectory", Path.GetDirectoryName(fullRedistList));
                t.FullFrameworkAssemblyTables = new ITaskItem[] { item };
                t.ProfileName = "Client";

                string microsoftBuildEnginePath = Path.Combine(fullFrameworkDirectory, "Microsoft.Build.Engine.dll");
                string systemXmlPath = Path.Combine(targetFrameworkDirectory, "System.Xml.dll");

                bool success = GenerateHelperDelegatesAndExecuteTask(t, microsoftBuildEnginePath, systemXmlPath);
                Assert.True(success); // "Expected errors."
                Assert.Equal(2, t.ResolvedFiles.Length); // "Expected two resolved assembly."
                e.AssertLogContains("MSB3263");
            }
            finally
            {
                if (Directory.Exists(fullFrameworkDirectory))
                {
                    FileUtilities.DeleteWithoutTrailingBackslash(fullFrameworkDirectory, true);
                }
            }
        }

        /// <summary>
        /// Generate the full framework and profile redist list directories and files
        /// </summary>
        private static void GenerateRedistAndProfileXmlLocations(string fullRedistContents, string profileListContents, out string profileRedistList, out string fullRedistList, string fullFrameworkDirectory, string targetFrameworkDirectory)
        {
            fullRedistList = Path.Combine(fullFrameworkDirectory, "RedistList", "FrameworkList.xml");
            string redistDirectory = Path.GetDirectoryName(fullRedistList);
            if (Directory.Exists(redistDirectory))
            {
                FileUtilities.DeleteWithoutTrailingBackslash(redistDirectory);
            }

            Directory.CreateDirectory(redistDirectory);

            File.WriteAllText(fullRedistList, fullRedistContents);

            profileRedistList = Path.Combine(targetFrameworkDirectory, "RedistList", "FrameworkList.xml");

            redistDirectory = Path.GetDirectoryName(profileRedistList);
            if (Directory.Exists(redistDirectory))
            {
                FileUtilities.DeleteWithoutTrailingBackslash(redistDirectory);
            }

            Directory.CreateDirectory(redistDirectory);

            File.WriteAllText(profileRedistList, profileListContents);
        }
    }
}


<|start_filename|>src/Build/BackEnd/Components/Communications/LogMessagePacket.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Generic;

using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using TaskItem = Microsoft.Build.Execution.ProjectItemInstance.TaskItem;

namespace Microsoft.Build.BackEnd
{
    /// <summary>
    /// A packet to encapsulate a BuildEventArg logging message.
    /// Contents:
    /// Build Event Type
    /// Build Event Args
    /// </summary>
    internal class LogMessagePacket : LogMessagePacketBase
    {
        /// <summary>
        /// Encapsulates the buildEventArg in this packet.
        /// </summary>
        internal LogMessagePacket(KeyValuePair<int, BuildEventArgs>? nodeBuildEvent)
            : base(nodeBuildEvent, new TargetFinishedTranslator(TranslateTargetFinishedEvent))
        {
        }

        /// <summary>
        /// Constructor for deserialization
        /// </summary>
        private LogMessagePacket(ITranslator translator)
            : base(translator)
        {
        }

        /// <summary>
        /// Factory for serialization
        /// </summary>
        static internal INodePacket FactoryForDeserialization(ITranslator translator)
        {
            return new LogMessagePacket(translator);
        }

        /// <summary>
        /// Translate the TargetOutputs for the target finished event.
        /// </summary>
        private static void TranslateTargetFinishedEvent(ITranslator translator, TargetFinishedEventArgs finishedEvent)
        {
            List<TaskItem> targetOutputs = null;
            if (translator.Mode == TranslationDirection.WriteToStream)
            {
                if (finishedEvent.TargetOutputs != null)
                {
                    targetOutputs = new List<TaskItem>();
                    foreach (TaskItem item in finishedEvent.TargetOutputs)
                    {
                        targetOutputs.Add(item);
                    }
                }
            }

            translator.Translate<TaskItem>(ref targetOutputs, TaskItem.FactoryForDeserialization);

            if (translator.Mode == TranslationDirection.ReadFromStream)
            {
                finishedEvent.TargetOutputs = targetOutputs;
            }
        }
    }
}


<|start_filename|>src/Package/Microsoft.Build.UnGAC/Program.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;

namespace Microsoft.Build.UnGAC
{
    /// <summary>
    /// Original Issue: https://github.com/dotnet/msbuild/issues/5183
    /// This tool was created to help prevent customers from putting MSBuild assemblies in the Global Assembly Cache.
    /// It runs at VS install-time as well as repair-time.
    /// It is intended to run as best effort. Meaning that if it fails, we avoid throwing and instead log it.
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                string[] assembliesToUnGAC =
                {
                    "Microsoft.Build, Version=15.1.0.0",
                    "Microsoft.Build.Engine, Version=15.1.0.0",
                    "Microsoft.Build.Framework, Version=15.1.0.0",
                    "Microsoft.Build.Tasks.Core, Version=15.1.0.0",
                    "Microsoft.Build.Utilities.Core, Version=15.1.0.0",
                    "Microsoft.Build.Conversion.Core, Version=15.1.0.0"
                };

                uint hresult = NativeMethods.CreateAssemblyCache(out IAssemblyCache assemblyCache, 0);

                // Most significant bit is set, meaning there was an error in the Hresult.
                if ((hresult >> 31) == 1)
                {
                    Console.WriteLine($"Could not successfully call CreateAssemblyCache. HResult: {hresult}");
                    Console.WriteLine("Exiting without removing assemblies from the GAC...");
                    return;
                }

                foreach (string assembly in assembliesToUnGAC)
                {
                    hresult = assemblyCache.UninstallAssembly(dwFlags: 0, pszAssemblyName: assembly, pRefData: IntPtr.Zero, pulDisposition: 0);

                    Console.WriteLine($"Tried to remove {assembly} from the GAC. HResult: 0x{hresult:X8}");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine($"Caught an exception! We don't want to throw because we want MSBuild to install.\n" + e.ToString());
            }
        }
    }
}


<|start_filename|>src/Build/BackEnd/Components/RequestBuilder/ITargetBuilderCallback.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using ElementLocation = Microsoft.Build.Construction.ElementLocation;
using Microsoft.Build.Execution;
using System.Threading.Tasks;

namespace Microsoft.Build.BackEnd
{
    /// <summary>
    /// Interface implemented by the Target Builder which allows tasks to invoke targets and build projects.
    /// </summary>
    internal interface ITargetBuilderCallback : IRequestBuilderCallback
    {
        /// <summary>
        /// Invokes the specified targets using Dev9 behavior.  
        /// </summary>
        /// <param name="targets">The targets to build.</param>
        /// <param name="continueOnError">True to continue building the remaining targets if one fails.</param>
        /// <param name="referenceLocation">The <see cref="ElementLocation"/> of the reference.</param>
        /// <returns>The results for each target.</returns>
        /// <remarks>
        /// The target is run using the data context of the Project, rather than the data context 
        /// of the current target.  This has the following effects:
        /// 1. Data visible to the CALLING target at the time it was first invoked is the only
        ///    data which the CALLED target can see.  No changes made between the time the CALLING
        ///    target starts and the CALLED target starts are visible to the CALLED target.
        /// 2. Items and Properties modified by the CALLED target are not visible to the CALLING
        ///    target, even after the CALLED target returns.  However, any changes made to
        ///    items and properties by the CALLING target will override any changes made by the
        ///    CALLED target.
        /// </remarks>
        Task<ITargetResult[]> LegacyCallTarget(string[] targets, bool continueOnError, ElementLocation referenceLocation);
    }
}


<|start_filename|>src/Build/Graph/ProjectInterpretation.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
using System.Linq;
using Microsoft.Build.BackEnd;
using Microsoft.Build.Collections;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Exceptions;
using Microsoft.Build.Execution;
using Microsoft.Build.Shared;

namespace Microsoft.Build.Graph
{
    internal sealed class ProjectInterpretation
    {
        private const string FullPathMetadataName = "FullPath";
        private const string ToolsVersionMetadataName = "ToolsVersion";
        private const string SetConfigurationMetadataName = "SetConfiguration";
        private const string SetPlatformMetadataName = "SetPlatform";
        private const string SetTargetFrameworkMetadataName = "SetTargetFramework";
        private const string GlobalPropertiesToRemoveMetadataName = "GlobalPropertiesToRemove";
        private const string ProjectReferenceTargetIsOuterBuildMetadataName = "OuterBuild";
        private const string InnerBuildReferenceItemName = "_ProjectSelfReference";
        internal static string TransitiveReferenceItemName = "_TransitiveProjectReference";
        internal const string AddTransitiveProjectReferencesInStaticGraphPropertyName = "AddTransitiveProjectReferencesInStaticGraph";

        private static readonly char[] PropertySeparator = MSBuildConstants.SemicolonChar;

        public static ProjectInterpretation Instance = new ProjectInterpretation();

        private ProjectInterpretation()
        {
        }

        private static readonly ImmutableList<GlobalPropertiesModifier> ModifierForNonMultitargetingNodes = new[] {(GlobalPropertiesModifier) ProjectReferenceGlobalPropertiesModifier}.ToImmutableList();

        internal enum ProjectType
        {
            OuterBuild, InnerBuild, NonMultitargeting
        }

        internal readonly struct ReferenceInfo
        {
            public ConfigurationMetadata ReferenceConfiguration { get; }
            public ProjectItemInstance ProjectReferenceItem { get; }

            public ReferenceInfo(ConfigurationMetadata referenceConfiguration, ProjectItemInstance projectReferenceItem)
            {
                ReferenceConfiguration = referenceConfiguration;
                ProjectReferenceItem = projectReferenceItem;
            }
        }

        public IEnumerable<ReferenceInfo> GetReferences(ProjectInstance requesterInstance)
        {
            IEnumerable<ProjectItemInstance> projectReferenceItems;
            IEnumerable<GlobalPropertiesModifier> globalPropertiesModifiers = null;

            switch (GetProjectType(requesterInstance))
            {
                case ProjectType.OuterBuild:
                    projectReferenceItems = ConstructInnerBuildReferences(requesterInstance);
                    break;
                case ProjectType.InnerBuild:
                    globalPropertiesModifiers = ModifierForNonMultitargetingNodes.Add((parts, reference) => parts.AddPropertyToUndefine(GetInnerBuildPropertyName(requesterInstance)));
                    projectReferenceItems = requesterInstance.GetItems(ItemTypeNames.ProjectReference);
                    break;
                case ProjectType.NonMultitargeting:
                    globalPropertiesModifiers = ModifierForNonMultitargetingNodes;
                    projectReferenceItems = requesterInstance.GetItems(ItemTypeNames.ProjectReference);
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }

            foreach (var projectReferenceItem in projectReferenceItems)
            {
                if (!String.IsNullOrEmpty(projectReferenceItem.GetMetadataValue(ToolsVersionMetadataName)))
                {
                    throw new InvalidOperationException(
                        String.Format(
                            CultureInfo.InvariantCulture,
                            ResourceUtilities.GetResourceString(
                                "ProjectGraphDoesNotSupportProjectReferenceWithToolset"),
                            projectReferenceItem.EvaluatedInclude,
                            requesterInstance.FullPath));
                }

                var projectReferenceFullPath = projectReferenceItem.GetMetadataValue(FullPathMetadataName);

                var referenceGlobalProperties = GetGlobalPropertiesForItem(projectReferenceItem, requesterInstance.GlobalPropertiesDictionary, globalPropertiesModifiers);

                var referenceConfig = new ConfigurationMetadata(projectReferenceFullPath, referenceGlobalProperties);

                yield return new ReferenceInfo(referenceConfig, projectReferenceItem);
            }
        }

        private static string GetInnerBuildPropertyValue(ProjectInstance project)
        {
            return project.GetPropertyValue(GetInnerBuildPropertyName(project));
        }

        private static string GetInnerBuildPropertyName(ProjectInstance project)
        {
            return project.GetPropertyValue(PropertyNames.InnerBuildProperty);
        }

        private static string GetInnerBuildPropertyValues(ProjectInstance project)
        {
            return project.GetPropertyValue(project.GetPropertyValue(PropertyNames.InnerBuildPropertyValues));
        }

        internal static ProjectType GetProjectType(ProjectInstance project)
        {
            var isOuterBuild = String.IsNullOrWhiteSpace(GetInnerBuildPropertyValue(project)) && !String.IsNullOrWhiteSpace(GetInnerBuildPropertyValues(project));
            var isInnerBuild = !String.IsNullOrWhiteSpace(GetInnerBuildPropertyValue(project));

            ErrorUtilities.VerifyThrow(!(isOuterBuild && isInnerBuild), $"A project cannot be an outer and inner build at the same time: ${project.FullPath}");

            return isOuterBuild
                ? ProjectType.OuterBuild
                : isInnerBuild
                    ? ProjectType.InnerBuild
                    : ProjectType.NonMultitargeting;
        }

        /// <summary>
        /// To avoid calling nuget at graph construction time, the graph is initially constructed with outer build nodes referencing inner build nodes.
        /// However, at build time, for non root outer builds, the inner builds are NOT referenced by the outer build, but by the nodes referencing the
        /// outer build. Change the graph to mimic this behaviour.
        /// Examples
        /// OuterAsRoot -> Inner go to OuterAsRoot -> Inner. Inner builds remain the same, parented to their outer build
        /// Node -> Outer -> Inner go to: Node -> Outer; Node->Inner; Outer -> empty. Inner builds get reparented to Node
        /// </summary>
        public void ReparentInnerBuilds(Dictionary<ConfigurationMetadata, ParsedProject> allNodes, GraphBuilder graphBuilder)
        {
            foreach (var node in allNodes)
            {
                var outerBuild = node.Value.GraphNode;

                if (GetProjectType(outerBuild.ProjectInstance) == ProjectType.OuterBuild && outerBuild.ReferencingProjects.Count != 0)
                {
                    foreach (var innerBuild in outerBuild.ProjectReferences)
                    {
                        foreach (var outerBuildReferencingProject in outerBuild.ReferencingProjects)
                        {
                            // Which edge should be used to connect the outerBuildReferencingProject to the inner builds?
                            // Decided to use the outerBuildBuildReferencingProject -> outerBuild edge in order to preserve any extra metadata
                            // information that may be present on the edge, like the "Targets" metadata which specifies what
                            // targets to call on the references.
                            var newInnerBuildEdge = graphBuilder.Edges[(outerBuildReferencingProject, outerBuild)];

                            if (outerBuildReferencingProject.ProjectReferences.Contains(innerBuild))
                            {
                                graphBuilder.Edges.TryGetEdge((outerBuildReferencingProject, innerBuild), out var existingEdge);

                                ErrorUtilities.VerifyThrow(
                                    graphBuilder.Edges[(outerBuildReferencingProject, innerBuild)]
                                        .ItemType.Equals(
                                            TransitiveReferenceItemName,
                                            StringComparison.OrdinalIgnoreCase),
                                    "Only transitive references may reference inner builds that got generated by outer builds");

                                outerBuildReferencingProject.RemoveReference(innerBuild, graphBuilder.Edges);
                            }

                            outerBuildReferencingProject.AddProjectReference(innerBuild, newInnerBuildEdge, graphBuilder.Edges);
                        }
                    }

                    outerBuild.RemoveReferences(graphBuilder.Edges);
                }
            }
        }

        private static IEnumerable<ProjectItemInstance> ConstructInnerBuildReferences(ProjectInstance outerBuild)
        {
            var globalPropertyName = GetInnerBuildPropertyName(outerBuild);
            var globalPropertyValues = GetInnerBuildPropertyValues(outerBuild);

            ErrorUtilities.VerifyThrow(!String.IsNullOrWhiteSpace(globalPropertyName), "Must have an inner build property");
            ErrorUtilities.VerifyThrow(!String.IsNullOrWhiteSpace(globalPropertyValues), "Must have values for the inner build property");

            foreach (var globalPropertyValue in ExpressionShredder.SplitSemiColonSeparatedList(globalPropertyValues))
            {
                yield return new ProjectItemInstance(
                    project: outerBuild,
                    itemType: InnerBuildReferenceItemName,
                    includeEscaped: outerBuild.FullPath,
                    directMetadata: new[] {new KeyValuePair<string, string>(ItemMetadataNames.PropertiesMetadataName, $"{globalPropertyName}={globalPropertyValue}")},
                    definingFileEscaped: outerBuild.FullPath);
            }
        }

        /// <summary>
        ///     Gets the effective global properties for a project reference item.
        /// </summary>
        /// <remarks>
        ///     The behavior of this method should match the logic in the SDK
        /// </remarks>
        private static GlobalPropertyPartsForMSBuildTask ProjectReferenceGlobalPropertiesModifier(
            GlobalPropertyPartsForMSBuildTask defaultParts,
            ProjectItemInstance projectReference
        )
        {
            // ProjectReference defines yet another metadata name containing properties to undefine. Merge it in if non empty.
            var globalPropertiesToRemove = SplitPropertyNames(projectReference.GetMetadataValue(GlobalPropertiesToRemoveMetadataName));

            var newUndefineProperties = defaultParts.UndefineProperties;

            newUndefineProperties = newUndefineProperties.AddRange(defaultParts.UndefineProperties);
            newUndefineProperties = newUndefineProperties.AddRange(globalPropertiesToRemove);

            newUndefineProperties.Add("InnerBuildProperty");

            var newProperties = defaultParts.Properties;

            // The properties on the project reference supersede the ones from the MSBuild task instead of appending.
            if (newProperties.Count == 0)
            {
                // TODO: Mimic AssignProjectConfiguration's behavior for determining the values for these.
                var setConfigurationString = projectReference.GetMetadataValue(SetConfigurationMetadataName);
                var setPlatformString = projectReference.GetMetadataValue(SetPlatformMetadataName);
                var setTargetFrameworkString = projectReference.GetMetadataValue(SetTargetFrameworkMetadataName);

                if (!String.IsNullOrEmpty(setConfigurationString) || !String.IsNullOrEmpty(setPlatformString) || !String.IsNullOrEmpty(setTargetFrameworkString))
                {
                    newProperties = SplitPropertyNameValuePairs(
                        ItemMetadataNames.PropertiesMetadataName,
                        $"{setConfigurationString};{setPlatformString};{setTargetFrameworkString}").ToImmutableDictionary();
                }
            }

            return new GlobalPropertyPartsForMSBuildTask(newProperties, defaultParts.AdditionalProperties, newUndefineProperties);
        }

        private readonly struct GlobalPropertyPartsForMSBuildTask
        {
            public ImmutableDictionary<string, string> Properties { get; }
            public ImmutableDictionary<string, string> AdditionalProperties { get; }
            public ImmutableList<string> UndefineProperties { get; }

            public GlobalPropertyPartsForMSBuildTask(
                ImmutableDictionary<string, string> properties,
                ImmutableDictionary<string, string> additionalProperties,
                ImmutableList<string> undefineProperties)
            {
                Properties = properties;
                AdditionalProperties = additionalProperties;
                UndefineProperties = undefineProperties;
            }

            public bool AllEmpty()
            {
                return Properties.Count == 0 && AdditionalProperties.Count == 0 && UndefineProperties.Count == 0;
            }

            public GlobalPropertyPartsForMSBuildTask AddPropertyToUndefine(string propertyToUndefine)
            {
                return new GlobalPropertyPartsForMSBuildTask(Properties, AdditionalProperties, UndefineProperties.Add(propertyToUndefine));
            }
        }

        delegate GlobalPropertyPartsForMSBuildTask GlobalPropertiesModifier(GlobalPropertyPartsForMSBuildTask defaultParts, ProjectItemInstance projectReference);

        /// <summary>
        ///     Gets the effective global properties for an item that will get passed to <see cref="MSBuild.Projects"/>.
        /// </summary>
        /// <remarks>
        ///     The behavior of this method matches the hardcoded behaviour of the msbuild task
        ///     and the <paramref name="globalPropertyModifiers"/> parameter can contain other mutations done at build time in targets / tasks
        /// </remarks>
        private static PropertyDictionary<ProjectPropertyInstance> GetGlobalPropertiesForItem(
            ProjectItemInstance projectReference,
            PropertyDictionary<ProjectPropertyInstance> requesterGlobalProperties,
            IEnumerable<GlobalPropertiesModifier> globalPropertyModifiers = null)
        {
            ErrorUtilities.VerifyThrowInternalNull(projectReference, nameof(projectReference));
            ErrorUtilities.VerifyThrowArgumentNull(requesterGlobalProperties, nameof(requesterGlobalProperties));

            var properties = SplitPropertyNameValuePairs(ItemMetadataNames.PropertiesMetadataName, projectReference.GetMetadataValue(ItemMetadataNames.PropertiesMetadataName));
            var additionalProperties = SplitPropertyNameValuePairs(ItemMetadataNames.AdditionalPropertiesMetadataName, projectReference.GetMetadataValue(ItemMetadataNames.AdditionalPropertiesMetadataName));
            var undefineProperties = SplitPropertyNames(projectReference.GetMetadataValue(ItemMetadataNames.UndefinePropertiesMetadataName));

            var defaultParts = new GlobalPropertyPartsForMSBuildTask(properties.ToImmutableDictionary(), additionalProperties.ToImmutableDictionary(), undefineProperties.ToImmutableList());

            var globalPropertyParts = globalPropertyModifiers?.Aggregate(defaultParts, (currentProperties, modifier) => modifier(currentProperties, projectReference)) ?? defaultParts;

            if (globalPropertyParts.AllEmpty())
            {
                return requesterGlobalProperties;
            }

            // Make a copy to avoid mutating the requester
            var globalProperties = new PropertyDictionary<ProjectPropertyInstance>(requesterGlobalProperties);

            // Append and remove properties as specified by the various metadata
            MergeIntoPropertyDictionary(globalProperties, globalPropertyParts.Properties);
            MergeIntoPropertyDictionary(globalProperties, globalPropertyParts.AdditionalProperties);
            RemoveFromPropertyDictionary(globalProperties, globalPropertyParts.UndefineProperties);

            return globalProperties;
        }

        private static void MergeIntoPropertyDictionary(
            PropertyDictionary<ProjectPropertyInstance> destination,
            IReadOnlyDictionary<string, string> source)
        {
            foreach (var pair in source)
            {
                destination[pair.Key] = ProjectPropertyInstance.Create(pair.Key, pair.Value);
            }
        }

        private static IReadOnlyDictionary<string, string> SplitPropertyNameValuePairs(string syntaxName, string propertyNameAndValuesString)
        {
            if (String.IsNullOrEmpty(propertyNameAndValuesString))
            {
                return ImmutableDictionary<string, string>.Empty;
            }

            if (PropertyParser.GetTableWithEscaping(
                null,
                null,
                null,
                propertyNameAndValuesString.Split(PropertySeparator, StringSplitOptions.RemoveEmptyEntries),
                out var propertiesTable))
            {
                return propertiesTable;
            }

            throw new InvalidProjectFileException(
                String.Format(
                    CultureInfo.InvariantCulture,
                    ResourceUtilities.GetResourceString("General.InvalidPropertyError"),
                    syntaxName,
                    propertyNameAndValuesString));
        }

        private static IReadOnlyCollection<string> SplitPropertyNames(string propertyNamesString)
        {
            if (String.IsNullOrEmpty(propertyNamesString))
            {
                return ImmutableArray<string>.Empty;
            }

            return propertyNamesString.Split(PropertySeparator, StringSplitOptions.RemoveEmptyEntries);
        }

        private static void RemoveFromPropertyDictionary(
            PropertyDictionary<ProjectPropertyInstance> properties,
            IReadOnlyCollection<string> propertyNamesToRemove)
        {
            foreach (var propertyName in propertyNamesToRemove)
            {
                properties.Remove(propertyName);
            }
        }

        public readonly struct TargetsToPropagate
        {
            private readonly ImmutableList<string> _outerBuildTargets;
            private readonly ImmutableList<string> _allTargets;

            private TargetsToPropagate(ImmutableList<string> outerBuildTargets, ImmutableList<string> nonOuterBuildTargets)
            {
                _outerBuildTargets = outerBuildTargets;

                // This is used as the list of entry targets for both inner builds and non-multitargeting projects.
                // It represents the concatenation of outer build targets and non outer build targets, in this order.
                // Non-multitargeting projects use these targets because they act as both outer and inner builds.
                _allTargets = outerBuildTargets.AddRange(nonOuterBuildTargets);
            }

            /// <summary>
            /// Given a project and a set of entry targets the project would get called with,
            /// parse the project's project reference target specification and compute how the target would call its references.
            ///
            /// The calling code should then call <see cref="GetApplicableTargetsForReference"/> for each of the project's references
            /// to get the concrete targets for each reference.
            /// </summary>
            /// <param name="project">Project containing the PRT protocol</param>
            /// <param name="entryTargets">Targets with which <paramref name="project"/> will get called</param>
            /// <returns></returns>
            public static TargetsToPropagate FromProjectAndEntryTargets(ProjectInstance project, ImmutableList<string> entryTargets)
            {
                var targetsForOuterBuild = ImmutableList.CreateBuilder<string>();
                var targetsForInnerBuild = ImmutableList.CreateBuilder<string>();

                var projectReferenceTargets = project.GetItems(ItemTypeNames.ProjectReferenceTargets);

                foreach (var entryTarget in entryTargets)
                {
                    foreach (var projectReferenceTarget in projectReferenceTargets)
                    {
                        if (projectReferenceTarget.EvaluatedInclude.Equals(entryTarget, StringComparison.OrdinalIgnoreCase))
                        {
                            var targetsMetadataValue = projectReferenceTarget.GetMetadataValue(ItemMetadataNames.ProjectReferenceTargetsMetadataName);

                            var targetsAreForOuterBuild = MSBuildStringIsTrue(projectReferenceTarget.GetMetadataValue(ProjectReferenceTargetIsOuterBuildMetadataName));

                            var targets = ExpressionShredder.SplitSemiColonSeparatedList(targetsMetadataValue).ToArray();

                            if (targetsAreForOuterBuild)
                            {
                                targetsForOuterBuild.AddRange(targets);
                            }
                            else
                            {
                                targetsForInnerBuild.AddRange(targets);
                            }
                        }
                    }
                }

                return new TargetsToPropagate(targetsForOuterBuild.ToImmutable(), targetsForInnerBuild.ToImmutable());
            }

            public ImmutableList<string> GetApplicableTargetsForReference(ProjectInstance reference)
            {
                return (GetProjectType(reference)) switch
                {
                    ProjectType.InnerBuild => _allTargets,
                    ProjectType.OuterBuild => _outerBuildTargets,
                    ProjectType.NonMultitargeting => _allTargets,
                    _ => throw new ArgumentOutOfRangeException(),
                };
            }
        }

        public bool RequiresTransitiveProjectReferences(ProjectInstance projectInstance)
        {
            // Outer builds do not get edges based on ProjectReference or their transitive closure, only inner builds do.
            if (GetProjectType(projectInstance) == ProjectType.OuterBuild)
            {
                return false;
            }

            // special case for Quickbuild which updates msbuild binaries independent of props/targets. Remove this when all QB repos will have
            // migrated to new enough Visual Studio versions whose Microsoft.Managed.After.Targets enable transitive references.
            if (string.IsNullOrWhiteSpace(projectInstance.GetPropertyValue(AddTransitiveProjectReferencesInStaticGraphPropertyName)) &&
                MSBuildStringIsTrue(projectInstance.GetPropertyValue("UsingMicrosoftNETSdk")) &&
                MSBuildStringIsFalse(projectInstance.GetPropertyValue("DisableTransitiveProjectReferences")))
            {
                return true;
            }

            return MSBuildStringIsTrue(
                projectInstance.GetPropertyValue(AddTransitiveProjectReferencesInStaticGraphPropertyName));
        }

        private static bool MSBuildStringIsTrue(string msbuildString) =>
            ConversionUtilities.ConvertStringToBool(msbuildString, nullOrWhitespaceIsFalse: true);

        private static bool MSBuildStringIsFalse(string msbuildString) => !MSBuildStringIsTrue(msbuildString);
    }
}


<|start_filename|>src/Build/Evaluation/Conditionals/OperatorExpressionNode.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using Microsoft.Build.Shared;

namespace Microsoft.Build.Evaluation
{
    /// <summary>
    /// Base class for nodes that are operators (have children in the parse tree)
    /// </summary>
    internal abstract class OperatorExpressionNode : GenericExpressionNode
    {
        /// <summary>
        /// Numeric evaluation is never allowed for operators
        /// </summary>
        internal override double NumericEvaluate(ConditionEvaluator.IConditionEvaluationState state)
        {
            // Should be unreachable: all calls check CanNumericEvaluate() first
            ErrorUtilities.VerifyThrow(false, "Cannot numeric evaluate an operator");
            return 0.0D;
        }

        /// <summary>
        /// Version evaluation is never allowed for operators
        /// </summary>
        internal override Version VersionEvaluate(ConditionEvaluator.IConditionEvaluationState state)
        {
            ErrorUtilities.VerifyThrow(false, "Cannot version evaluate an operator");
            return null;
        }

        /// <summary>
        /// Whether boolean evaluation is allowed: always allowed for operators
        /// </summary>
        internal override bool CanBoolEvaluate(ConditionEvaluator.IConditionEvaluationState state)
        {
            return true;
        }

        /// <summary>
        /// Whether the node can be evaluated as a numeric: by default,
        /// this is not allowed
        /// </summary>
        internal override bool CanNumericEvaluate(ConditionEvaluator.IConditionEvaluationState state)
        {
            return false;
        }

        /// <summary>
        /// Whether the node can be evaluated as a version: by default,
        /// this is not allowed
        /// </summary>
        internal override bool CanVersionEvaluate(ConditionEvaluator.IConditionEvaluationState state)
        {
            return false;
        }

        /// <summary>
        /// Value after any item and property expressions are expanded
        /// </summary>
        /// <returns></returns>
        internal override string GetExpandedValue(ConditionEvaluator.IConditionEvaluationState state)
        {
            return null;
        }

        /// <summary>
        /// Value before any item and property expressions are expanded
        /// </summary>
        /// <returns></returns>
        internal override string GetUnexpandedValue(ConditionEvaluator.IConditionEvaluationState state)
        {
            return null;
        }

        /// <summary>
        /// If any expression nodes cache any state for the duration of evaluation, 
        /// now's the time to clean it up
        /// </summary>
        internal override void ResetState()
        {
            LeftChild?.ResetState();

            RightChild?.ResetState();
        }

        /// <summary>
        /// Storage for the left child
        /// </summary>
        internal GenericExpressionNode LeftChild { set; get; }

        /// <summary>
        /// Storage for the right child
        /// </summary>
        internal GenericExpressionNode RightChild { set; get; }

        #region REMOVE_COMPAT_WARNING
        internal override bool DetectAnd()
        {
            // Read the state of the current node
            bool detectedAnd = this.PossibleAndCollision;
            // Reset the flags on the current node
            this.PossibleAndCollision = false;
            // Process the children of the node if preset
            bool detectAndRChild = false;
            bool detectAndLChild = false;
            if (RightChild != null)
            {
                detectAndRChild = RightChild.DetectAnd();
            }
            if (LeftChild != null)
            {
                detectAndLChild = LeftChild.DetectAnd();
            }
            return detectedAnd || detectAndRChild || detectAndLChild;
        }

        internal override bool DetectOr()
        {
            // Read the state of the current node
            bool detectedOr = this.PossibleOrCollision;
            // Reset the flags on the current node
            this.PossibleOrCollision = false;
            // Process the children of the node if preset
            bool detectOrRChild = false;
            bool detectOrLChild = false;
            if (RightChild != null)
            {
                detectOrRChild = RightChild.DetectOr();
            }
            if (LeftChild != null)
            {
                detectOrLChild = LeftChild.DetectOr();
            }
            return detectedOr || detectOrRChild || detectOrLChild;
        }
        #endregion
    }
}


<|start_filename|>src/Build/Instance/ProjectTargetInstanceChild.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Build.BackEnd;
using Microsoft.Build.Shared;

using Microsoft.Build.Construction;

namespace Microsoft.Build.Execution
{
    /// <summary>
    /// Type for ProjectTaskInstance and ProjectPropertyGroupTaskInstance and ProjectItemGroupTaskInstance
    /// allowing them to be used in a single collection of target children
    /// </summary>
    public abstract class ProjectTargetInstanceChild : ITranslatable
    {
        /// <summary>
        /// Condition on the element
        /// </summary>
        public abstract string Condition { get; }

        /// <summary>
        /// Full path to the file in which the originating element was originally 
        /// defined.
        /// If it originated in a project that was not loaded and has never been 
        /// given a path, returns an empty string.
        /// </summary>
        public string FullPath
        {
            get { return Location.File; }
        }

        /// <summary>
        /// Location of the original element
        /// </summary>
        public abstract ElementLocation Location { get; }

        /// <summary>
        /// Location of the original condition attribute
        /// if any
        /// </summary>
        public abstract ElementLocation ConditionLocation { get; }

        void ITranslatable.Translate(ITranslator translator)
        {
            // all subclasses should be translateable
            ErrorUtilities.ThrowInternalErrorUnreachable();
        }

        internal static ProjectTargetInstanceChild FactoryForDeserialization(ITranslator translator)
        {
            return translator.FactoryForDeserializingTypeWithName<ProjectTargetInstanceChild>();
        }
    }
}


<|start_filename|>src/Shared/FileDelegates.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.IO;

namespace Microsoft.Build.Shared
{
    /// <summary>
    /// delegate for System.IO.Directory.GetFiles, used for testing
    /// </summary>
    /// <param name="path">Directory path to start search for files in</param>
    /// <param name="searchPattern">pattern of files to match</param>
    /// <returns>string array of files which match search pattern</returns>
    internal delegate string[] DirectoryGetFiles(string path, string searchPattern);

    /// <summary>
    /// delegate for Directory.GetDirectories.
    /// </summary>
    /// <param name="path">The path to get directories for.</param>
    /// <param name="pattern">The pattern to search for.</param>
    /// <returns>An array of directories.</returns>
    internal delegate string[] GetDirectories(string path, string pattern);

    /// <summary>
    /// Delegate for System.IO.Directory.Exists
    /// </summary>
    /// <param name="path">Directory path to check if it exists</param>
    /// <returns>true if directory exists</returns>
    internal delegate bool DirectoryExists(string path);

    /// <summary>
    /// File exists delegate
    /// </summary>
    /// <param name="path">The path to check for existence.</param>
    /// <returns>'true' if the file exists.</returns>
    internal delegate bool FileExists(string path);

    /// <summary>
    /// File.Copy delegate
    /// </summary>
    /// <param name="source"></param>
    /// <param name="destination"></param>
    internal delegate void FileCopy(string source, string destination);

    /// <summary>
    /// File.Delete delegate
    /// </summary>
    /// <param name="path"></param>
    internal delegate void FileDelete(string path);

    /// <summary>
    /// File create delegate
    /// </summary>
    /// <param name="path">The path to create.</param>
    internal delegate FileStream FileCreate(string path);
}

<|start_filename|>src/Build.UnitTests/ChangeWaves_Tests.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Xunit;
using Shouldly;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Utilities;
using Microsoft.Build.UnitTests;
using Xunit.Abstractions;
using System;
using Microsoft.Build.Shared;

namespace Microsoft.Build.Engine.UnitTests
{
    sealed public class ChangeWaves_Tests
    {
        ITestOutputHelper _output;
        public ChangeWaves_Tests(ITestOutputHelper output)
        {
            _output = output;
        }

        /// <summary>
        /// Performs necessary operations for setting the MSBuildDisableFeaturesFromVersion environment variable.
        /// This is required because Change Waves is static and stale values can be seen between tests in the same assembly.
        /// </summary>
        /// <param name="wave">The version to set as the current Change Wave.</param>
        private void SetChangeWave(string wave, TestEnvironment env)
        {
            ChangeWaves.ResetStateForTests();
            env.SetEnvironmentVariable("MSBUILDDISABLEFEATURESFROMVERSION", wave);
            BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly();
        }

        /// <summary>
        /// Helper function to build a simple project based on a particular change wave being set.
        /// Call SetChangeWave on your TestEnvironment before calling this function.
        /// </summary>
        /// <param name="testEnvironment">The TestEnvironment being used for this test.</param>
        /// <param name="versionToCheckAgainstCurrentChangeWave">The version to compare to the current set Change Wave.</param>
        /// <param name="currentChangeWaveShouldUltimatelyResolveTo">What the project property for the environment variable MSBuildDisableFeaturesFromVersion ultimately resolves to.</param>
        /// <param name="warningCodesLogShouldContain">An array of warning codes that should exist in the resulting log. Ex: "MSB4271".</param>
        private void buildSimpleProjectAndValidateChangeWave(TestEnvironment testEnvironment, Version versionToCheckAgainstCurrentChangeWave, Version currentChangeWaveShouldUltimatelyResolveTo, params string[] warningCodesLogShouldContain)
        {
            bool isThisWaveEnabled = versionToCheckAgainstCurrentChangeWave < currentChangeWaveShouldUltimatelyResolveTo || currentChangeWaveShouldUltimatelyResolveTo == ChangeWaves.EnableAllFeatures;

            ChangeWaves.AreFeaturesEnabled(versionToCheckAgainstCurrentChangeWave).ShouldBe(isThisWaveEnabled);

            string projectFile = $"" +
                $"<Project>" +
                    $"<Target Name='HelloWorld' Condition=\"$([MSBuild]::AreFeaturesEnabled('{versionToCheckAgainstCurrentChangeWave}')) and '$(MSBUILDDISABLEFEATURESFROMVERSION)' == '{currentChangeWaveShouldUltimatelyResolveTo}'\">" +
                        $"<Message Text='Hello World!'/>" +
                    $"</Target>" +
                $"</Project>";

            TransientTestFile file = testEnvironment.CreateFile("proj.csproj", projectFile);

            ProjectCollection collection = new ProjectCollection();
            MockLogger log = new MockLogger(_output);
            collection.RegisterLogger(log);

            Project p = collection.LoadProject(file.Path);
            p.Build().ShouldBeTrue();

            log.FullLog.Contains("Hello World!").ShouldBe(isThisWaveEnabled);

            if (warningCodesLogShouldContain != null)
            {
                log.WarningCount.ShouldBe(warningCodesLogShouldContain.Length);
                log.AssertLogContains(warningCodesLogShouldContain);
            }

            ChangeWaves.ResetStateForTests();
        }

        [Fact]
        public void EnableAllFeaturesBehindChangeWavesEnablesAllFeaturesBehindChangeWaves()
        {
            using (TestEnvironment env = TestEnvironment.Create())
            {
                SetChangeWave(ChangeWaves.EnableAllFeatures.ToString(), env);

                for (int i = 0; i < ChangeWaves.AllWaves.Length - 1; i++)
                {
                    buildSimpleProjectAndValidateChangeWave(testEnvironment: env,
                                                            versionToCheckAgainstCurrentChangeWave: ChangeWaves.AllWaves[i],
                                                            currentChangeWaveShouldUltimatelyResolveTo: ChangeWaves.EnableAllFeatures,
                                                            warningCodesLogShouldContain: null);
                }
            }
        }

        [Theory]
        [InlineData("16.8")]
        [InlineData("16.10")]
        [InlineData("17.0")]
        [InlineData("27.3")]
        public void NoChangeWaveSetMeansAllChangeWavesAreEnabled(string featureVersion)
        {
            using (TestEnvironment env = TestEnvironment.Create())
            {
                // Reset static ChangeWave
                SetChangeWave(string.Empty, env);
                Version featureAsVersion = Version.Parse(featureVersion);
                ChangeWaves.AreFeaturesEnabled(featureAsVersion).ShouldBe(true);

                buildSimpleProjectAndValidateChangeWave(testEnvironment: env,
                                                        versionToCheckAgainstCurrentChangeWave: featureAsVersion,
                                                        currentChangeWaveShouldUltimatelyResolveTo: ChangeWaves.EnableAllFeatures,
                                                        warningCodesLogShouldContain: null);
            }
        }

        [Theory]
        [InlineData("test")]
        [InlineData("16_8")]
        [InlineData("16x8")]
        [InlineData("garbage")]
        public void InvalidFormatThrowsWarningAndLeavesFeaturesEnabled(string disableFeaturesFromVersion)
        {
            using (TestEnvironment env = TestEnvironment.Create())
            {
                SetChangeWave(disableFeaturesFromVersion, env);

                buildSimpleProjectAndValidateChangeWave(testEnvironment: env,
                                                        versionToCheckAgainstCurrentChangeWave: ChangeWaves.HighestWave,
                                                        currentChangeWaveShouldUltimatelyResolveTo: ChangeWaves.EnableAllFeatures,
                                                        warningCodesLogShouldContain: "MSB4271");
            }
        }

        [Theory]
        [InlineData("0.8")]
        [InlineData("4.5")]
        [InlineData("10.0")]
        public void VersionTooLowClampsToLowestVersionInRotation(string disableFeaturesFromVersion)
        {
            using (TestEnvironment env = TestEnvironment.Create())
            {
                SetChangeWave(disableFeaturesFromVersion, env);

                // All waves should be disabled
                for (int i = 0; i < ChangeWaves.AllWaves.Length; i++)
                {
                    buildSimpleProjectAndValidateChangeWave(testEnvironment: env,
                                                            versionToCheckAgainstCurrentChangeWave: ChangeWaves.AllWaves[i],
                                                            currentChangeWaveShouldUltimatelyResolveTo: ChangeWaves.LowestWave,
                                                            warningCodesLogShouldContain: "MSB4272");
                }
            }
        }

        [Theory]
        [InlineData("100.10")]
        [InlineData("203.45")]
        public void VersionTooHighClampsToHighestVersionInRotation(string disableFeaturesFromVersion)
        {
            using (TestEnvironment env = TestEnvironment.Create())
            {
                SetChangeWave(disableFeaturesFromVersion, env);

                // all waves but the highest should pass
                for (int i = 0; i < ChangeWaves.AllWaves.Length - 1; i++)
                {
                    buildSimpleProjectAndValidateChangeWave(testEnvironment: env,
                                        versionToCheckAgainstCurrentChangeWave: ChangeWaves.AllWaves[i],
                                        currentChangeWaveShouldUltimatelyResolveTo: ChangeWaves.HighestWave,
                                        warningCodesLogShouldContain: "MSB4272");
                }

                // Make sure the last wave is disabled.
                buildSimpleProjectAndValidateChangeWave(testEnvironment: env,
                                                        versionToCheckAgainstCurrentChangeWave: ChangeWaves.AllWaves[ChangeWaves.AllWaves.Length - 1],
                                                        currentChangeWaveShouldUltimatelyResolveTo: ChangeWaves.HighestWave,
                                                        warningCodesLogShouldContain: "MSB4272");
            }
        }

        [Fact]
        public void VersionSetToValidValueButInvalidVersionSetsNextVersion()
        {
            using (TestEnvironment env = TestEnvironment.Create())
            {
                SetChangeWave($"{ChangeWaves.LowestWave.Major}.{ChangeWaves.LowestWave.Minor}.{ChangeWaves.LowestWave.Build + 1}", env);

                buildSimpleProjectAndValidateChangeWave(testEnvironment: env,
                                                        versionToCheckAgainstCurrentChangeWave: ChangeWaves.LowestWave,
                                                        currentChangeWaveShouldUltimatelyResolveTo: ChangeWaves.AllWaves[1],
                                                        warningCodesLogShouldContain: null);
            }
        }

        [Fact]
        public void CorrectlyDetermineEnabledFeatures()
        {
            using (TestEnvironment env = TestEnvironment.Create())
            {
                SetChangeWave(ChangeWaves.HighestWave.ToString(), env);

                for (int i = 0; i < ChangeWaves.AllWaves.Length - 1; i++)
                {
                    buildSimpleProjectAndValidateChangeWave(testEnvironment: env,
                                                            versionToCheckAgainstCurrentChangeWave: ChangeWaves.AllWaves[i],
                                                            currentChangeWaveShouldUltimatelyResolveTo: ChangeWaves.HighestWave,
                                                            warningCodesLogShouldContain: null);
                }

                // Make sure the last wave is disabled.
                buildSimpleProjectAndValidateChangeWave(testEnvironment: env,
                                                        versionToCheckAgainstCurrentChangeWave: ChangeWaves.AllWaves[ChangeWaves.AllWaves.Length - 1],
                                                        currentChangeWaveShouldUltimatelyResolveTo: ChangeWaves.HighestWave,
                                                        warningCodesLogShouldContain: null);
            }
        }

        [Fact]
        public void CorrectlyDetermineDisabledFeatures()
        {
            using (TestEnvironment env = TestEnvironment.Create())
            {
                SetChangeWave(ChangeWaves.LowestWave.ToString(), env);

                foreach (Version wave in ChangeWaves.AllWaves)
                {
                    buildSimpleProjectAndValidateChangeWave(testEnvironment: env,
                                                            versionToCheckAgainstCurrentChangeWave: wave,
                                                            currentChangeWaveShouldUltimatelyResolveTo: ChangeWaves.LowestWave,
                                                            warningCodesLogShouldContain: null);
                }
            }
        }
    }
}


<|start_filename|>src/Build/Evaluation/Conditionals/Parser.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using ElementLocation = Microsoft.Build.Construction.ElementLocation;

namespace Microsoft.Build.Evaluation
{
    using ILoggingService = Microsoft.Build.BackEnd.Logging.ILoggingService;

    [Flags]
    internal enum ParserOptions
    {
        None = 0x0,
        AllowProperties = 0x1,
        AllowItemLists = 0x2,
        AllowPropertiesAndItemLists = AllowProperties | AllowItemLists,
        AllowBuiltInMetadata = 0x4,
        AllowCustomMetadata = 0x8,
        AllowItemMetadata = AllowBuiltInMetadata | AllowCustomMetadata,
        AllowPropertiesAndItemMetadata = AllowProperties | AllowItemMetadata,
        AllowPropertiesAndCustomMetadata = AllowProperties | AllowCustomMetadata,
        AllowAll = AllowProperties | AllowItemLists | AllowItemMetadata
    };

    /// <summary>
    /// This class implements the grammar for complex conditionals.
    ///
    /// The usage is:
    ///    Parser p = new Parser(CultureInfo);
    ///    ExpressionTree t = p.Parse(expression, XmlNode);
    ///
    /// The expression tree can then be evaluated and re-evaluated as needed.
    /// </summary>
    /// <remarks>
    /// UNDONE: When we copied over the conditionals code, we didn't copy over the unit tests for scanner, parser, and expression tree.
    /// </remarks>
    internal sealed class Parser
    {
        private Scanner _lexer;
        private ParserOptions _options;
        private ElementLocation _elementLocation;
        internal int errorPosition = 0; // useful for unit tests

        #region REMOVE_COMPAT_WARNING

        private bool _warnedForExpression = false;

        private BuildEventContext _logBuildEventContext;
        /// <summary>
        ///  Location contextual information which are attached to logging events to 
        ///  say where they are in relation to the process, engine, project, target,task which is executing
        /// </summary>
        internal BuildEventContext LogBuildEventContext
        {
            get
            {
                return _logBuildEventContext;
            }
            set
            {
                _logBuildEventContext = value;
            }
        }
        private ILoggingService _loggingServices;
        /// <summary>
        /// Engine Logging Service reference where events will be logged to
        /// </summary>
        internal ILoggingService LoggingServices
        {
            set
            {
                _loggingServices = value;
            }

            get
            {
                return _loggingServices;
            }
        }
        #endregion

        internal Parser()
        {
            // nothing to see here, move along.
        }

        //
        // Main entry point for parser.
        // You pass in the expression you want to parse, and you get an
        // ExpressionTree out the back end.
        //
        internal GenericExpressionNode Parse(string expression, ParserOptions optionSettings, ElementLocation elementLocation)
        {
            // We currently have no support (and no scenarios) for disallowing property references
            // in Conditions.
            ErrorUtilities.VerifyThrow(0 != (optionSettings & ParserOptions.AllowProperties),
                "Properties should always be allowed.");

            _options = optionSettings;
            _elementLocation = elementLocation;

            _lexer = new Scanner(expression, _options);
            if (!_lexer.Advance())
            {
                errorPosition = _lexer.GetErrorPosition();
                ProjectErrorUtilities.VerifyThrowInvalidProject(false, elementLocation, _lexer.GetErrorResource(), expression, errorPosition, _lexer.UnexpectedlyFound);
            }
            GenericExpressionNode node = Expr(expression);
            if (!_lexer.IsNext(Token.TokenType.EndOfInput))
            {
                errorPosition = _lexer.GetErrorPosition();
                ProjectErrorUtilities.VerifyThrowInvalidProject(false, elementLocation, "UnexpectedTokenInCondition", expression, _lexer.IsNextString(), errorPosition);
            }
            return node;
        }

        //
        // Top node of grammar
        //    See grammar for how the following methods relate to each
        //    other.
        //
        private GenericExpressionNode Expr(string expression)
        {
            GenericExpressionNode node = BooleanTerm(expression);
            if (!_lexer.IsNext(Token.TokenType.EndOfInput))
            {
                node = ExprPrime(expression, node);
            }

            #region REMOVE_COMPAT_WARNING
            // Check for potential change in behavior
            if (LoggingServices != null && !_warnedForExpression &&
                node.PotentialAndOrConflict())
            {
                // We only want to warn once even if there multiple () sub expressions
                _warnedForExpression = true;

                // Log a warning regarding the fact the expression may have been evaluated
                // incorrectly in earlier version of MSBuild
                LoggingServices.LogWarning(_logBuildEventContext, null, new BuildEventFileInfo(_elementLocation), "ConditionMaybeEvaluatedIncorrectly", expression);
            }
            #endregion

            return node;
        }

        private GenericExpressionNode ExprPrime(string expression, GenericExpressionNode lhs)
        {
            if (Same(expression, Token.TokenType.EndOfInput))
            {
                return lhs;
            }
            else if (Same(expression, Token.TokenType.Or))
            {
                OperatorExpressionNode orNode = new OrExpressionNode();
                GenericExpressionNode rhs = BooleanTerm(expression);
                orNode.LeftChild = lhs;
                orNode.RightChild = rhs;
                return ExprPrime(expression, orNode);
            }
            else
            {
                // I think this is ok.  ExprPrime always shows up at
                // the rightmost side of the grammar rhs, the EndOfInput case
                // takes care of things
                return lhs;
            }
        }

        private GenericExpressionNode BooleanTerm(string expression)
        {
            GenericExpressionNode node = RelationalExpr(expression);
            if (node == null)
            {
                errorPosition = _lexer.GetErrorPosition();
                ProjectErrorUtilities.VerifyThrowInvalidProject(false, _elementLocation, "UnexpectedTokenInCondition", expression, _lexer.IsNextString(), errorPosition);
            }

            if (!_lexer.IsNext(Token.TokenType.EndOfInput))
            {
                node = BooleanTermPrime(expression, node);
            }
            return node;
        }

        private GenericExpressionNode BooleanTermPrime(string expression, GenericExpressionNode lhs)
        {
            if (_lexer.IsNext(Token.TokenType.EndOfInput))
            {
                return lhs;
            }
            else if (Same(expression, Token.TokenType.And))
            {
                GenericExpressionNode rhs = RelationalExpr(expression);
                if (rhs == null)
                {
                    errorPosition = _lexer.GetErrorPosition();
                    ProjectErrorUtilities.VerifyThrowInvalidProject(false, _elementLocation, "UnexpectedTokenInCondition", expression, _lexer.IsNextString(), errorPosition);
                }

                OperatorExpressionNode andNode = new AndExpressionNode();
                andNode.LeftChild = lhs;
                andNode.RightChild = rhs;
                return BooleanTermPrime(expression, andNode);
            }
            else
            {
                // Should this be error case?
                return lhs;
            }
        }

        private GenericExpressionNode RelationalExpr(string expression)
        {
            {
                GenericExpressionNode lhs = Factor(expression);
                if (lhs == null)
                {
                    errorPosition = _lexer.GetErrorPosition();
                    ProjectErrorUtilities.VerifyThrowInvalidProject(false, _elementLocation, "UnexpectedTokenInCondition", expression, _lexer.IsNextString(), errorPosition);
                }

                OperatorExpressionNode node = RelationalOperation(expression);
                if (node == null)
                {
                    return lhs;
                }
                GenericExpressionNode rhs = Factor(expression);
                node.LeftChild = lhs;
                node.RightChild = rhs;
                return node;
            }
        }

        private OperatorExpressionNode RelationalOperation(string expression)
        {
            OperatorExpressionNode node = null;
            if (Same(expression, Token.TokenType.LessThan))
            {
                node = new LessThanExpressionNode();
            }
            else if (Same(expression, Token.TokenType.GreaterThan))
            {
                node = new GreaterThanExpressionNode();
            }
            else if (Same(expression, Token.TokenType.LessThanOrEqualTo))
            {
                node = new LessThanOrEqualExpressionNode();
            }
            else if (Same(expression, Token.TokenType.GreaterThanOrEqualTo))
            {
                node = new GreaterThanOrEqualExpressionNode();
            }
            else if (Same(expression, Token.TokenType.EqualTo))
            {
                node = new EqualExpressionNode();
            }
            else if (Same(expression, Token.TokenType.NotEqualTo))
            {
                node = new NotEqualExpressionNode();
            }
            return node;
        }

        private GenericExpressionNode Factor(string expression)
        {
            // Checks for TokenTypes String, Numeric, Property, ItemMetadata, and ItemList.
            GenericExpressionNode arg = this.Arg(expression);

            // If it's one of those, return it.
            if (arg != null)
            {
                return arg;
            }

            // If it's not one of those, check for other TokenTypes.
            Token current = _lexer.CurrentToken;
            if (Same(expression, Token.TokenType.Function))
            {
                if (!Same(expression, Token.TokenType.LeftParenthesis))
                {
                    errorPosition = _lexer.GetErrorPosition();
                    ProjectErrorUtilities.VerifyThrowInvalidProject(false, _elementLocation, "UnexpectedTokenInCondition", _lexer.IsNextString(), errorPosition);
                    return null;
                }
                var arglist = new List<GenericExpressionNode>();
                Arglist(expression, arglist);
                if (!Same(expression, Token.TokenType.RightParenthesis))
                {
                    errorPosition = _lexer.GetErrorPosition();
                    ProjectErrorUtilities.VerifyThrowInvalidProject(false, _elementLocation, "UnexpectedTokenInCondition", expression, _lexer.IsNextString(), errorPosition);
                    return null;
                }
                return new FunctionCallExpressionNode(current.String, arglist);
            }
            else if (Same(expression, Token.TokenType.LeftParenthesis))
            {
                GenericExpressionNode child = Expr(expression);
                if (Same(expression, Token.TokenType.RightParenthesis))
                    return child;
                else
                {
                    errorPosition = _lexer.GetErrorPosition();
                    ProjectErrorUtilities.VerifyThrowInvalidProject(false, _elementLocation, "UnexpectedTokenInCondition", expression, _lexer.IsNextString(), errorPosition);
                }
            }
            else if (Same(expression, Token.TokenType.Not))
            {
                OperatorExpressionNode notNode = new NotExpressionNode();
                GenericExpressionNode expr = Factor(expression);
                if (expr == null)
                {
                    errorPosition = _lexer.GetErrorPosition();
                    ProjectErrorUtilities.VerifyThrowInvalidProject(false, _elementLocation, "UnexpectedTokenInCondition", expression, _lexer.IsNextString(), errorPosition);
                }
                notNode.LeftChild = expr;
                return notNode;
            }
            else
            {
                errorPosition = _lexer.GetErrorPosition();
                ProjectErrorUtilities.VerifyThrowInvalidProject(false, _elementLocation, "UnexpectedTokenInCondition", expression, _lexer.IsNextString(), errorPosition);
            }
            return null;
        }

        private void Arglist(string expression, List<GenericExpressionNode> arglist)
        {
            if (!_lexer.IsNext(Token.TokenType.RightParenthesis))
            {
                Args(expression, arglist);
            }
        }

        private void Args(string expression, List<GenericExpressionNode> arglist)
        {
            GenericExpressionNode arg = Arg(expression);
            arglist.Add(arg);
            if (Same(expression, Token.TokenType.Comma))
            {
                Args(expression, arglist);
            }
        }

        private GenericExpressionNode Arg(string expression)
        {
            Token current = _lexer.CurrentToken;
            if (Same(expression, Token.TokenType.String))
            {
                return new StringExpressionNode(current.String, current.Expandable);
            }
            else if (Same(expression, Token.TokenType.Numeric))
            {
                return new NumericExpressionNode(current.String);
            }
            else if (Same(expression, Token.TokenType.Property))
            {
                return new StringExpressionNode(current.String, true /* requires expansion */);
            }
            else if (Same(expression, Token.TokenType.ItemMetadata))
            {
                return new StringExpressionNode(current.String, true /* requires expansion */);
            }
            else if (Same(expression, Token.TokenType.ItemList))
            {
                return new StringExpressionNode(current.String, true /* requires expansion */);
            }
            else
            {
                return null;
            }
        }

        private bool Same(string expression, Token.TokenType token)
        {
            if (_lexer.IsNext(token))
            {
                if (!_lexer.Advance())
                {
                    errorPosition = _lexer.GetErrorPosition();
                    if (_lexer.UnexpectedlyFound != null)
                    {
                        ProjectErrorUtilities.VerifyThrowInvalidProject(false, _elementLocation, _lexer.GetErrorResource(), expression, errorPosition, _lexer.UnexpectedlyFound);
                    }
                    else
                    {
                        ProjectErrorUtilities.VerifyThrowInvalidProject(false, _elementLocation, _lexer.GetErrorResource(), expression, errorPosition);
                    }
                }
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}


<|start_filename|>src/Tasks.UnitTests/MockFaultInjectionHelper.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;

namespace Microsoft.Build.UnitTests
{
    public class MockFaultInjectionHelper<FailurePointEnum>
        where FailurePointEnum : IComparable
    {
        private FailurePointEnum _failureToInject;
        private Exception _exceptionToThrow;

        public MockFaultInjectionHelper()
        {
        }

        public void InjectFailure(FailurePointEnum failureToInject, Exception exceptionToThrow)
        {
            _failureToInject = failureToInject;
            _exceptionToThrow = exceptionToThrow;
        }

        public void FailurePointThrow(FailurePointEnum failurePointId)
        {
            if (_failureToInject.CompareTo(failurePointId) == 0)
            {
                throw _exceptionToThrow;
            }
        }
    }
}


<|start_filename|>src/Build/Evaluation/ProjectChangedEventArgs.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using Microsoft.Build.Shared;

namespace Microsoft.Build.Evaluation
{
    /// <summary>
    /// Event arguments for the <see cref="ProjectCollection.ProjectChanged"/> event.
    /// </summary>
    public class ProjectChangedEventArgs : EventArgs
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ProjectChangedEventArgs"/> class.
        /// </summary>
        /// <param name="project">The changed project.</param>
        internal ProjectChangedEventArgs(Project project)
        {
            ErrorUtilities.VerifyThrowArgumentNull(project, nameof(project));

            Project = project;
        }

        /// <summary>
        /// Gets the project that was marked dirty.
        /// </summary>
        /// <value>Never null.</value>
        public Project Project { get; private set; }
    }
}


<|start_filename|>src/Build.UnitTests/BackEnd/ITestTaskHost.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Build.Framework;

namespace Microsoft.Build.UnitTests.BackEnd
{
    /// <summary>
    /// Interface used by the test task to communicate what the TaskExecutionHost did to it.
    /// </summary>
    internal interface ITestTaskHost : ITaskHost
    {
        /// <summary>
        /// Called when a parameter is set on the task.
        /// </summary>
        void ParameterSet(string parameterName, object valueSet);

        /// <summary>
        /// Called when an output is read from the task.
        /// </summary>
        void OutputRead(string parameterName, object actualValue);
    }
}


<|start_filename|>src/Tasks.UnitTests/ComReference_Tests.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using Microsoft.Build.Tasks;
using Microsoft.Build.Shared;
using Xunit;

namespace Microsoft.Build.UnitTests
{
    sealed public class ComReference_Tests
    {
        private static Dictionary<string, string> s_existingFiles = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

        private static Dictionary<string, string> ExistingFilesDictionary
        {
            get
            {
                if (s_existingFiles.Count != 0)
                    return s_existingFiles;

                s_existingFiles.Add(@"C:\test\typelib1.dll", string.Empty);
                s_existingFiles.Add(@"C:\test\typelib2\2.dll", string.Empty);
                s_existingFiles.Add(@"C:\test\typelib3.\3dll", string.Empty);
                s_existingFiles.Add(@"C:\test\typelib4.dll", string.Empty);
                s_existingFiles.Add(@"C:\test\typelib5.dll", string.Empty);

                return s_existingFiles;
            }
        }

        private static bool FileExistsMock(string filepath)
        {
            return ExistingFilesDictionary.ContainsKey(filepath);
        }

        [Fact]
        public void TestStripTypeLibNumber()
        {
            if (!NativeMethodsShared.IsWindows)
            {
                return; // "COM is only found on Windows"
            }

            Assert.Null(ComReference.StripTypeLibNumberFromPath(null, new FileExists(FileExistsMock)));
            Assert.Equal("", ComReference.StripTypeLibNumberFromPath("", new FileExists(FileExistsMock)));
            Assert.Equal(@"C:\test\typelib1.dll", ComReference.StripTypeLibNumberFromPath(@"C:\test\typelib1.dll", new FileExists(FileExistsMock)));
            Assert.Equal(@"C:\test\typelib2\2.dll", ComReference.StripTypeLibNumberFromPath(@"C:\test\typelib2\2.dll", new FileExists(FileExistsMock)));
            Assert.Equal(@"C:\test\typelib3.\3dll", ComReference.StripTypeLibNumberFromPath(@"C:\test\typelib3.\3dll", new FileExists(FileExistsMock)));
            Assert.Equal(@"C:\test\typelib4.dll", ComReference.StripTypeLibNumberFromPath(@"C:\test\typelib4.dll\4", new FileExists(FileExistsMock)));
            Assert.Equal(@"C:\test\typelib5.dll", ComReference.StripTypeLibNumberFromPath(@"C:\test\typelib5.dll\555", new FileExists(FileExistsMock)));
            Assert.Equal(@"", ComReference.StripTypeLibNumberFromPath(@"C:\test\typelib6.dll", new FileExists(FileExistsMock)));
            Assert.Equal(@"", ComReference.StripTypeLibNumberFromPath(@"C:\test\typelib7.dll\7", new FileExists(FileExistsMock)));
        }
    }
}


<|start_filename|>src/Build/FileSystem/MSBuildFileSystemBase.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.IO;

namespace Microsoft.Build.FileSystem
{
    /// <summary>
    /// Abstracts away some file system operations.
    ///
    /// Implementations:
    /// - must be thread safe
    /// - may cache some or all the calls.
    /// </summary>
    public abstract class MSBuildFileSystemBase
    {
        /// <summary>
        /// Use this for var sr = new StreamReader(path)
        /// </summary>
        public abstract TextReader ReadFile(string path);

        /// <summary>
        /// Use this for new FileStream(path, mode, access, share)
        /// </summary>
        public abstract Stream GetFileStream(string path, FileMode mode, FileAccess access, FileShare share);

        /// <summary>
        /// Use this for File.ReadAllText(path)
        /// </summary>
        public abstract string ReadFileAllText(string path);

        /// <summary>
        /// Use this for File.ReadAllBytes(path)
        /// </summary>
        public abstract byte[] ReadFileAllBytes(string path);

        /// <summary>
        /// Use this for Directory.EnumerateFiles(path, pattern, option)
        /// </summary>
        public abstract IEnumerable<string> EnumerateFiles(string path, string searchPattern = "*", SearchOption searchOption = SearchOption.TopDirectoryOnly);

        /// <summary>
        /// Use this for Directory.EnumerateFolders(path, pattern, option)
        /// </summary>
        public abstract IEnumerable<string> EnumerateDirectories(string path, string searchPattern = "*", SearchOption searchOption = SearchOption.TopDirectoryOnly);

        /// <summary>
        /// Use this for Directory.EnumerateFileSystemEntries(path, pattern, option)
        /// </summary>
        public abstract IEnumerable<string> EnumerateFileSystemEntries(string path, string searchPattern = "*", SearchOption searchOption = SearchOption.TopDirectoryOnly);

        /// <summary>
        /// Use this for File.GetAttributes()
        /// </summary>
        public abstract FileAttributes GetAttributes(string path);

        /// <summary>
        /// Use this for File.GetLastWriteTimeUtc(path)
        /// </summary>
        public abstract DateTime GetLastWriteTimeUtc(string path);

        /// <summary>
        /// Use this for Directory.Exists(path)
        /// </summary>
        public abstract bool DirectoryExists(string path);

        /// <summary>
        /// Use this for File.Exists(path)
        /// </summary>
        public abstract bool FileExists(string path);

        /// <summary>
        /// Use this for File.Exists(path) || Directory.Exists(path)
        /// </summary>
        public abstract bool FileOrDirectoryExists(string path);
    }
}


<|start_filename|>src/Shared/FileSystem/IFileSystem.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.IO;

namespace Microsoft.Build.Shared.FileSystem
{

    /*
     * This is a clone of Microsoft.Build.FileSystem.MSBuildFileSystemBase.
     * MSBuildFileSystemBase is the public, reference interface. Changes should be made to MSBuildFileSystemBase and cloned in IFileSystem.
     * Any new code should depend on MSBuildFileSystemBase instead of IFileSystem, if possible.
     *
     * MSBuild uses IFileSystem internally and adapts MSBuildFileSystemBase instances received from the outside to IFileSystem.
     * Ideally there should be only one, public interface. However, such an interface would need to be put into the 
     * Microsoft.Build.Framework assembly, but that assembly cannot take new types because it breaks some old version of Nuget.exe.
     * IFileSystem cannot be deleted for the same reason.
     */
    internal interface IFileSystem
    {
        TextReader ReadFile(string path);

        Stream GetFileStream(string path, FileMode mode, FileAccess access, FileShare share);

        string ReadFileAllText(string path);

        byte[] ReadFileAllBytes(string path);

        IEnumerable<string> EnumerateFiles(string path, string searchPattern = "*", SearchOption searchOption = SearchOption.TopDirectoryOnly);

        IEnumerable<string> EnumerateDirectories(string path, string searchPattern = "*", SearchOption searchOption = SearchOption.TopDirectoryOnly);

        IEnumerable<string> EnumerateFileSystemEntries(string path, string searchPattern = "*", SearchOption searchOption = SearchOption.TopDirectoryOnly);

        FileAttributes GetAttributes(string path);

        public DateTime GetLastWriteTimeUtc(string path);

        bool DirectoryExists(string path);

        bool FileExists(string path);

        bool DirectoryEntryExists(string path);
    }
}


<|start_filename|>src/Build/Definition/ToolsetLocalReader.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Build.Collections;
using Microsoft.Build.Construction;
using Microsoft.Build.Execution;
using Microsoft.Build.Shared;
using System.Collections.Generic;
using System.Linq;

namespace Microsoft.Build.Evaluation
{
    internal class ToolsetLocalReader : ToolsetReader
    {
        private readonly IElementLocation _sourceLocation = new RegistryLocation("ToolsetLocalReader");

        internal ToolsetLocalReader(PropertyDictionary<ProjectPropertyInstance> environmentProperties, PropertyDictionary<ProjectPropertyInstance> globalProperties)
           : base(environmentProperties, globalProperties)
        {
        }

        protected override string DefaultOverrideToolsVersion => MSBuildConstants.CurrentToolsVersion;

        protected override string DefaultToolsVersion => MSBuildConstants.CurrentToolsVersion;

        protected override string MSBuildOverrideTasksPath => BuildEnvironmentHelper.Instance.CurrentMSBuildToolsDirectory;

        protected override IEnumerable<ToolsetPropertyDefinition> ToolsVersions
        {
            get
            {
                yield return new ToolsetPropertyDefinition(MSBuildConstants.CurrentToolsVersion, string.Empty, _sourceLocation);
            }
        }

        protected override IEnumerable<ToolsetPropertyDefinition> GetPropertyDefinitions(string toolsVersion)
        {
            yield return new ToolsetPropertyDefinition(MSBuildConstants.ToolsPath, BuildEnvironmentHelper.Instance.CurrentMSBuildToolsDirectory, _sourceLocation);
            yield return new ToolsetPropertyDefinition(MSBuildConstants.SdksPath, BuildEnvironmentHelper.Instance.MSBuildSDKsPath, _sourceLocation);
            yield return new ToolsetPropertyDefinition("RoslynTargetsPath",
                System.IO.Path.Combine(BuildEnvironmentHelper.Instance.CurrentMSBuildToolsDirectory, "Roslyn"),
                _sourceLocation);
        }

        protected override IEnumerable<ToolsetPropertyDefinition> GetSubToolsetPropertyDefinitions(string toolsVersion, string subToolsetVersion)
        {
            return Enumerable.Empty<ToolsetPropertyDefinition>();
        }

        protected override Dictionary<string, ProjectImportPathMatch> GetProjectImportSearchPathsTable(string toolsVersion, string os)
        {
            return new Dictionary<string, ProjectImportPathMatch>();
        }

        protected override IEnumerable<string> GetSubToolsetVersions(string toolsVersion)
        {
            return Enumerable.Empty<string>();
        }
    }
}


<|start_filename|>src/Tasks.UnitTests/ComReferenceWalker_Tests.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using Microsoft.Build.Tasks;
using System.Runtime.InteropServices.ComTypes;
using COMException = System.Runtime.InteropServices.COMException;
using Xunit;

namespace Microsoft.Build.UnitTests
{
    public class ComReferenceWalker_Tests
    {
        static private int MockReleaseComObject(object o)
        {
            return 0;
        }

        private void AssertDependenciesContainTypeLib(TYPELIBATTR[] dependencies, MockTypeLib typeLib, bool contains)
        {
            AssertDependenciesContainTypeLib("", dependencies, typeLib, contains);
        }

        private void AssertDependenciesContainTypeLib(string message, TYPELIBATTR[] dependencies, MockTypeLib typeLib, bool contains)
        {
            bool dependencyExists = false;

            foreach (TYPELIBATTR attr in dependencies)
            {
                if (attr.guid == typeLib.Attributes.guid)
                {
                    dependencyExists = true;
                    break;
                }
            }

            Assert.Equal(contains, dependencyExists);
        }

        [Fact]
        public void WalkTypeInfosInEmptyLibrary()
        {
            MockTypeLib typeLib = new MockTypeLib();

            ComDependencyWalker walker = new ComDependencyWalker(new MarshalReleaseComObject(MockReleaseComObject));
            walker.AnalyzeTypeLibrary(typeLib);
            Assert.Equal(0, walker.GetDependencies().GetLength(0));

            typeLib.AssertAllHandlesReleased();
        }

        private void CreateTwoTypeLibs(out MockTypeLib mainTypeLib, out MockTypeLib dependencyTypeLib)
        {
            mainTypeLib = new MockTypeLib();
            mainTypeLib.AddTypeInfo(new MockTypeInfo());

            dependencyTypeLib = new MockTypeLib();
            dependencyTypeLib.AddTypeInfo(new MockTypeInfo());
        }

        private TYPELIBATTR[] RunDependencyWalker(MockTypeLib mainTypeLib, MockTypeLib dependencyTypeLib, bool dependencyShouldBePresent)
        {
            ComDependencyWalker walker = new ComDependencyWalker(new MarshalReleaseComObject(MockReleaseComObject));
            walker.AnalyzeTypeLibrary(mainTypeLib);

            TYPELIBATTR[] dependencies = walker.GetDependencies();

            // types from the main type library should be in the dependency list
            AssertDependenciesContainTypeLib(dependencies, mainTypeLib, true);

            AssertDependenciesContainTypeLib(dependencies, dependencyTypeLib, dependencyShouldBePresent);

            mainTypeLib.AssertAllHandlesReleased();
            dependencyTypeLib.AssertAllHandlesReleased();

            return dependencies;
        }

        /// <summary>
        /// A type in the main type library implements an interface from a dependent type library
        /// </summary>
        [Fact]
        public void ImplementedInterfaces()
        {
            MockTypeLib mainTypeLib, dependencyTypeLib;
            CreateTwoTypeLibs(out mainTypeLib, out dependencyTypeLib);

            mainTypeLib.ContainedTypeInfos[0].ImplementsInterface(dependencyTypeLib.ContainedTypeInfos[0]);

            RunDependencyWalker(mainTypeLib, dependencyTypeLib, true);
        }

        [Fact]
        public void DefinedVariableUDT()
        {
            MockTypeLib mainTypeLib, dependencyTypeLib;
            CreateTwoTypeLibs(out mainTypeLib, out dependencyTypeLib);

            mainTypeLib.ContainedTypeInfos[0].DefinesVariable(dependencyTypeLib.ContainedTypeInfos[0]);

            RunDependencyWalker(mainTypeLib, dependencyTypeLib, true);
        }

        [Fact]
        public void DefinedVariableUDTArray()
        {
            MockTypeLib mainTypeLib, dependencyTypeLib;
            CreateTwoTypeLibs(out mainTypeLib, out dependencyTypeLib);

            mainTypeLib.ContainedTypeInfos[0].DefinesVariable(new ArrayCompositeTypeInfo(dependencyTypeLib.ContainedTypeInfos[0]));

            RunDependencyWalker(mainTypeLib, dependencyTypeLib, true);
        }

        [Fact]
        public void DefinedVariableUDTPtr()
        {
            MockTypeLib mainTypeLib, dependencyTypeLib;
            CreateTwoTypeLibs(out mainTypeLib, out dependencyTypeLib);

            mainTypeLib.ContainedTypeInfos[0].DefinesVariable(new PtrCompositeTypeInfo(dependencyTypeLib.ContainedTypeInfos[0]));

            RunDependencyWalker(mainTypeLib, dependencyTypeLib, true);
        }

        [Fact]
        public void ThereAndBackAgain()
        {
            MockTypeLib mainTypeLib, dependencyTypeLib;
            CreateTwoTypeLibs(out mainTypeLib, out dependencyTypeLib);

            mainTypeLib.ContainedTypeInfos[0].DefinesVariable(new PtrCompositeTypeInfo(dependencyTypeLib.ContainedTypeInfos[0]));
            dependencyTypeLib.ContainedTypeInfos[0].ImplementsInterface(mainTypeLib.ContainedTypeInfos[0]);

            RunDependencyWalker(mainTypeLib, dependencyTypeLib, true);
        }

        [Fact]
        public void ComplexComposition()
        {
            MockTypeLib mainTypeLib, dependencyTypeLib;
            CreateTwoTypeLibs(out mainTypeLib, out dependencyTypeLib);

            mainTypeLib.ContainedTypeInfos[0].DefinesVariable(
                new ArrayCompositeTypeInfo(new ArrayCompositeTypeInfo(new PtrCompositeTypeInfo(
                    new PtrCompositeTypeInfo(new ArrayCompositeTypeInfo(new PtrCompositeTypeInfo(dependencyTypeLib.ContainedTypeInfos[0])))))));

            RunDependencyWalker(mainTypeLib, dependencyTypeLib, true);
        }

        [Fact]
        public void DefinedFunction()
        {
            MockTypeLib mainTypeLib, dependencyTypeLib1, dependencyTypeLib2, dependencyTypeLib3;
            CreateTwoTypeLibs(out mainTypeLib, out dependencyTypeLib1);
            CreateTwoTypeLibs(out dependencyTypeLib2, out dependencyTypeLib3);

            mainTypeLib.ContainedTypeInfos[0].DefinesFunction(
                new MockTypeInfo[] { dependencyTypeLib1.ContainedTypeInfos[0], dependencyTypeLib2.ContainedTypeInfos[0] },
                dependencyTypeLib3.ContainedTypeInfos[0]);

            TYPELIBATTR[] dependencies = RunDependencyWalker(mainTypeLib, dependencyTypeLib1, true);

            AssertDependenciesContainTypeLib(dependencies, dependencyTypeLib2, true);
            AssertDependenciesContainTypeLib(dependencies, dependencyTypeLib3, true);

            dependencyTypeLib2.AssertAllHandlesReleased();
            dependencyTypeLib3.AssertAllHandlesReleased();
        }

        [Fact]
        public void IgnoreKnownOleTypes()
        {
            MockTypeLib mainTypeLib = new MockTypeLib();
            mainTypeLib.AddTypeInfo(new MockTypeInfo());

            MockTypeLib oleTypeLib = new MockTypeLib();
            oleTypeLib.AddTypeInfo(new MockTypeInfo(NativeMethods.IID_IUnknown));
            oleTypeLib.AddTypeInfo(new MockTypeInfo(NativeMethods.IID_IDispatch));
            oleTypeLib.AddTypeInfo(new MockTypeInfo(NativeMethods.IID_IDispatchEx));
            oleTypeLib.AddTypeInfo(new MockTypeInfo(NativeMethods.IID_IEnumVariant));
            oleTypeLib.AddTypeInfo(new MockTypeInfo(NativeMethods.IID_ITypeInfo));

            // We don't check for this type in the ComDependencyWalker, so it doesn't get counted as a known OLE type.
            // It's too late in the Dev10 cycle to add it to shipping code without phenomenally good reason, but we should
            // re-examine this in Dev11.  
            // oleTypeLib.AddTypeInfo(new MockTypeInfo(TYPEKIND.TKIND_ENUM));

            foreach (MockTypeInfo typeInfo in oleTypeLib.ContainedTypeInfos)
            {
                mainTypeLib.ContainedTypeInfos[0].DefinesVariable(typeInfo);
            }

            RunDependencyWalker(mainTypeLib, oleTypeLib, false);
        }

        [Fact]
        public void IgnoreGuidType()
        {
            MockTypeLib mainTypeLib = new MockTypeLib();
            mainTypeLib.AddTypeInfo(new MockTypeInfo());

            MockTypeLib oleTypeLib = new MockTypeLib(NativeMethods.IID_StdOle);
            oleTypeLib.AddTypeInfo(new MockTypeInfo());
            oleTypeLib.ContainedTypeInfos[0].TypeName = "GUID";

            mainTypeLib.ContainedTypeInfos[0].DefinesVariable(oleTypeLib.ContainedTypeInfos[0]);

            RunDependencyWalker(mainTypeLib, oleTypeLib, false);
        }

        [Fact]
        public void IgnoreNetExportedTypeLibs()
        {
            MockTypeLib mainTypeLib, dependencyTypeLib;
            CreateTwoTypeLibs(out mainTypeLib, out dependencyTypeLib);

            mainTypeLib.ContainedTypeInfos[0].DefinesFunction(
                new MockTypeInfo[] { dependencyTypeLib.ContainedTypeInfos[0] }, dependencyTypeLib.ContainedTypeInfos[0]);
            dependencyTypeLib.ExportedFromComPlus = "1";

            RunDependencyWalker(mainTypeLib, dependencyTypeLib, false);
        }

        /// <summary>
        /// The main type lib is broken... don't expect any results, but make sure we don't throw.
        /// </summary>
        [Fact]
        public void FaultInjectionMainLib()
        {
            // The primary test here is that we don't throw, which can't be explicitly expressed in NUnit...
            // other asserts are secondary
            foreach (MockTypeLibrariesFailurePoints failurePoint in Enum.GetValues(typeof(MockTypeLibrariesFailurePoints)))
            {
                MockTypeLib mainTypeLib = new MockTypeLib();
                mainTypeLib.AddTypeInfo(new MockTypeInfo());

                // Make it the StdOle lib to exercise the ITypeInfo.GetDocumentation failure point
                MockTypeLib dependencyTypeLib = new MockTypeLib(NativeMethods.IID_StdOle);
                dependencyTypeLib.AddTypeInfo(new MockTypeInfo());

                COMException failureException = new COMException("unhandled exception in " + failurePoint.ToString());
                mainTypeLib.InjectFailure(failurePoint, failureException);
                dependencyTypeLib.InjectFailure(failurePoint, failureException);

                mainTypeLib.ContainedTypeInfos[0].ImplementsInterface(dependencyTypeLib.ContainedTypeInfos[0]);
                mainTypeLib.ContainedTypeInfos[0].DefinesVariable(dependencyTypeLib.ContainedTypeInfos[0]);
                mainTypeLib.ContainedTypeInfos[0].DefinesFunction(
                    new MockTypeInfo[] { dependencyTypeLib.ContainedTypeInfos[0] }, dependencyTypeLib.ContainedTypeInfos[0]);

                ComDependencyWalker walker = new ComDependencyWalker(new MarshalReleaseComObject(MockReleaseComObject));
                walker.AnalyzeTypeLibrary(mainTypeLib);

                Assert.Single(walker.EncounteredProblems); // "Test failed for failure point " + failurePoint.ToString()
                Assert.Equal(failureException, walker.EncounteredProblems[0]); // "Test failed for failure point " + failurePoint.ToString()

                mainTypeLib.AssertAllHandlesReleased();
                dependencyTypeLib.AssertAllHandlesReleased();
            }
        }

        private static void CreateFaultInjectionTypeLibs(MockTypeLibrariesFailurePoints failurePoint, out MockTypeLib mainTypeLib,
            out MockTypeLib dependencyTypeLibGood1, out MockTypeLib dependencyTypeLibBad1,
            out MockTypeLib dependencyTypeLibGood2, out MockTypeLib dependencyTypeLibBad2)
        {
            mainTypeLib = new MockTypeLib();
            mainTypeLib.AddTypeInfo(new MockTypeInfo());
            mainTypeLib.AddTypeInfo(new MockTypeInfo());

            dependencyTypeLibGood1 = new MockTypeLib();
            dependencyTypeLibGood1.AddTypeInfo(new MockTypeInfo());

            // Make it the StdOle lib to exercise the ITypeInfo.GetDocumentation failure point
            dependencyTypeLibBad1 = new MockTypeLib(NativeMethods.IID_StdOle);
            dependencyTypeLibBad1.AddTypeInfo(new MockTypeInfo());

            dependencyTypeLibGood2 = new MockTypeLib();
            dependencyTypeLibGood2.AddTypeInfo(new MockTypeInfo());

            // Make it the StdOle lib to exercise the ITypeInfo.GetDocumentation failure point
            dependencyTypeLibBad2 = new MockTypeLib(NativeMethods.IID_StdOle);
            dependencyTypeLibBad2.AddTypeInfo(new MockTypeInfo());

            COMException failureException = new COMException("unhandled exception in " + failurePoint.ToString());

            dependencyTypeLibBad1.InjectFailure(failurePoint, failureException);
            dependencyTypeLibBad2.InjectFailure(failurePoint, failureException);
        }

        private void RunDependencyWalkerFaultInjection(MockTypeLibrariesFailurePoints failurePoint, MockTypeLib mainTypeLib, MockTypeLib dependencyTypeLibGood1, MockTypeLib dependencyTypeLibBad1, MockTypeLib dependencyTypeLibGood2, MockTypeLib dependencyTypeLibBad2)
        {
            ComDependencyWalker walker = new ComDependencyWalker(new MarshalReleaseComObject(MockReleaseComObject));
            walker.AnalyzeTypeLibrary(mainTypeLib);

            // Did the current failure point get hit for this test? If not then no point in checking anything
            // The previous test (FaultInjectionMainLib) ensures that all defined failure points actually 
            // cause some sort of trouble
            if (walker.EncounteredProblems.Count > 0)
            {
                TYPELIBATTR[] dependencies = walker.GetDependencies();
                AssertDependenciesContainTypeLib("Test failed for failure point " + failurePoint.ToString(),
                    dependencies, mainTypeLib, true);
                AssertDependenciesContainTypeLib("Test failed for failure point " + failurePoint.ToString(),
                    dependencies, dependencyTypeLibGood1, true);
                AssertDependenciesContainTypeLib("Test failed for failure point " + failurePoint.ToString(),
                    dependencies, dependencyTypeLibGood2, true);
                AssertDependenciesContainTypeLib("Test failed for failure point " + failurePoint.ToString(),
                    dependencies, dependencyTypeLibBad1, false);
                AssertDependenciesContainTypeLib("Test failed for failure point " + failurePoint.ToString(),
                    dependencies, dependencyTypeLibBad2, false);
            }

            mainTypeLib.AssertAllHandlesReleased();
            dependencyTypeLibGood1.AssertAllHandlesReleased();
            dependencyTypeLibGood2.AssertAllHandlesReleased();
            dependencyTypeLibBad1.AssertAllHandlesReleased();
            dependencyTypeLibBad2.AssertAllHandlesReleased();
        }

        [Fact]
        public void FullDependenciesWithIncrementalAnalysis()
        {
            MockTypeLib mainTypeLib1, mainTypeLib2, mainTypeLib3, dependencyTypeLib1, dependencyTypeLib2, dependencyTypeLib3;
            CreateTwoTypeLibs(out mainTypeLib1, out dependencyTypeLib1);
            CreateTwoTypeLibs(out mainTypeLib2, out dependencyTypeLib2);
            CreateTwoTypeLibs(out mainTypeLib3, out dependencyTypeLib3);

            mainTypeLib1.ContainedTypeInfos[0].DefinesVariable(dependencyTypeLib1.ContainedTypeInfos[0]);

            mainTypeLib2.ContainedTypeInfos[0].DefinesVariable(dependencyTypeLib1.ContainedTypeInfos[0]);
            mainTypeLib2.ContainedTypeInfos[0].DefinesVariable(dependencyTypeLib2.ContainedTypeInfos[0]);

            mainTypeLib3.ContainedTypeInfos[0].DefinesVariable(dependencyTypeLib1.ContainedTypeInfos[0]);
            mainTypeLib3.ContainedTypeInfos[0].DefinesVariable(dependencyTypeLib3.ContainedTypeInfos[0]);

            ComDependencyWalker walker = new ComDependencyWalker(MockReleaseComObject);

            walker.AnalyzeTypeLibrary(mainTypeLib1);
            TYPELIBATTR[] dependencies = walker.GetDependencies();
            ICollection<string> analyzedTypes = walker.GetAnalyzedTypeNames();

            AssertDependenciesContainTypeLib(dependencies, dependencyTypeLib1, true);
            AssertDependenciesContainTypeLib(dependencies, dependencyTypeLib2, false);
            AssertDependenciesContainTypeLib(dependencies, dependencyTypeLib3, false);
            Assert.Equal(2, analyzedTypes.Count);

            walker.ClearDependencyList();
            walker.AnalyzeTypeLibrary(mainTypeLib2);
            dependencies = walker.GetDependencies();
            analyzedTypes = walker.GetAnalyzedTypeNames();

            AssertDependenciesContainTypeLib(dependencies, dependencyTypeLib1, true);
            AssertDependenciesContainTypeLib(dependencies, dependencyTypeLib2, true);
            AssertDependenciesContainTypeLib(dependencies, dependencyTypeLib3, false);
            Assert.Equal(4, analyzedTypes.Count);

            walker.ClearDependencyList();
            walker.AnalyzeTypeLibrary(mainTypeLib3);
            dependencies = walker.GetDependencies();
            analyzedTypes = walker.GetAnalyzedTypeNames();

            AssertDependenciesContainTypeLib(dependencies, dependencyTypeLib1, true);
            AssertDependenciesContainTypeLib(dependencies, dependencyTypeLib2, false);
            AssertDependenciesContainTypeLib(dependencies, dependencyTypeLib3, true);
            Assert.Equal(6, analyzedTypes.Count);
        }
    }
}


<|start_filename|>src/Deprecated/Engine/Collections/CopyOnWriteHashtable.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections;
using Microsoft.Build.BuildEngine.Shared;

namespace Microsoft.Build.BuildEngine
{
    /// <summary>
    /// A hashtable wrapper that defers copying until the data is written.
    /// </summary>
    internal sealed class CopyOnWriteHashtable : IDictionary, ICloneable
    {
        // Either of these can act as the true backing writeableData.
        private Hashtable writeableData = null;

        // These are references to someone else's backing writeableData.
        private Hashtable readonlyData = null;

        // This is used to synchronize access to the readonlyData and writeableData fields.
        private object sharedLock;

        // Carry around the StringComparer when possible to make Clear less expensive.
        StringComparer stringComparer = null;

#region Construct
        /// <summary>
        /// Construct as a traditional data-backed hashtable.
        /// </summary>
        /// <param name="stringComparer"></param>
        internal CopyOnWriteHashtable(StringComparer stringComparer)
            : this(0, stringComparer)
        {
            this.sharedLock = new object();
        }

        /// <summary>
        /// Construct with specified initial capacity. If the capacity is known
        /// up front, specifying it avoids unnecessary rehashing operations
        /// </summary>
        internal CopyOnWriteHashtable(int capacity, StringComparer stringComparer)
        {
            ErrorUtilities.VerifyThrowArgumentNull(stringComparer, nameof(stringComparer));
            this.sharedLock = new object();

            if (capacity == 0)
            {
                // Actually 0 tells the Hashtable to use its default, but let's not rely on that
                writeableData = new Hashtable(stringComparer);
            }
            else
            {
                writeableData = new Hashtable(capacity, stringComparer);
            }
            readonlyData = null;
            this.stringComparer = stringComparer;
        }

        /// <summary>
        /// Construct over an IDictionary instance.
        /// </summary>
        /// <param name="dictionary"></param>
        /// <param name="stringComparer">The string comparer to use.</param>
        internal CopyOnWriteHashtable(IDictionary dictionary, StringComparer stringComparer)
        {
            ErrorUtilities.VerifyThrowArgumentNull(dictionary, nameof(dictionary));
            ErrorUtilities.VerifyThrowArgumentNull(stringComparer, nameof(stringComparer));

            this.sharedLock = new object();
            CopyOnWriteHashtable source = dictionary as CopyOnWriteHashtable;
            if (source != null)
            {
                if (source.stringComparer.GetHashCode() == stringComparer.GetHashCode())
                {
                    // If we're copying another CopyOnWriteHashtable then we can defer the clone until later.
                    ConstructFrom(source);
                    return;
                }
                else
                {
                    // Technically, it would be legal to fall through here and let a new hashtable be constructed.
                    // However, Engine is supposed to use consistent case comparisons everywhere and so, for us,
                    // this means a bug in the engine code somewhere.
                    throw new InternalErrorException("Bug: Changing the case-sensitiveness of a copied hash-table.");
                }
            }

            // Can't defer this because we don't control what gets written to the dictionary exogenously.
            writeableData = new Hashtable(dictionary, stringComparer);
            readonlyData = null;
            this.stringComparer = stringComparer;
        }

        /// <summary>
        /// Construct a shallow copy over another instance of this class.
        /// </summary>
        /// <param name="that"></param>
        private CopyOnWriteHashtable(CopyOnWriteHashtable that)
        {
            this.sharedLock = new object();
            ConstructFrom(that);
        }
        
        /// <summary>
        /// Implementation of construction logic.
        /// </summary>
        /// <param name="that"></param>
        private void ConstructFrom(CopyOnWriteHashtable that)
        {
            lock (that.sharedLock)
            {
                this.writeableData = null;

                // If the source it was writeable, need to transform it into 
                // read-only because we don't want subsequent writes to bleed through.
                if (that.writeableData != null)
                {
                    that.readonlyData = that.writeableData;
                    that.writeableData = null;
                }

                this.readonlyData = that.readonlyData;
                this.stringComparer = that.stringComparer;
            }
        }

        /// <summary>
        /// Whether or not this CopyOnWriteHashtable is currently a shallow or deep copy.
        /// This state can change from true->false when this hashtable is written to.
        /// </summary>
        internal bool IsShallowCopy
        {
            get
            {
                return this.readonlyData != null;
            }
        }
#endregion
#region Pass-through Hashtable methods.
        public bool Contains(Object key) {return ReadOperation.Contains(key);}
        public void Add(Object key, Object value) {WriteOperation.Add(key, value);}
        public void Clear() 
        {
            lock (sharedLock)
            {
                ErrorUtilities.VerifyThrow(stringComparer != null, "Should have a valid string comparer.");

                writeableData = new Hashtable(stringComparer);
                readonlyData = null;
            }
        }

        IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)ReadOperation).GetEnumerator(); }
        public IDictionaryEnumerator GetEnumerator() {return ReadOperation.GetEnumerator();}
        public void Remove(Object key) {WriteOperation.Remove(key);}        
        public bool IsFixedSize { get { return ReadOperation.IsFixedSize; }}
        public bool IsReadOnly {get {return ReadOperation.IsFixedSize;}}
        public ICollection Keys {get {return ReadOperation.Keys;}}
        public ICollection Values {get {return ReadOperation.Values;}}
        public void CopyTo(Array array, int arrayIndex) { ReadOperation.CopyTo(array, arrayIndex); }
        public int Count{get { return ReadOperation.Count; }}
        public bool IsSynchronized {get { return ReadOperation.IsSynchronized; }}
        public Object SyncRoot {get { return ReadOperation.SyncRoot; }}
        public bool ContainsKey(Object key)    {return ReadOperation.Contains(key);}
        
        public Object this[Object key] 
        {
            get 
            {
                return ReadOperation[key];
            }
            set 
            {
                lock (sharedLock)
                {
                    if(writeableData != null)
                    {
                        writeableData[key] = value;
                    }
                    else
                    {
                        // Setting to exactly the same value? Skip the the Clone in this case.
                        if (readonlyData[key] != value || (!readonlyData.ContainsKey(key)))
                        {
                            WriteOperation[key] = value;
                        }
                    }
                }
            }
        }
#endregion

        /// <summary>
        /// Clone this.
        /// </summary>
        /// <returns></returns>
        public Object Clone()
        {
            return new CopyOnWriteHashtable(this);
        }

        /// <summary>
        /// Returns a hashtable instance for reading from.
        /// </summary>
        private Hashtable ReadOperation
        {
            get
            {
                lock (sharedLock)
                {
                    if (readonlyData != null)
                    {
                        return readonlyData;
                    }

                    return writeableData;
                }
            }
        }

        /// <summary>
        /// Returns a hashtable instance for writting to.
        /// Clones the readonly hashtable if necessary to create a writeable version.
        /// </summary>
        private Hashtable WriteOperation
        {
            get
            {
                lock (sharedLock)
                {
                    if (writeableData == null)
                    {
                        writeableData = (Hashtable)readonlyData.Clone();
                        readonlyData = null;
                    }

                    return writeableData;
                }
            }
        }
    }
}


<|start_filename|>src/Deprecated/Engine/Engine/EngineProxy.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections;
using System.Collections.Generic;
using Microsoft.Build.Framework;
using Microsoft.Build.BuildEngine.Shared;
using System.Runtime.Remoting.Lifetime;
using System.Runtime.Remoting;

namespace Microsoft.Build.BuildEngine
{
    /// <summary>
    /// This class serves as a surrogate for the build engine. It limits access to the build engine by implementing only a subset
    /// of all public methods on the Engine class.
    /// </summary>
    internal sealed class EngineProxy : MarshalByRefObject, IBuildEngine3
    {
        #region Data
        // The logging interface
        private EngineLoggingServices loggingServices;

        // We've already computed and cached the line/column number of the task node in the project file.
        private bool haveProjectFileLocation = false;

        // The line number of the task node in the calling project file.
        private int lineNumber;

        // The column number of the task node in the calling project file.
        private int columnNumber;

        /// <summary>
        /// The full path to the project that's currently building.
        /// </summary>
        private string parentProjectFullFileName;

        /// <summary>
        /// The project file that contains the XML for task. This may be an import file and not the primary
        /// project file
        /// </summary>
        private string projectFileOfTaskNode;

        /// <summary>
        /// The token identifing the context of this evaluation
        /// </summary>
        private int handleId;

        /// <summary>
        /// Continue on error value per batch exposed via IBuildEngine
        /// </summary>
        private bool continueOnError;

        /// <summary>
        /// The module within which this class has been created. Used for all callbacks to
        /// engine.
        /// </summary>
        private TaskExecutionModule parentModule;

        /// <summary>
        /// Event contextual information, this tells the loggers where the task events were fired from
        /// </summary>
        private BuildEventContext buildEventContext;

        /// <summary>
        /// True if the task connected to this proxy is alive
        /// </summary>
        private bool activeProxy;

        /// <summary>
        /// This reference type is used to block access to a single entry methods of the interface
        /// </summary>
        private object callbackMonitor;

        /// <summary>
        /// A client sponsor is a class
        /// which will respond to a lease renewal request and will
        /// increase the lease time allowing the object to stay in memory
        /// </summary>
        private ClientSponsor sponsor;

        /// <summary>
        /// Will hold cached copy of typeof(BuildErrorEventArgs) used by each call to LogError
        /// </summary>
        private static Type buildErrorEventArgsType = null;

        /// <summary>
        /// Will hold cached copy of typeof(BuildErrorEventArgs) used by each call to LogError
        /// </summary>
        private static Type buildWarningEventArgsType = null;

        #endregion

        /// <summary>
        /// Private default constructor disallows parameterless instantiation.
        /// </summary>
        private EngineProxy()
        {
            // do nothing
        }

        /// <summary>
        /// Create an instance of this class to represent the IBuildEngine2 interface to the task
        /// including the event location where the log messages are raised
        /// </summary>
        /// <param name="parentModule">Parent Task Execution Module</param>
        /// <param name="handleId"></param>
        /// <param name="parentProjectFullFileName">the full path to the currently building project</param>
        /// <param name="projectFileOfTaskNode">the path to the actual file (project or targets) where the task invocation is located</param>
        /// <param name="loggingServices"></param>
        /// <param name="buildEventContext">Event Context where events will be seen to be raised from. Task messages will get this as their event context</param>
        internal EngineProxy
        (
            TaskExecutionModule parentModule,
            int handleId,
            string parentProjectFullFileName,
            string projectFileOfTaskNode,
            EngineLoggingServices loggingServices,
            BuildEventContext buildEventContext
        )
        {
            ErrorUtilities.VerifyThrow(parentModule != null, "No parent module.");
            ErrorUtilities.VerifyThrow(loggingServices != null, "No logging services.");
            ErrorUtilities.VerifyThrow(projectFileOfTaskNode != null, "Need project file path string");

            this.parentModule = parentModule;
            this.handleId = handleId;
            this.parentProjectFullFileName = parentProjectFullFileName;
            this.projectFileOfTaskNode = projectFileOfTaskNode;
            this.loggingServices = loggingServices;
            this.buildEventContext = buildEventContext;
            this.callbackMonitor = new object();

            activeProxy = true;
        }

        /// <summary>
        /// Stub implementation -- forwards to engine being proxied.
        /// </summary>
        public void LogErrorEvent(BuildErrorEventArgs e)
        {
            ErrorUtilities.VerifyThrowArgumentNull(e, nameof(e));
            ErrorUtilities.VerifyThrowInvalidOperation(activeProxy, "AttemptingToLogFromInactiveTask");

            if (parentModule.IsRunningMultipleNodes && !e.GetType().IsSerializable)
            {
                loggingServices.LogWarning(buildEventContext, new BuildEventFileInfo(string.Empty), "ExpectedEventToBeSerializable", e.GetType().Name);
                return;
            }

            string message = GetUpdatedMessage(e.File, e.Message, parentProjectFullFileName);

            if (ContinueOnError)
            {
                // Convert the error into a warning.  We do this because the whole point of 
                // ContinueOnError is that a project author expects that the task might fail,
                // but wants to ignore the failures.  This implies that we shouldn't be logging
                // errors either, because you should never have a successful build with errors.
                BuildWarningEventArgs warningEvent = new BuildWarningEventArgs
                        (   e.Subcategory,
                            e.Code,
                            e.File,
                            e.LineNumber,
                            e.ColumnNumber,
                            e.EndLineNumber,
                            e.EndColumnNumber,
                            message,  // this is the new message from above
                            e.HelpKeyword,
                            e.SenderName);

                warningEvent.BuildEventContext = buildEventContext;
                loggingServices.LogWarningEvent(warningEvent);

                // Log a message explaining why we converted the previous error into a warning.
                loggingServices.LogComment(buildEventContext,MessageImportance.Normal, "ErrorConvertedIntoWarning");
            }
            else
            {
                if(e.GetType().Equals(BuildErrorEventArgsType))
                {
                    // We'd like to add the project file to the subcategory, but since this property
                    // is read-only on the BuildErrorEventArgs type, this requires creating a new
                    // instance.  However, if some task logged a custom error type, we don't want to
                    // impolitely (as we already do above on ContinueOnError) throw the custom type
                    // data away.
                    e = new BuildErrorEventArgs
                        (
                            e.Subcategory,
                            e.Code,
                            e.File,
                            e.LineNumber,
                            e.ColumnNumber,
                            e.EndLineNumber,
                            e.EndColumnNumber,
                            message,  // this is the new message from above
                            e.HelpKeyword,
                            e.SenderName
                        );
                }

                e.BuildEventContext = buildEventContext;
                loggingServices.LogErrorEvent(e);
            }
        }

        /// <summary>
        /// Stub implementation -- forwards to engine being proxied.
        /// </summary>
        public void LogWarningEvent(BuildWarningEventArgs e)
        {
            ErrorUtilities.VerifyThrowArgumentNull(e, nameof(e));
            ErrorUtilities.VerifyThrowInvalidOperation(activeProxy, "AttemptingToLogFromInactiveTask");

            if (parentModule.IsRunningMultipleNodes && !e.GetType().IsSerializable)
            {
                loggingServices.LogWarning(buildEventContext, new BuildEventFileInfo(string.Empty), "ExpectedEventToBeSerializable", e.GetType().Name);
                return;
            }

            if (e.GetType().Equals(BuildWarningEventArgsType))
            {
                // We'd like to add the project file to the message, but since this property
                // is read-only on the BuildWarningEventArgs type, this requires creating a new
                // instance.  However, if some task logged a custom warning type, we don't want 
                // to impolitely throw the custom type data away.

                string message = GetUpdatedMessage(e.File, e.Message, parentProjectFullFileName);

                e = new BuildWarningEventArgs
                (
                    e.Subcategory,
                    e.Code,
                    e.File,
                    e.LineNumber,
                    e.ColumnNumber,
                    e.EndLineNumber,
                    e.EndColumnNumber,
                    message, // this is the new message from above
                    e.HelpKeyword,
                    e.SenderName
                );
            }

            e.BuildEventContext = buildEventContext;
            loggingServices.LogWarningEvent(e);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="file">File field from the original BuildEventArgs</param>
        /// <param name="message">Message field from the original BuildEventArgs</param>
        /// <param name="parentProjectFullFileName">Full file name of the parent (building) project.</param>
        /// <returns></returns>
        private static string GetUpdatedMessage(string file, string message, string parentProjectFullFileName)
        {
#if BUILDING_DF_LKG
            // In the dogfood LKG, add the project path to the end, because we need it to help diagnose builds.

            // Don't bother doing anything if we don't have a project path (e.g., we loaded from XML directly)
            if (String.IsNullOrEmpty(parentProjectFullFileName))
            {
                return message;
            }

            // Don't bother adding the project file path if it's already in the file part
            if(String.Equals(file, parentProjectFullFileName, StringComparison.OrdinalIgnoreCase))
            {
                return message;
            }

            string updatedMessage = String.IsNullOrEmpty(message) ?
                                        String.Format(CultureInfo.InvariantCulture, "[{0}]", parentProjectFullFileName) :
                                        String.Format(CultureInfo.InvariantCulture, "{0} [{1}]", message, parentProjectFullFileName);

            return updatedMessage;
#else
            // In the regular product, don't modify the message. We want to do this properly, with a field on the event args, in a future version.
            return message;
#endif
        }

        /// <summary>
        /// Stub implementation -- forwards to engine being proxied.
        /// </summary>
        public void LogMessageEvent(BuildMessageEventArgs e)
        {
            ErrorUtilities.VerifyThrowArgumentNull(e, nameof(e));
            ErrorUtilities.VerifyThrowInvalidOperation(activeProxy, "AttemptingToLogFromInactiveTask");

            if (parentModule.IsRunningMultipleNodes && !e.GetType().IsSerializable)
            {
                loggingServices.LogWarning(buildEventContext, new BuildEventFileInfo(string.Empty), "ExpectedEventToBeSerializable", e.GetType().Name);
                    return;
            }
            e.BuildEventContext = buildEventContext;
            loggingServices.LogMessageEvent(e);
        }

        /// <summary>
        /// Stub implementation -- forwards to engine being proxied.
        /// </summary>
        public void LogCustomEvent(CustomBuildEventArgs e)
        {
            ErrorUtilities.VerifyThrowArgumentNull(e, nameof(e));
            ErrorUtilities.VerifyThrowInvalidOperation(activeProxy, "AttemptingToLogFromInactiveTask");

            if (parentModule.IsRunningMultipleNodes && !e.GetType().IsSerializable)
            {
                loggingServices.LogWarning(buildEventContext, new BuildEventFileInfo(string.Empty), "ExpectedEventToBeSerializable", e.GetType().Name);
                    return;
            }

            e.BuildEventContext = buildEventContext;
            loggingServices.LogCustomEvent(e);
        }

        /// <summary>
        /// Returns true if the ContinueOnError flag was set to true for this particular task
        /// in the project file.
        /// </summary>
        public bool ContinueOnError
        {
            get
            {
                ErrorUtilities.VerifyThrowInvalidOperation(activeProxy, "AttemptingToLogFromInactiveTask");

                return this.continueOnError;
            }
        }

        /// <summary>
        /// Called by the task engine to update the value for each batch
        /// </summary>
        /// <param name="shouldContinueOnError"></param>
        internal void UpdateContinueOnError(bool shouldContinueOnError)
        {
            this.continueOnError = shouldContinueOnError;
        }

        /// <summary>
        /// Retrieves the line number of the task node withing the project file that called it.
        /// </summary>
        /// <remarks>This method is expensive in terms of perf.  Do not call it in mainline scenarios.</remarks>
        /// <owner>RGoel</owner>
        public int LineNumberOfTaskNode
        {
            get
            {
                ErrorUtilities.VerifyThrowInvalidOperation(activeProxy, "AttemptingToLogFromInactiveTask");

                ComputeProjectFileLocationOfTaskNode();
                return this.lineNumber;
            }
        }

        /// <summary>
        /// Retrieves the line number of the task node withing the project file that called it.
        /// </summary>
        /// <remarks>This method is expensive in terms of perf.  Do not call it in mainline scenarios.</remarks>
        /// <owner>RGoel</owner>
        public int ColumnNumberOfTaskNode
        {
            get
            {
                ErrorUtilities.VerifyThrowInvalidOperation(activeProxy, "AttemptingToLogFromInactiveTask");

                ComputeProjectFileLocationOfTaskNode();
                return this.columnNumber;
            }
        }

        /// <summary>
        /// Returns the full path to the project file that contained the call to this task.
        /// </summary>
        public string ProjectFileOfTaskNode
        {
            get
            {
                ErrorUtilities.VerifyThrowInvalidOperation(activeProxy, "AttemptingToLogFromInactiveTask");

                return projectFileOfTaskNode;
            }
        }

        /// <summary>
        /// Computes the line/column number of the task node in the project file (or .TARGETS file)
        /// that called it.
        /// </summary>
        private void ComputeProjectFileLocationOfTaskNode()
        {
            if (!haveProjectFileLocation)
            {
                parentModule.GetLineColumnOfXmlNode(handleId, out this.lineNumber, out this.columnNumber);
                haveProjectFileLocation = true;
            }
        }

        /// <summary>
        /// Stub implementation -- forwards to engine being proxied.
        /// </summary>
        /// <param name="projectFileName"></param>
        /// <param name="targetNames"></param>
        /// <param name="globalProperties"></param>
        /// <param name="targetOutputs"></param>
        /// <returns>result of call to engine</returns>
        public bool BuildProjectFile
            (
            string projectFileName,
            string[] targetNames,
            IDictionary globalProperties,
            IDictionary targetOutputs
            )
        {
            return BuildProjectFile(projectFileName, targetNames, globalProperties, targetOutputs, null);
        }

        /// <summary>
        /// Stub implementation -- forwards to engine being proxied.
        /// </summary>
        /// <param name="projectFileName"></param>
        /// <param name="targetNames"></param>
        /// <param name="globalProperties"></param>
        /// <param name="targetOutputs"></param>
        /// <param name="toolsVersion">Tools Version to override on the project. May be null</param>
        /// <returns>result of call to engine</returns>
        public bool BuildProjectFile
            (
            string projectFileName,
            string[] targetNames,
            IDictionary globalProperties,
            IDictionary targetOutputs,
            string toolsVersion
            )
        {
            lock (callbackMonitor)
            {
                ErrorUtilities.VerifyThrowInvalidOperation(activeProxy, "AttemptingToLogFromInactiveTask");

                // Wrap the project name into an array
                string[] projectFileNames = new string[1];
                projectFileNames[0] = projectFileName;
                string[] toolsVersions = new string[1];
                toolsVersions[0] = toolsVersion;
                IDictionary[] targetOutputsPerProject = new IDictionary[1];
                targetOutputsPerProject[0] = targetOutputs;
                IDictionary[] globalPropertiesPerProject = new IDictionary[1];
                globalPropertiesPerProject[0] = globalProperties;
                return parentModule.BuildProjectFile(handleId, projectFileNames, targetNames, globalPropertiesPerProject, targetOutputsPerProject,
                                                     loggingServices, toolsVersions, false, false, buildEventContext);
            }
        }

        /// <summary>
        /// Stub implementation -- forwards to engine being proxied.
        /// </summary>
        /// <param name="projectFileNames"></param>
        /// <param name="targetNames"></param>
        /// <param name="globalProperties"></param>
        /// <param name="targetOutputsPerProject"></param>
        /// <param name="toolsVersions">Tools Version to overrides per project. May contain null values</param>
        /// <param name="unloadProjectsOnCompletion"></param>
        /// <returns>result of call to engine</returns>
        public bool BuildProjectFilesInParallel
            (
            string[] projectFileNames,
            string[] targetNames,
            IDictionary[] globalProperties,
            IDictionary[] targetOutputsPerProject,
            string[] toolsVersions,
            bool useResultsCache,
            bool unloadProjectsOnCompletion
            )
        {
            lock (callbackMonitor)
            {
                return parentModule.BuildProjectFile(handleId, projectFileNames, targetNames, globalProperties,
                                                         targetOutputsPerProject, loggingServices,
                                                         toolsVersions, useResultsCache, unloadProjectsOnCompletion, buildEventContext);
            }
        }

        /// <summary>
        /// Not implemented for the proxy
        /// </summary>
	public void Yield()
	{
	}

        /// <summary>
        /// Not implemented for the proxy
        /// </summary>
	public void Reacquire()
	{
	}

        /// <summary>
        /// Stub implementation -- forwards to engine being proxied.
        /// </summary>
        /// <remarks>
        /// 1) it is acceptable to pass null for both <c>targetNames</c> and <c>targetOutputs</c>
        /// 2) if no targets are specified, the default targets are built
        ///
        /// </remarks>
        /// <param name="projectFileNames">The project to build.</param>
        /// <param name="targetNames">The targets in the project to build (can be null).</param>
        /// <param name="globalProperties">An array of hashtables of additional global properties to apply
        ///     to the child project (array entries can be null).
        ///     The key and value in the hashtable should both be strings.</param>
        /// <param name="removeGlobalProperties">A list of global properties which should be removed.</param>
        /// <param name="toolsVersions">A tools version recognized by the Engine that will be used during this build (can be null).</param>
        /// <param name="returnTargetOutputs">Should the target outputs be returned in the BuildEngineResults</param>
        /// <returns>Returns a structure containing the success or failures of the build and the target outputs by project.</returns>
        public BuildEngineResult BuildProjectFilesInParallel
            (
            string[] projectFileNames,
            string[] targetNames,
            IDictionary [] globalProperties,
            IList<string>[] removeGlobalProperties,
            string[] toolsVersions,
            bool returnTargetOutputs
            )
        {
            lock (callbackMonitor)
            {
                ErrorUtilities.VerifyThrowInvalidOperation(activeProxy, "AttemptingToLogFromInactiveTask");

                ErrorUtilities.VerifyThrowArgumentNull(projectFileNames, nameof(projectFileNames));
                ErrorUtilities.VerifyThrowArgumentNull(globalProperties, "globalPropertiesPerProject");

                Dictionary<string, ITaskItem[]>[] targetOutputsPerProject = null;

                if (returnTargetOutputs)
                {
                    targetOutputsPerProject = new Dictionary<string, ITaskItem[]>[projectFileNames.Length];
                    for (int i = 0; i < targetOutputsPerProject.Length; i++)
                    {
                        targetOutputsPerProject[i] = new Dictionary<string, ITaskItem[]>(StringComparer.OrdinalIgnoreCase);
                    }
                }

                bool result = parentModule.BuildProjectFile(handleId, projectFileNames, targetNames, globalProperties,
                                                     targetOutputsPerProject, loggingServices,
                                                     toolsVersions, false, false, buildEventContext);

                return new BuildEngineResult(result, new List<IDictionary<string, ITaskItem[]>>(targetOutputsPerProject));
            }
        }

        /// <summary>
        /// InitializeLifetimeService is called when the remote object is activated.
        /// This method will determine how long the lifetime for the object will be.
        /// </summary>
        public override object InitializeLifetimeService()
        {
            // Each MarshalByRef object has a reference to the service which
            // controls how long the remote object will stay around
            ILease lease = (ILease)base.InitializeLifetimeService();

            // Set how long a lease should be initially. Once a lease expires
            // the remote object will be disconnected and it will be marked as being availiable 
            // for garbage collection
            int initialLeaseTime = 1;

            string initialLeaseTimeFromEnvironment = Environment.GetEnvironmentVariable("MSBUILDENGINEPROXYINITIALLEASETIME");

            if (!String.IsNullOrEmpty(initialLeaseTimeFromEnvironment))
            {
                int leaseTimeFromEnvironment;
                if (int.TryParse(initialLeaseTimeFromEnvironment , out leaseTimeFromEnvironment) && leaseTimeFromEnvironment > 0)
                {
                      initialLeaseTime = leaseTimeFromEnvironment;
                }
            }

            lease.InitialLeaseTime = TimeSpan.FromMinutes(initialLeaseTime);

            // Make a new client sponsor. A client sponsor is a class
            // which will respond to a lease renewal request and will
            // increase the lease time allowing the object to stay in memory
            sponsor = new ClientSponsor();

            // When a new lease is requested lets make it last 1 minutes longer. 
            int leaseExtensionTime = 1;

            string leaseExtensionTimeFromEnvironment = Environment.GetEnvironmentVariable("MSBUILDENGINEPROXYLEASEEXTENSIONTIME");
            if (!String.IsNullOrEmpty(leaseExtensionTimeFromEnvironment))
            {
                int leaseExtensionFromEnvironment;
                if (int.TryParse(leaseExtensionTimeFromEnvironment , out leaseExtensionFromEnvironment) && leaseExtensionFromEnvironment > 0)
                {
                      leaseExtensionTime = leaseExtensionFromEnvironment;
                }
            }

            sponsor.RenewalTime = TimeSpan.FromMinutes(leaseExtensionTime);

            // Register the sponsor which will increase lease timeouts when the lease expires
            lease.Register(sponsor);

            return lease;
        }

        /// <summary>
        /// Indicates to the EngineProxy that it is no longer needed.
        /// Called by TaskEngine when the task using the EngineProxy is done.
        /// </summary>
        internal void MarkAsInActive()
        {
            activeProxy = false;

            // Since the task has a pointer to this class it may store it in a static field. Null out
            // internal data so the leak of this object doesn't lead to a major memory leak.
            loggingServices = null;
            parentModule = null;
            buildEventContext = null;

            // Clear out the sponsor (who is responsible for keeping the EngineProxy remoting lease alive until the task is done)
            // this will be null if the engineproxy was never sent accross an appdomain boundry.
            if (sponsor != null)
            {
                ILease lease = (ILease)RemotingServices.GetLifetimeService(this);
                lease?.Unregister(sponsor);

                sponsor.Close();
                sponsor = null;
            }
        }

        #region Properties
        /// <summary>
        /// Provide a way to change the BuildEventContext of the engine proxy. This is important in batching where each batch will need its own buildEventContext.
        /// </summary>
        internal BuildEventContext BuildEventContext
        {
            get { return buildEventContext; }
            set { buildEventContext = value; }
        }

        /// <summary>
        /// This property allows a task to query whether or not the system is running in single process mode or multi process mode.
        /// Single process mode is where the engine is initialized with the number of cpus = 1 and the engine is not a child engine.
        /// The engine is in multi process mode when the engine is initialized with a number of cpus > 1 or the engine is a child engine.
        /// </summary>
        public bool IsRunningMultipleNodes
        {
            get { return parentModule.IsRunningMultipleNodes; }
        }

        /// <summary>
        /// Cached copy of typeof(BuildErrorEventArgs) used during each call to LogError
        /// </summary>
        private static Type BuildErrorEventArgsType
        {
            get
            {
                if (buildErrorEventArgsType == null)
                {
                    buildErrorEventArgsType = typeof(BuildErrorEventArgs);
                }
                return buildErrorEventArgsType;
            }
        }

        /// <summary>
        /// Cached copy of typeof(BuildWarningEventArgs) used during each call to LogWarning
        /// </summary>
        private static Type BuildWarningEventArgsType
        {
            get
            {
                if (buildWarningEventArgsType == null)
                {
                    buildWarningEventArgsType = typeof(BuildWarningEventArgs);
                }
                return buildWarningEventArgsType;
            }
        }

        #endregion
    }
}


<|start_filename|>src/Build.OM.UnitTests/ObjectModelRemoting/Helpers/TestCollectionGroup.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.Build.UnitTests.OM.ObjectModelRemoting
{
    using System;
    using System.Collections.Generic;
    using Microsoft.Build.Evaluation;
    using Xunit;

    public class TestCollectionGroup : IDisposable
    {
        public static string SampleProjectFile = ObjectModelHelpers.CleanupFileContents(@"
                    <Project xmlns='msbuildnamespace' ToolsVersion='2.0' InitialTargets='it' DefaultTargets='dt'>
                        <PropertyGroup Condition=""'$(Configuration)'=='Foo'"">
                            <p>v1</p>
                            <gpt1>Foo$(gp1)</gpt1>
                        </PropertyGroup>
                        <PropertyGroup Condition=""'$(Configuration)'!='Foo'"">
                            <p>v2</p>
                            <gpt1>NotFoo$(gp1)</gpt1>
                        </PropertyGroup>
                        <PropertyGroup>
                            <p2>X$(p)</p2>
                        </PropertyGroup>
                        <ItemGroup>
                            <i Condition=""'$(Configuration)'=='Foo'"" Include='i0'/>
                            <i Include='i1'/>
                            <i Include='$(p)X;i3'/>
                        </ItemGroup>
                        <Target Name='t'>
                            <task/>
                        </Target>
                    </Project>
                ");

        public static string BigProjectFile = ObjectModelHelpers.CleanupFileContents(@"
                    <Project xmlns='msbuildnamespace' ToolsVersion='2.0' InitialTargets='it' DefaultTargets='dt'>
                        <Import Project='pi1.proj' />
                        <Import Project='pi2.proj' Condition=""'$(Configuration)'=='Foo'""/>
                        <Import Project='pi3.proj' Condition='false' Sdk=""FakeSdk"" Version=""1.0"" MinimumVersion=""1.0""/>

                        <UsingTask TaskName='SuperTask' AssemblyFile='af' TaskFactory='AssemblyFactory'>
                           <ParameterGroup>
                              <MyParameter1 ParameterType='System.String' Output='true' Required='false'/>
                              <MyParameter2 ParameterType='System.String' Output='true' Required='false'/>
                           </ParameterGroup>
                       </UsingTask>

                        <UsingTask TaskName='LooserTask' AssemblyFile='af' TaskFactory='AssemblyFactory'>
                           <Task Evaluate='false'>Contents</Task>
                           <ParameterGroup>
                              <YourParameter1 ParameterType='System.String' Output='true' Required='false'/>
                              <YourParameter2 ParameterType='System.String' Output='true' Required='false'/>
                           </ParameterGroup>
                       </UsingTask>

                        <ImportGroup>
                            <Import Project='a.proj' />
                            <Import Project='b.proj' />
                        </ImportGroup>
                        <ImportGroup Condition='false'>
                            <Import Project='c.proj' />
                        </ImportGroup>


                        <PropertyGroup Condition=""'$(Configuration)'=='Foo'"">
                            <p>v1</p>
                        </PropertyGroup>
                        <PropertyGroup Condition=""'$(Configuration)'!='Foo'"">
                            <p>v2</p>
                        </PropertyGroup>
                        <PropertyGroup>
                            <p2>X$(p)</p2>
                        </PropertyGroup>
                        <ItemGroup>
                            <i Condition=""'$(Configuration)'=='Foo'"" Include='i0'/>
                            <i Include='i1'/>
                            <i Include='$(p)X;i3'/>
                            <i2 Include='item2' KeepDuplicates=""false"" KeepMetadata=""CopyToOutputDirectory;TargetPath"" RemoveMetadata=""xx""/>
                            <i2 Remove='item2'/>
                            <i2 Update='item2'/>
                        </ItemGroup>

                        <ItemGroup>
                            <src Condition=""'$(Configuration)'=='Foo'"" Include='foo.cs'/>
                            <src Include='foo2.cs'/>
                            <i4 Include='i' Exclude='j' m2='v2' />
                        </ItemGroup>

                        <ItemGroup Label=""Group1"">
                            <Compile Include=""Constants.cs"">
                                <ExcludeFromStyleCop>true</ExcludeFromStyleCop>
                            </Compile>
                            <Compile Include=""EncodingStringWriter.cs"">
                                <Link>EncodingStringWriter.cs</Link>
                            </Compile>
                            <Compile Include=""EncodingUtilities.cs"">
                                 <Link>EncodingUtilities.cs</Link>
                            </Compile>
                        </ItemGroup>

                        <ItemDefinitionGroup >
                            <i2 m1='v1'>
                                <m2 Condition='true'>v2</m2>
                                <m1>v3</m1>
                            </i2>
                        </ItemDefinitionGroup>

                        <ItemDefinitionGroup>
                            <i3 m1='v1'>
                                <m1>v3</m1>
                            </i3>
                            <i4 />
                        </ItemDefinitionGroup>

                        <Choose>
                            <When Condition=""'$(Configuration)'=='Foo'"">
                              <PropertyGroup>
                                <p>vFoo</p>
                              </PropertyGroup> 
                            </When>
                            <When Condition='false'>
                              <PropertyGroup>
                                <p>vFalse</p>
                              </PropertyGroup> 
                            </When>      
                            <When Condition='true'>
                              <PropertyGroup>
                                <p>vTrue</p>
                              </PropertyGroup> 
                            </When>      
                            <Otherwise>
                              <PropertyGroup>
                                <p>vOtherwise</p>
                              </PropertyGroup> 
                            </Otherwise>
                        </Choose>

                        <Target Name='t'>
                            <task/>
                        </Target>

                        <Target
                            Name=""Frankenstein""
                            Label=""Target1""
                            Returns=""@(_ProjectReferencesFromRAR);@(_ResolvedNativeProjectReferencePaths)""
                            Inputs=""@(_SourceItemsToCopyToOutputDirectory)""
                            BeforeTargets=""Compile""
                            AfterTargets=""Link""
                            Outputs=""@(_SourceItemsToCopyToOutputDirectory->'$(OutDir)%(TargetPath)')""
                            KeepDuplicateOutputs="" '$(MSBuildDisableGetCopyToOutputDirectoryItemsOptimization)' == '' ""
                            DependsOnTargets=""ResolveProjectReferences;ResolveAssemblyReferences"">

                            <ItemGroup>
                                <_ProjectReferencesFromRAR Include=""@(ReferencePath->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference'))"">
                                <OriginalItemSpec>%(ReferencePath.ProjectReferenceOriginalItemSpec)</OriginalItemSpec>
                                </_ProjectReferencesFromRAR>

                                <Compile Include=""Constants.cs"">
                                    <ExcludeFromStyleCop>true</ExcludeFromStyleCop>
                                </Compile>
                                <Compile Include=""EncodingStringWriter.cs"">
                                    <Link>EncodingStringWriter.cs</Link>
                                </Compile>

                            </ItemGroup>

                            <FindAppConfigFile PrimaryList=""@(None)"" SecondaryList=""@(Content)"" TargetPath=""$(TargetFileName).config"" Condition=""'$(AppConfig)'==''"">
                                <Output TaskParameter=""AppConfigFile"" ItemName=""AppConfigWithTargetPath""/>
                                <Output TaskParameter=""AppConfigFile"" PropertyName=""AppConfig""/>
                            </FindAppConfigFile>

                            <MakeDir Directories=""$(OutDir);$(IntermediateOutputPath);@(DocFileItem->'%(RelativeDir)');@(CreateDirectory)"" ContinueOnError=""True""/>

                            <OnError ExecuteTargets='1'/>
                            <OnError ExecuteTargets='2'/>
                        </Target>

                        <Sdk Name=""sdkName"" Version=""version"" MinimumVersion=""minVersion"" />

                       <ProjectExtensions>
                         <a>x</a>
                         <b>y</b>
                       </ProjectExtensions>
                    </Project>
                ");
        public int RemoteCount { get; }

        internal ProjectCollectionLinker.ConnectedProjectCollections Group { get; }
        internal ProjectCollectionLinker Local { get; }

        internal ProjectCollectionLinker[] Remote { get; } = new ProjectCollectionLinker[2];
        internal TransientIO Disk { get; }
        protected TransientIO ImmutableDisk { get; }
        public IReadOnlyList<string> StdProjectFiles { get; }

        private IReadOnlyDictionary<ProjectCollectionLinker, HashSet<Project>> ImmutableProjects { get; set; }

        protected void TakeSnapshot()
        {
            Assert.Null(this.ImmutableProjects);
            var result = new Dictionary<ProjectCollectionLinker, HashSet<Project>>();
            this.Local.Importing = false;
            result.Add(this.Local, new HashSet<Project>(this.Local.Collection.LoadedProjects));
            foreach (var r in this.Remote)
            {
                r.Importing = false;
                result.Add(r, new HashSet<Project>(r.Collection.LoadedProjects));
            }

            this.ImmutableProjects = result;
        }

        public TestCollectionGroup(int remoteCount, int stdFilesCount)
        {
            this.RemoteCount = 2;

            this.Group = ProjectCollectionLinker.CreateGroup();

            this.Local = this.Group.AddNew();
            this.Remote = new ProjectCollectionLinker[this.RemoteCount];
            for (int i = 0; i < this.RemoteCount; i++)
            {
                this.Remote[i] = this.Group.AddNew();
            }

            this.ImmutableDisk = new TransientIO();
            this.Disk = this.ImmutableDisk.GetSubFolder("Mutable");

            List<string> stdFiles = new List<string>();
            for (int i=0; i< stdFilesCount; i++)
            {
                stdFiles.Add(this.ImmutableDisk.WriteProjectFile($"Proj{i}.proj", TestCollectionGroup.SampleProjectFile));
            }

            this.StdProjectFiles = stdFiles;
        }

        private void Clear(ProjectCollectionLinker linker)
        {
            linker.Importing = false;
            HashSet<Project> toKeep = null;
            this.ImmutableProjects?.TryGetValue(linker, out toKeep);
            if (toKeep == null)
            {
                linker.Collection.UnloadAllProjects();
            }
            else
            {
                var toUnload = new List<Project>();
                foreach (var p in linker.Collection.LoadedProjects)
                {
                    if (!toKeep.Contains(p))
                        toUnload.Add(p);
                }

                foreach (var p in toUnload)
                {
                    linker.Collection.UnloadProject(p);
                    linker.Collection.UnloadProject(p.Xml);
                }
            }
        }
        public void Clear()
        {
            this.Clear(this.Local);
            foreach (var remote in this.Remote)
            {
                this.Clear(remote);
            }

            this.Group.ClearAllRemotes();
            this.Disk.Clear();
        }

        public void Dispose()
        {
            this.Clear();
            this.ImmutableDisk.Dispose();
        }
    }
}


<|start_filename|>src/Shared/UnitTests/TestProgram.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;


class Program
{
    public static int Main(string[] args)
    {
#if RUNTIME_TYPE_NETCORE
        var newArgs = new List<string>(args);
        newArgs.Insert(0, typeof(Program).Assembly.Location);

        int returnCode = Xunit.ConsoleClient.Program.Main(newArgs.ToArray());

        //if (showHelp)
        //{
        //    TestCommandLine.ShowHelp();
        //}

        return returnCode;
#else
        throw new NotImplementedException();
#endif
    }
}


<|start_filename|>src/Build.UnitTests/BackEnd/IntegrationTests.cs<|end_filename|>
﻿namespace Microsoft.Build.Unittest.BackEnd
{
    class IntegrationTests
    {
    }
}


<|start_filename|>src/Build/Evaluation/Conditionals/Token.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using ErrorUtilities = Microsoft.Build.Shared.ErrorUtilities;

namespace Microsoft.Build.Evaluation
{
    /// <summary>
    /// This class represents a token in the Complex Conditionals grammar.  It's
    /// really just a bag that contains the type of the token and the string that
    /// was parsed into the token.  This isn't very useful for operators, but
    /// is useful for strings and such.
    /// </summary>
    internal sealed class Token
    {
        internal readonly static Token Comma = new Token(TokenType.Comma);
        internal readonly static Token LeftParenthesis = new Token(TokenType.LeftParenthesis);
        internal readonly static Token RightParenthesis = new Token(TokenType.RightParenthesis);
        internal readonly static Token LessThan = new Token(TokenType.LessThan);
        internal readonly static Token GreaterThan = new Token(TokenType.GreaterThan);
        internal readonly static Token LessThanOrEqualTo = new Token(TokenType.LessThanOrEqualTo);
        internal readonly static Token GreaterThanOrEqualTo = new Token(TokenType.GreaterThanOrEqualTo);
        internal readonly static Token And = new Token(TokenType.And);
        internal readonly static Token Or = new Token(TokenType.Or);
        internal readonly static Token EqualTo = new Token(TokenType.EqualTo);
        internal readonly static Token NotEqualTo = new Token(TokenType.NotEqualTo);
        internal readonly static Token Not = new Token(TokenType.Not);
        internal readonly static Token EndOfInput = new Token(TokenType.EndOfInput);

        /// <summary>
        /// Valid tokens
        /// </summary>
        internal enum TokenType
        {
            Comma, LeftParenthesis, RightParenthesis,
            LessThan, GreaterThan, LessThanOrEqualTo, GreaterThanOrEqualTo,
            And, Or,
            EqualTo, NotEqualTo, Not,
            Property, String, Numeric, ItemList, ItemMetadata, Function,
            EndOfInput
        };

        private TokenType _tokenType;
        private string _tokenString;

        /// <summary>
        /// Constructor for types that don't have values
        /// </summary>
        /// <param name="tokenType"></param>
        private Token(TokenType tokenType)
        {
            _tokenType = tokenType;
            _tokenString = null;
        }

        /// <summary>
        /// Constructor takes the token type and the string that
        /// represents the token
        /// </summary>
        /// <param name="type"></param>
        /// <param name="tokenString"></param>
        internal Token(TokenType type, string tokenString)
            : this(type, tokenString, false /* not expandable */)
        { }

        /// <summary>
        /// Constructor takes the token type and the string that
        /// represents the token.
        /// If the string may contain content that needs expansion, expandable is set.
        /// </summary>
        internal Token(TokenType type, string tokenString, bool expandable)
        {
            ErrorUtilities.VerifyThrow
                (
                type == TokenType.Property ||
                type == TokenType.String ||
                type == TokenType.Numeric ||
                type == TokenType.ItemList ||
                type == TokenType.ItemMetadata ||
                type == TokenType.Function,
                "Unexpected token type"
                );

            ErrorUtilities.VerifyThrowInternalNull(tokenString, nameof(tokenString));

            _tokenType = type;
            _tokenString = tokenString;
            this.Expandable = expandable;
        }

        /// <summary>
        /// Whether the content potentially has expandable content,
        /// such as a property expression or escaped character.
        /// </summary>
        internal bool Expandable
        {
            get;
            set;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        internal bool IsToken(TokenType type)
        {
            return _tokenType == type;
        }

        internal string String
        {
            get
            {
                if (_tokenString != null)
                {
                    return _tokenString;
                }

                // Return a token string for 
                // an error message.
                switch (_tokenType)
                {
                    case TokenType.Comma:
                        return ",";
                    case TokenType.LeftParenthesis:
                        return "(";
                    case TokenType.RightParenthesis:
                        return ")";
                    case TokenType.LessThan:
                        return "<";
                    case TokenType.GreaterThan:
                        return ">";
                    case TokenType.LessThanOrEqualTo:
                        return "<=";
                    case TokenType.GreaterThanOrEqualTo:
                        return ">=";
                    case TokenType.And:
                        return "and";
                    case TokenType.Or:
                        return "or";
                    case TokenType.EqualTo:
                        return "==";
                    case TokenType.NotEqualTo:
                        return "!=";
                    case TokenType.Not:
                        return "!";
                    case TokenType.EndOfInput:
                        return null;
                    default:
                        ErrorUtilities.ThrowInternalErrorUnreachable();
                        return null;
                }
            }
        }
    }
}

<|start_filename|>src/Tasks/FileIO/GetFileHash.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Threading.Tasks;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using Microsoft.Build.Shared.FileSystem;

namespace Microsoft.Build.Tasks
{
    /// <summary>
    /// Computes the checksum for a single file.
    /// </summary>
    public sealed class GetFileHash : TaskExtension
    {
        internal const string _defaultFileHashAlgorithm = "SHA256";
        internal const string _hashEncodingHex = "hex";
        internal const string _hashEncodingBase64 = "base64";
        internal static readonly Dictionary<string, Func<HashAlgorithm>> SupportedAlgorithms
            = new Dictionary<string, Func<HashAlgorithm>>(StringComparer.OrdinalIgnoreCase)
            {
                ["SHA256"] = SHA256.Create,
                ["SHA384"] = SHA384.Create,
                ["SHA512"] = SHA512.Create,
            };

        /// <summary>
        /// The files to be hashed.
        /// </summary>
        [Required]
        public ITaskItem[] Files { get; set; }

        /// <summary>
        /// The algorithm. Allowed values: SHA256, SHA384, SHA512. Default = SHA256.
        /// </summary>
        public string Algorithm { get; set; } = _defaultFileHashAlgorithm;

        /// <summary>
        /// The metadata name where the hash is stored in each item. Defaults to "FileHash".
        /// </summary>
        public string MetadataName { get; set; } = "FileHash";

        /// <summary>
        /// The encoding to use for generated hashs. Defaults to "hex". Allowed values = "hex", "base64".
        /// </summary>
        public string HashEncoding { get; set; } = _hashEncodingHex;

        /// <summary>
        /// The hash of the file. This is only set if there was one item group passed in.
        /// </summary>
        [Output]
        public string Hash { get; set; }

        /// <summary>
        /// The input files with additional metadata set to include the file hash.
        /// </summary>
        [Output]
        public ITaskItem[] Items { get; set; }

        public override bool Execute()
        {
            if (!SupportedAlgorithms.TryGetValue(Algorithm, out var algorithmFactory))
            {
                Log.LogErrorWithCodeFromResources("FileHash.UnrecognizedHashAlgorithm", Algorithm);
                return false;
            }

            if (!TryParseHashEncoding(HashEncoding, out var encoding))
            {
                Log.LogErrorWithCodeFromResources("FileHash.UnrecognizedHashEncoding", HashEncoding);
                return false;
            }

            var writeLock = new object();
            Parallel.For(0, Files.Length, index =>
            {
                var file = Files[index];

                if (!FileSystems.Default.FileExists(file.ItemSpec))
                {
                    Log.LogErrorWithCodeFromResources("FileHash.FileNotFound", file.ItemSpec);
                    return;
                }

                var hash = ComputeHash(algorithmFactory, file.ItemSpec);
                var encodedHash = EncodeHash(encoding, hash);

                lock (writeLock)
                {
                    // We cannot guarantee Files instances are unique. Write to it inside a lock to
                    // avoid concurrent edits.
                    file.SetMetadata("FileHashAlgorithm", Algorithm);
                    file.SetMetadata(MetadataName, encodedHash);
                }
            });

            if (Log.HasLoggedErrors)
            {
                return false;
            }

            Items = Files;

            if (Files.Length == 1)
            {
                Hash = Files[0].GetMetadata(MetadataName);
            }

            return !Log.HasLoggedErrors;
        }

        internal static string EncodeHash(HashEncoding encoding, byte[] hash)
        {
            return encoding switch
            {
                Tasks.HashEncoding.Hex => ConversionUtilities.ConvertByteArrayToHex(hash),
                Tasks.HashEncoding.Base64 => Convert.ToBase64String(hash),
                _ => throw new NotImplementedException(),
            };
        }

        internal static bool TryParseHashEncoding(string value, out HashEncoding encoding)
            => Enum.TryParse<HashEncoding>(value, /*ignoreCase:*/ true, out encoding);

        internal static byte[] ComputeHash(Func<HashAlgorithm> algorithmFactory, string filePath)
        {
            using (var stream = File.OpenRead(filePath))
            using (var algorithm = algorithmFactory())
            {
                return algorithm.ComputeHash(stream);
            }
        }
    }
}


<|start_filename|>src/Build/Evaluation/IItemProvider.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Generic;

namespace Microsoft.Build.Evaluation
{
    /// <summary>
    /// This interface represents an object which can act as a source of items for the Expander.
    /// </summary>
    /// <typeparam name="T">The type of items provided by the implementation.</typeparam>
    internal interface IItemProvider<T> where T : IItem
    {
        /// <summary>
        /// Returns a list of items with the specified item type.
        /// 
        /// If there are no items of this type, returns an empty list.
        /// </summary>
        /// <param name="itemType">The item type of items to return.</param>
        /// <returns>A list of matching items.</returns>
        ICollection<T> GetItems(string itemType);
    }
}


<|start_filename|>src/Tasks/DownloadFile.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Task = System.Threading.Tasks.Task;

namespace Microsoft.Build.Tasks
{
    /// <summary>
    /// Represents a task that can download a file.
    /// </summary>
    public sealed class DownloadFile : TaskExtension, ICancelableTask
    {
        private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();

        /// <summary>
        /// Gets or sets an optional filename for the destination file.  By default, the filename is derived from the <see cref="SourceUrl"/> if possible.
        /// </summary>
        public ITaskItem DestinationFileName { get; set; }

        /// <summary>
        /// Gets or sets a <see cref="ITaskItem"/> that specifies the destination folder to download the file to.
        /// </summary>
        [Required]
        public ITaskItem DestinationFolder { get; set; }

        /// <summary>
        /// Gets or sets a <see cref="ITaskItem"/> that contains details about the downloaded file.
        /// </summary>
        [Output]
        public ITaskItem DownloadedFile { get; set; }

        /// <summary>
        /// Gets or sets an optional number of times to retry if possible.
        /// </summary>
        public int Retries { get; set; }

        /// <summary>
        /// Gets or sets the number of milliseconds to wait before retrying.
        /// </summary>
        public int RetryDelayMilliseconds { get; set; } = 5 * 1000;

        /// <summary>
        /// Gets or sets an optional value indicating whether or not the download should be skipped if the file is up-to-date.
        /// </summary>
        public bool SkipUnchangedFiles { get; set; } = true;

        /// <summary>
        /// Gets or sets the URL to download.
        /// </summary>
        [Required]
        public string SourceUrl { get; set; }

        /// <summary>
        /// Gets or sets a <see cref="HttpMessageHandler"/> to use.  This is used by unit tests to mock a connection to a remote server.
        /// </summary>
        internal HttpMessageHandler HttpMessageHandler { get; set; }

        /// <inheritdoc cref="ICancelableTask.Cancel"/>
        public void Cancel()
        {
            _cancellationTokenSource.Cancel();
        }

        public override bool Execute()
        {
            return ExecuteAsync().GetAwaiter().GetResult();
        }

        private async Task<bool> ExecuteAsync()
        {
            if (!Uri.TryCreate(SourceUrl, UriKind.Absolute, out Uri uri))
            {
                Log.LogErrorWithCodeFromResources("DownloadFile.ErrorInvalidUrl", SourceUrl);
                return false;
            }

            int retryAttemptCount = 0;
            
            CancellationToken cancellationToken = _cancellationTokenSource.Token;

            while(true)
            {
                try
                {
                    await DownloadAsync(uri, cancellationToken);
                    break;
                }
                catch (OperationCanceledException e) when (e.CancellationToken == cancellationToken)
                {
                    // This task is being cancelled. Exit the loop.
                    break;
                }
                catch (Exception e)
                {
                    bool canRetry = IsRetriable(e, out Exception actualException) && retryAttemptCount++ < Retries;

                    if (canRetry)
                    {
                        Log.LogWarningWithCodeFromResources("DownloadFile.Retrying", SourceUrl, retryAttemptCount + 1, RetryDelayMilliseconds, actualException.Message);

                        try
                        {
                            await Task.Delay(RetryDelayMilliseconds, cancellationToken).ConfigureAwait(false);
                        }
                        catch (OperationCanceledException delayException) when (delayException.CancellationToken == cancellationToken)
                        {
                            // This task is being cancelled, exit the loop
                            break;
                        }
                    }
                    else
                    {
                        Log.LogErrorWithCodeFromResources("DownloadFile.ErrorDownloading", SourceUrl, actualException.Message);
                        break;
                    }
                }
            }

            return !_cancellationTokenSource.IsCancellationRequested && !Log.HasLoggedErrors;
        }

        /// <summary>
        /// Attempts to download the file.
        /// </summary>
        /// <param name="uri">The parsed <see cref="Uri"/> of the request.</param>
        /// <param name="cancellationToken">The cancellation token for the task.</param>
        private async Task DownloadAsync(Uri uri, CancellationToken cancellationToken)
        {
            // The main reason to use HttpClient vs WebClient is because we can pass a message handler for unit tests to mock
            using (var client = new HttpClient(HttpMessageHandler ?? new HttpClientHandler(), disposeHandler: true))
            {
                // Only get the response without downloading the file so we can determine if the file is already up-to-date
                using (HttpResponseMessage response = await client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false))
                {
                    try
                    {
                        response.EnsureSuccessStatusCode();
                    }
                    catch (HttpRequestException e)
                    {
                        // HttpRequestException does not have the status code so its wrapped and thrown here so that later on we can determine
                        // if a retry is possible based on the status code
                        throw new CustomHttpRequestException(e.Message, e.InnerException, response.StatusCode);
                    }

                    if (!TryGetFileName(response, out string filename))
                    {
                        Log.LogErrorWithCodeFromResources("DownloadFile.ErrorUnknownFileName", SourceUrl, nameof(DestinationFileName));
                        return;
                    }

                    DirectoryInfo destinationDirectory = Directory.CreateDirectory(DestinationFolder.ItemSpec);

                    var destinationFile = new FileInfo(Path.Combine(destinationDirectory.FullName, filename));

                    // The file is considered up-to-date if its the same length.  This could be inaccurate, we can consider alternatives in the future
                    if (ShouldSkip(response, destinationFile))
                    {
                        Log.LogMessageFromResources(MessageImportance.Normal, "DownloadFile.DidNotDownloadBecauseOfFileMatch", SourceUrl, destinationFile.FullName, nameof(SkipUnchangedFiles), "true");

                        DownloadedFile = new TaskItem(destinationFile.FullName);

                        return;
                    }

                    try
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        using (var target = new FileStream(destinationFile.FullName, FileMode.Create, FileAccess.Write, FileShare.None))
                        {
                            Log.LogMessageFromResources(MessageImportance.High, "DownloadFile.Downloading", SourceUrl, destinationFile.FullName, response.Content.Headers.ContentLength);

                            using (Stream responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
                            {
                                await responseStream.CopyToAsync(target, 1024, cancellationToken).ConfigureAwait(false);
                            }

                            DownloadedFile = new TaskItem(destinationFile.FullName);
                        }
                    }
                    finally
                    {
                        if (DownloadedFile == null)
                        {
                            // Delete the file if anything goes wrong during download.  This could be destructive but we don't want to leave
                            // partially downloaded files on disk either.  Alternatively we could download to a temporary location and copy
                            // on success but we are concerned about the added I/O
                            destinationFile.Delete();
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Determines if the specified exception is considered retriable.
        /// </summary>
        /// <param name="exception">The originally thrown exception.</param>
        /// <param name="actualException">The actual exception to be used for logging errors.</param>
        /// <returns><code>true</code> if the exception is retriable, otherwise <code>false</code>.</returns>
        private static bool IsRetriable(Exception exception, out Exception actualException)
        {
            actualException = exception;

            // Get aggregate inner exception
            if (actualException is AggregateException aggregateException && aggregateException.InnerException != null)
            {
                actualException = aggregateException.InnerException;
            }

            // Some HttpRequestException have an inner exception that has the real error
            if (actualException is HttpRequestException httpRequestException && httpRequestException.InnerException != null)
            {
                actualException = httpRequestException.InnerException;

                // An IOException inside of a HttpRequestException means that something went wrong while downloading
                if (actualException is IOException)
                {
                    return true;
                }
            }

            if (actualException is CustomHttpRequestException customHttpRequestException)
            {
                // A wrapped CustomHttpRequestException has the status code from the error
                switch (customHttpRequestException.StatusCode)
                {
                    case HttpStatusCode.InternalServerError:
                    case HttpStatusCode.RequestTimeout:
                        return true;
                }
            }

            if (actualException is WebException webException)
            {
                // WebException is thrown when accessing the Content of the response
                switch (webException.Status)
                {
                    // Don't retry on anything that cannot be compensated for
                    case WebExceptionStatus.TrustFailure:
                    case WebExceptionStatus.MessageLengthLimitExceeded:
                    case WebExceptionStatus.RequestProhibitedByCachePolicy:
                    case WebExceptionStatus.RequestProhibitedByProxy:
                        return false;

                    default:
                        // Retry on all other WebExceptions
                        return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Attempts to get the file name to use when downloading the file.
        /// </summary>
        /// <param name="response">The <see cref="HttpResponseMessage"/> with information about the response.</param>
        /// <param name="filename">Receives the name of the file.</param>
        /// <returns><code>true</code> if a file name could be determined, otherwise <code>false</code>.</returns>
        private bool TryGetFileName(HttpResponseMessage response, out string filename)
        {
            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }

            // Not all URIs contain a file name so users will have to specify one
            // Example: http://www.download.com/file/1/

            filename = !String.IsNullOrWhiteSpace(DestinationFileName?.ItemSpec)
                ? DestinationFileName.ItemSpec // Get the file name from what the user specified
                : response.Content?.Headers?.ContentDisposition?.FileName // Attempt to get the file name from the content-disposition header value
                  ?? Path.GetFileName(response.RequestMessage.RequestUri.LocalPath); // Otherwise attempt to get a file name from the URI

            return !String.IsNullOrWhiteSpace(filename);
        }

        /// <summary>
        /// Represents a wrapper around the <see cref="HttpRequestException"/> that also contains the <see cref="HttpStatusCode"/>.
        /// </summary>
        private sealed class CustomHttpRequestException : HttpRequestException
        {
            public CustomHttpRequestException(string message, Exception inner, HttpStatusCode statusCode)
                : base(message, inner)
            {
                StatusCode = statusCode;
            }

            public HttpStatusCode StatusCode { get; }
        }

        private bool ShouldSkip(HttpResponseMessage response, FileInfo destinationFile)
        {
            return SkipUnchangedFiles
                   && destinationFile.Exists
                   && destinationFile.Length == response.Content.Headers.ContentLength
                   && response.Content.Headers.LastModified.HasValue
                   && destinationFile.LastWriteTimeUtc > response.Content.Headers.LastModified.Value.UtcDateTime;
        }
    }
}


<|start_filename|>src/Build.OM.UnitTests/ObjectModelRemoting/RemoteProjectsProviderMock/EvaluationLinkMocks/MockProjectItemLink.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Microsoft.Build.UnitTests.OM.ObjectModelRemoting
{
    using System.Collections.Generic;
    using Microsoft.Build.Construction;
    using Microsoft.Build.Evaluation;
    using Microsoft.Build.ObjectModelRemoting;

    internal class MockProjectItemLinkRemoter : MockLinkRemoter<ProjectItem>
    {
        public override ProjectItem CreateLinkedObject(IImportHolder holder)
        {
            var link = new MockProjectItemLink(this, holder);
            return holder.Linker.LinkFactory.Create(link);
        }


        ///  ProjectItemLink remoting
        public MockProjectLinkRemoter Project => this.OwningCollection.Export<Project, MockProjectLinkRemoter>(this.Source.Project);
        public MockProjectItemElementLinkRemoter Xml => (MockProjectItemElementLinkRemoter)this.OwningCollection.ExportElement(this.Source.Xml);
        public string EvaluatedInclude => this.Source.EvaluatedInclude;
        public ICollection<MockProjectMetadataLinkRemoter> MetadataCollection => this.OwningCollection.ExportCollection<ProjectMetadata, MockProjectMetadataLinkRemoter>(this.Source.Metadata);
        public ICollection<MockProjectMetadataLinkRemoter> DirectMetadata => this.OwningCollection.ExportCollection<ProjectMetadata, MockProjectMetadataLinkRemoter>(this.Source.DirectMetadata);
        public bool HasMetadata(string name) => this.Source.HasMetadata(name);
        public MockProjectMetadataLinkRemoter GetMetadata(string name)
            => this.OwningCollection.Export<ProjectMetadata, MockProjectMetadataLinkRemoter>(this.Source.GetMetadata(name));
        public string GetMetadataValue(string name) => this.Source.GetMetadataValue(name);
        public MockProjectMetadataLinkRemoter SetMetadataValue(string name, string unevaluatedValue, bool propagateMetadataToSiblingItems)
            => this.OwningCollection.Export<ProjectMetadata, MockProjectMetadataLinkRemoter>(this.Source.SetMetadataValue(name, unevaluatedValue, propagateMetadataToSiblingItems));
        public bool RemoveMetadata(string name) => this.Source.RemoveMetadata(name);
        public void Rename(string name) => this.Source.Rename(name);
        public void ChangeItemType(string newItemType) => this.Source.ItemType = newItemType;
    }

    internal class MockProjectItemLink : ProjectItemLink, ILinkMock
    {
        public MockProjectItemLink(MockProjectItemLinkRemoter proxy, IImportHolder holder)
        {
            this.Holder = holder;
            this.Proxy = proxy;
        }

        public IImportHolder Holder { get; }
        public ProjectCollectionLinker Linker => this.Holder.Linker;
        public MockProjectItemLinkRemoter Proxy { get; }
        object ILinkMock.Remoter => this.Proxy;

        // ProjectItemLink

        public override Project Project => this.Linker.Import<Project, MockProjectLinkRemoter>(this.Proxy.Project);
        public override ProjectItemElement Xml => (ProjectItemElement)this.Proxy.Xml.Import(this.Linker);
        public override string EvaluatedInclude => this.Proxy.EvaluatedInclude;
        public override ICollection<ProjectMetadata> MetadataCollection
            => this.Linker.ImportCollection<ProjectMetadata, MockProjectMetadataLinkRemoter>(this.Proxy.MetadataCollection);
        public override ICollection<ProjectMetadata> DirectMetadata
            => this.Linker.ImportCollection<ProjectMetadata, MockProjectMetadataLinkRemoter>(this.Proxy.DirectMetadata);
        public override bool HasMetadata(string name) => this.Proxy.HasMetadata(name);
        public override ProjectMetadata GetMetadata(string name)
            => this.Linker.Import<ProjectMetadata, MockProjectMetadataLinkRemoter>(this.Proxy.GetMetadata(name));
        public override string GetMetadataValue(string name) => this.Proxy.GetMetadataValue(name);
        public override ProjectMetadata SetMetadataValue(string name, string unevaluatedValue, bool propagateMetadataToSiblingItems)
            => this.Linker.Import<ProjectMetadata, MockProjectMetadataLinkRemoter>(this.Proxy.SetMetadataValue(name, unevaluatedValue, propagateMetadataToSiblingItems));
        public override bool RemoveMetadata(string name) => this.Proxy.RemoveMetadata(name);
        public override void Rename(string name) => this.Proxy.Rename(name);
        public override void ChangeItemType(string newItemType) => this.Proxy.ChangeItemType(newItemType);
    }
}


<|start_filename|>src/Utilities/CommandLineBuilder.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Diagnostics;
using System.IO;
using System.Text;

using Microsoft.Build.Framework;
using System.Text.RegularExpressions;
using Microsoft.Build.Shared;

namespace Microsoft.Build.Utilities
{
    /// <summary>
    /// (1) Make sure values containing hyphens are quoted (RC at least requires this)
    /// (2) Escape any embedded quotes. 
    ///     -- Literal double quotes should be written in the form \" not ""
    ///     -- Backslashes falling just before doublequotes must be doubled.
    ///     -- Literal double quotes can only occur in pairs (you cannot pass a single literal double quote)
    /// 	-- Functional double quotes (for example to handle spaces) are best put around both name and value
    /// 	    in switches like /Dname=value.
    /// </summary>
    /// <remarks>
    /// 
    /// Below are some quoting experiments, using the /D switch with the CL and RC preprocessor.
    /// The /D switch is a little more tricky than most switches, because it has a name=value pair.
    /// The table below contains what the preprocessor actually embeds when passed the switch in the
    /// first column:
    /// 
    ///                      CL via cmd line         CL via response file       RC
    ///     /DFOO="A"                A                   A   
    ///     /D"FOO="A""              A                   A                       A
    ///     /DFOO=A                  A                   A   
    ///     /D"FOO=A"                A                   A   
    ///     /DFOO=""A""              A                   A                       A
    ///         
    ///     /DFOO=\"A\"             "A"                                         "A"
    ///     /DFOO="""A"""           "A"                broken                   "A"
    ///     /D"FOO=\"A\""           "A"                                         "A"
    ///     /D"FOO=""A"""           "A"                                         "A"
    ///         
    ///     /DFOO="A B"             A B                 A B 
    ///     /D"FOO=A B"             A B                 A B 
    ///         
    ///     /D"FOO="A B""          broken      
    ///     /DFOO=\"A B\"          broken      
    ///     /D"FOO=\"A B\""        "A B"               "A B"                   "A B"
    ///     /D"FOO=""A B"""        "A B"               broken                  broken
    ///
    /// From my experiments (with CL and RC only) it seems that 
    ///    -- Literal double quotes are most reliably written in the form \" not ""
    ///    -- Backslashes falling just before doublequotes must be doubled.
    ///    -- Values containing literal double quotes must be quoted.
    ///    -- Literal double quotes can only occur in pairs (you cannot pass a single literal double quote)
    ///    -- For /Dname=value style switches, functional double quotes (for example to handle spaces) are best put around both 
    ///           name and value (in other words, these kinds of switches don't need special treatment for their '=' signs).
    ///    -- Values containing hyphens should be quoted; RC requires this, and CL does not mind.
    /// </remarks>
    public class CommandLineBuilder
    {
        #region Constructors

        /// <summary>
        /// Default constructor
        /// </summary>
        public CommandLineBuilder()
        {
        }

        /// <summary>
        /// Default constructor
        /// </summary>
        public CommandLineBuilder(bool quoteHyphensOnCommandLine)
        {
            _quoteHyphens = quoteHyphensOnCommandLine;
        }

        /// <summary>
        /// Default constructor
        /// </summary>
        public CommandLineBuilder(bool quoteHyphensOnCommandLine, bool useNewLineSeparator)
            : this(quoteHyphensOnCommandLine)
        {
            _useNewLineSeparator = useNewLineSeparator;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Returns the length of the current command
        /// </summary>
        public int Length => CommandLine.Length;

        /// <summary>
        /// Retrieves the private StringBuilder instance for inheriting classes
        /// </summary>
        protected StringBuilder CommandLine { get; } = new StringBuilder();

        #endregion

        #region Basic methods

        /// <summary>
        /// Return the command-line as a string.
        /// </summary>
        /// <returns></returns>
        public override string ToString() => CommandLine.ToString();

        // Use if escaping of hyphens is supposed to take place
        private static readonly string s_allowedUnquotedRegexNoHyphen =
                         "^"                             // Beginning of line
                       + @"[a-z\\/:0-9\._+=]*"
                       + "$";

        private static readonly string s_definitelyNeedQuotesRegexWithHyphen = @"[|><\s,;\-""]+";

        // Use if escaping of hyphens is not to take place
        private static readonly string s_allowedUnquotedRegexWithHyphen =
                        "^"                             // Beginning of line
                       + @"[a-z\\/:0-9\._\-+=]*"       //  Allow hyphen to be unquoted
                       + "$";
        private static readonly string s_definitelyNeedQuotesRegexNoHyphen = @"[|><\s,;""]+";

        /// <summary>
        ///  Should hyphens be quoted or not
        /// </summary>
        private readonly bool _quoteHyphens;

        /// <summary>
        /// Should use new line separators instead of spaces to separate arguments.
        /// </summary>
        private readonly bool _useNewLineSeparator;

        /// <summary>
        /// Instead of defining which characters must be quoted, define 
        /// which characters we know its safe to not quote. This way leads
        /// to more false-positives (which still work, but don't look as 
        /// nice coming out of the logger), but is less likely to leave a 
        /// security hole.
        /// </summary>
        private Regex _allowedUnquoted;

        /// <summary>
        /// Also, define the characters that we know for certain need quotes.
        /// This is partly to document which characters we know can cause trouble
        /// and partly as a sanity check against a bug creeping in.
        /// </summary>
        private Regex _definitelyNeedQuotes;

        /// <summary>
        /// Use a private property so that we can lazy initialize the regex
        /// </summary>
        private Regex DefinitelyNeedQuotes => _definitelyNeedQuotes
            ?? (_definitelyNeedQuotes = new Regex(_quoteHyphens ? s_definitelyNeedQuotesRegexWithHyphen : s_definitelyNeedQuotesRegexNoHyphen, RegexOptions.None));

        /// <summary>
        /// Use a private getter property to we can lazy initialize the regex
        /// </summary>
        private Regex AllowedUnquoted => _allowedUnquoted
            ?? (_allowedUnquoted = new Regex(_quoteHyphens ? s_allowedUnquotedRegexNoHyphen : s_allowedUnquotedRegexWithHyphen, RegexOptions.IgnoreCase));

        /// <summary>
        /// Checks the given switch parameter to see if it must/can be quoted.
        /// </summary>
        /// <param name="parameter">the string to examine for characters that require quoting</param>
        /// <returns>true, if parameter should be quoted</returns>
        protected virtual bool IsQuotingRequired(string parameter)
        {
            bool isQuotingRequired = false;

            if (parameter != null)
            {
                #region Security Note: About cross-parameter injection
                /*
                        If string parameters have whitespace in them, then a possible attack would
                        be like the following:

                            <Win32Icon>MyFile.ico /out:c:\windows\system32\notepad.exe</Win32Icon>

                            <Csc
                                Win32Icon="$(Win32Icon)"
                                ...
                            />

                        Since we just build up a command-line to pass into CSC.EXE, without quoting,
                        the project might overwrite notepad.exe.

                        If there are spaces in the parameter, then we must quote that parameter.
                    */
                #endregion
                bool hasAllUnquotedCharacters = AllowedUnquoted.IsMatch(parameter);
                bool hasSomeQuotedCharacters = DefinitelyNeedQuotes.IsMatch(parameter);

                isQuotingRequired = !hasAllUnquotedCharacters;
                isQuotingRequired = isQuotingRequired || hasSomeQuotedCharacters;

                Debug.Assert(!hasAllUnquotedCharacters || !hasSomeQuotedCharacters,
                    "At least one of allowedUnquoted or definitelyNeedQuotes is wrong.");
            }

            return isQuotingRequired;
        }

        /// <summary>
        /// Add a space or newline to the specified string if and only if it's not empty.
        /// </summary>
        /// <remarks>
        /// This is a pretty obscure method and so it's only available to inherited classes.
        /// </remarks>
        protected void AppendSpaceIfNotEmpty()
        {
            if (CommandLine.Length != 0)
            {
                if (_useNewLineSeparator)
                {
                    CommandLine.Append(Environment.NewLine);
                }
                else if(CommandLine[CommandLine.Length - 1] != ' ')
                {
                    CommandLine.Append(" ");
                }
            }
        }

        #endregion

        #region Methods for use in inherited classes, do not prepend a space before doing their thing

        /// <summary>
        /// Appends a string. Quotes are added if they are needed.
        /// This method does not append a space to the command line before executing.
        /// </summary>
        /// <remarks>
        /// Escapes any double quotes in the string.
        /// </remarks>
        /// <param name="textToAppend">The string to append</param>
        protected void AppendTextWithQuoting(string textToAppend) => AppendQuotedTextToBuffer(CommandLine, textToAppend);

        /// <summary>
        /// Appends given text to the buffer after first quoting the text if necessary.
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="unquotedTextToAppend"></param>
        protected void AppendQuotedTextToBuffer(StringBuilder buffer, string unquotedTextToAppend)
        {
            ErrorUtilities.VerifyThrowArgumentNull(buffer, nameof(buffer));

            if (unquotedTextToAppend != null)
            {
                bool addQuotes = IsQuotingRequired(unquotedTextToAppend);

                if (addQuotes)
                {
                    buffer.Append('"');
                }

                // Count the number of quotes
                int literalQuotes = 0;
                for (int i = 0; i < unquotedTextToAppend.Length; i++)
                {
                    if (unquotedTextToAppend[i] == '"')
                    {
                        literalQuotes++;
                    }
                }
                if (literalQuotes > 0)
                {
                    // Replace any \" sequences with \\"
                    unquotedTextToAppend = unquotedTextToAppend.Replace("\\\"", "\\\\\"");
                    // Now replace any " with \"
                    unquotedTextToAppend = unquotedTextToAppend.Replace("\"", "\\\"");
                }

                buffer.Append(unquotedTextToAppend);

                // Be careful any trailing slash doesn't escape the quote we're about to add
                if (addQuotes && unquotedTextToAppend.EndsWith("\\", StringComparison.Ordinal))
                {
                    buffer.Append('\\');
                }

                if (addQuotes)
                {
                    buffer.Append('"');
                }
            }
        }

        /// <summary>
        /// Appends a string. No quotes are added.
        /// This method does not append a space to the command line before executing.
        /// </summary>
        /// <example>
        /// AppendTextUnquoted(@"Folder name\filename.cs") => "Folder name\\filename.cs"
        /// </example>
        /// <remarks>
        /// In the future, this function may fixup 'textToAppend' to handle
        /// literal embedded quotes.
        /// </remarks>
        /// <param name="textToAppend">The string to append</param>
        public void AppendTextUnquoted(string textToAppend)
        {
            if (textToAppend != null)
            {
                CommandLine.Append(textToAppend);
            }
        }

        /// <summary>
        /// Appends a file name. Quotes are added if they are needed. 
        /// If the first character of the file name is a dash, ".\" is prepended to avoid confusing the file name with a switch
        /// This method does not append a space to the command line before executing.
        /// </summary>
        /// <example>
        /// AppendFileNameWithQuoting("-StrangeFileName.cs") => ".\-StrangeFileName.cs"
        /// </example>
        /// <remarks>
        /// In the future, this function may fixup 'text' to handle
        /// literal embedded quotes.
        /// </remarks>
        /// <param name="fileName">The file name to append</param>
        protected void AppendFileNameWithQuoting(string fileName)
        {
            if (fileName != null)
            {
                // Don't let injection attackers escape from our quotes by sticking in
                // their own quotes. Quotes are illegal.
                VerifyThrowNoEmbeddedDoubleQuotes(string.Empty, fileName);

                fileName = FileUtilities.FixFilePath(fileName);
                if (fileName.Length != 0 && fileName[0] == '-')
                {
                    AppendTextWithQuoting("." + Path.DirectorySeparatorChar + fileName);
                }
                else
                {
                    AppendTextWithQuoting(fileName);
                }
            }
        }

        #endregion

        #region Appending file names

        /// <summary>
        /// Appends a file name quoting it if necessary.
        /// This method appends a space to the command line (if it's not currently empty) before the file name.
        /// </summary>
        /// <example>
        /// AppendFileNameIfNotNull("-StrangeFileName.cs") => ".\-StrangeFileName.cs"
        /// </example>
        /// <param name="fileName">File name to append, if it's null this method has no effect</param>
        public void AppendFileNameIfNotNull(string fileName)
        {
            if (fileName != null)
            {
                // Don't let injection attackers escape from our quotes by sticking in
                // their own quotes. Quotes are illegal.
                VerifyThrowNoEmbeddedDoubleQuotes(string.Empty, fileName);

                AppendSpaceIfNotEmpty();
                AppendFileNameWithQuoting(fileName);
            }
        }

        /// <summary>
        /// Appends a file name quoting it if necessary.
        /// This method appends a space to the command line (if it's not currently empty) before the file name.
        /// </summary>
        /// <example>
        /// See the string overload version
        /// </example>
        /// <param name="fileItem">File name to append, if it's null this method has no effect</param>
        public void AppendFileNameIfNotNull(ITaskItem fileItem)
        {
            if (fileItem != null)
            {
                // Don't let injection attackers escape from our quotes by sticking in
                // their own quotes. Quotes are illegal.
                VerifyThrowNoEmbeddedDoubleQuotes(string.Empty, fileItem.ItemSpec);

                AppendFileNameIfNotNull(fileItem.ItemSpec);
            }
        }

        /// <summary>
        /// Appends array of file name strings, quoting them if necessary, delimited by a delimiter.
        /// This method appends a space to the command line (if it's not currently empty) before the file names.
        /// </summary>
        /// <example>
        /// AppendFileNamesIfNotNull(new string[] {"Alpha.cs", "Beta.cs"}, ",") => "Alpha.cs,Beta.cs"
        /// </example>
        /// <param name="fileNames">File names to append, if it's null this method has no effect</param>
        /// <param name="delimiter">The delimiter between file names</param>
        public void AppendFileNamesIfNotNull(string[] fileNames, string delimiter)
        {
            ErrorUtilities.VerifyThrowArgumentNull(delimiter, nameof(delimiter));

            if (fileNames?.Length > 0)
            {
                // Don't let injection attackers escape from our quotes by sticking in
                // their own quotes. Quotes are illegal.
                for (int i = 0; i < fileNames.Length; ++i)
                {
                    VerifyThrowNoEmbeddedDoubleQuotes(string.Empty, fileNames[i]);
                }

                AppendSpaceIfNotEmpty();
                for (int i = 0; i < fileNames.Length; ++i)
                {
                    if (i != 0)
                    {
                        AppendTextUnquoted(delimiter);
                    }

                    AppendFileNameWithQuoting(fileNames[i]);
                }
            }
        }

        /// <summary>
        /// Appends array of ITaskItem specs as file names, quoting them if necessary, delimited by a delimiter.
        /// This method appends a space to the command line (if it's not currently empty) before the file names.
        /// </summary>
        /// <example>
        /// See the string[] overload version
        /// </example>
        /// <param name="fileItems">Task items to append, if null this method has no effect</param>
        /// <param name="delimiter">Delimiter to put between items in the command line</param>
        public void AppendFileNamesIfNotNull(ITaskItem[] fileItems, string delimiter)
        {
            ErrorUtilities.VerifyThrowArgumentNull(delimiter, nameof(delimiter));

            if (fileItems?.Length > 0)
            {
                // Don't let injection attackers escape from our quotes by sticking in
                // their own quotes. Quotes are illegal.
                for (int i = 0; i < fileItems.Length; ++i)
                {
                    if (fileItems[i] != null)
                    {
                        VerifyThrowNoEmbeddedDoubleQuotes(string.Empty, fileItems[i].ItemSpec);
                    }
                }

                AppendSpaceIfNotEmpty();
                for (int i = 0; i < fileItems.Length; ++i)
                {
                    if (i != 0)
                    {
                        AppendTextUnquoted(delimiter);
                    }

                    if (fileItems[i] != null)
                    {
                        AppendFileNameWithQuoting(fileItems[i].ItemSpec);
                    }
                }
            }
        }

        #endregion

        #region Appending switches with quoted parameters

        /// <summary>
        /// Appends a command-line switch that has no separate value, without any quoting.
        /// This method appends a space to the command line (if it's not currently empty) before the switch.
        /// </summary>
        /// <example>
        /// AppendSwitch("/utf8output") => "/utf8output"
        /// </example>
        /// <param name="switchName">The switch to append to the command line, may not be null</param>
        public void AppendSwitch(string switchName)
        {
            ErrorUtilities.VerifyThrowArgumentNull(switchName, nameof(switchName));

            AppendSpaceIfNotEmpty();
            AppendTextUnquoted(switchName);
        }

        /// <summary>
        /// Appends a command-line switch that takes a single string parameter, quoting the parameter if necessary.
        /// This method appends a space to the command line (if it's not currently empty) before the switch.
        /// </summary>
        /// <example>
        /// AppendSwitchIfNotNull("/source:", "File Name.cs") => "/source:\"File Name.cs\""
        /// </example>
        /// <param name="switchName">The switch to append to the command line, may not be null</param>
        /// <param name="parameter">Switch parameter to append, quoted if necessary. If null, this method has no effect.</param>
        public void AppendSwitchIfNotNull(string switchName, string parameter)
        {
            ErrorUtilities.VerifyThrowArgumentNull(switchName, nameof(switchName));

            if (parameter != null)
            {
                // Now, stick the parameter in.
                AppendSwitch(switchName);
                AppendTextWithQuoting(parameter);
            }
        }

        /// <summary>
        /// Throws if the parameter has a double-quote in it. This is used to prevent parameter
        /// injection. It's virtual so that tools can override this method if they want to have quotes escaped in filenames
        /// </summary>
        /// <param name="switchName">Switch name for error message</param>
        /// <param name="parameter">Switch parameter to scan</param>
        protected virtual void VerifyThrowNoEmbeddedDoubleQuotes(string switchName, string parameter)
        {
            if (parameter != null)
            {
                if (string.IsNullOrEmpty(switchName))
                {
                    ErrorUtilities.VerifyThrowArgument
                        (
                            -1 == parameter.IndexOf('"'),
                            "General.QuotesNotAllowedInThisKindOfTaskParameterNoSwitchName",
                            parameter
                        );
                }
                else
                {
                    ErrorUtilities.VerifyThrowArgument
                        (
                            -1 == parameter.IndexOf('"'),
                            "General.QuotesNotAllowedInThisKindOfTaskParameter",
                            switchName,
                            parameter
                        );
                }
            }
        }

        /// <summary>
        /// Append a switch [overload]
        /// This method appends a space to the command line (if it's not currently empty) before the switch.
        /// </summary>
        /// <example>
        /// See the string overload version
        /// </example>
        /// <param name="switchName">The switch to append to the command line, may not be null</param>
        /// <param name="parameter">Switch parameter to append, quoted if necessary. If null, this method has no effect.</param>
        public void AppendSwitchIfNotNull(string switchName, ITaskItem parameter)
        {
            ErrorUtilities.VerifyThrowArgumentNull(switchName, nameof(switchName));

            if (parameter != null)
            {
                AppendSwitchIfNotNull(switchName, parameter.ItemSpec);
            }
        }

        /// <summary>
        /// Appends a command-line switch that takes a string[] parameter,
        /// and add double-quotes around the individual filenames if necessary.
        /// This method appends a space to the command line (if it's not currently empty) before the switch.
        /// </summary>
        /// <example>
        /// AppendSwitchIfNotNull("/sources:", new string[] {"Alpha.cs", "Be ta.cs"}, ";") => "/sources:Alpha.cs;\"Be ta.cs\""
        /// </example>
        /// <param name="switchName">The switch to append to the command line, may not be null</param>
        /// <param name="parameters">Switch parameters to append, quoted if necessary. If null, this method has no effect.</param>
        /// <param name="delimiter">Delimiter to put between individual parameters, may not be null (may be empty)</param>
        public void AppendSwitchIfNotNull(string switchName, string[] parameters, string delimiter)
        {
            ErrorUtilities.VerifyThrowArgumentNull(switchName, nameof(switchName));
            ErrorUtilities.VerifyThrowArgumentNull(delimiter, nameof(delimiter));

            if (parameters?.Length > 0)
            {
                AppendSwitch(switchName);
                bool first = true;
                foreach (string parameter in parameters)
                {
                    if (!first)
                    {
                        AppendTextUnquoted(delimiter);
                    }
                    first = false;
                    AppendTextWithQuoting(parameter);
                }
            }
        }

        /// <summary>
        /// Appends a command-line switch that takes a ITaskItem[] parameter,
        /// and add double-quotes around the individual filenames if necessary.
        /// This method appends a space to the command line (if it's not currently empty) before the switch.
        /// </summary>
        /// <example>
        /// See the string[] overload version
        /// </example>
        /// <param name="switchName">The switch to append to the command line, may not be null</param>
        /// <param name="parameters">Switch parameters to append, quoted if necessary. If null, this method has no effect.</param>
        /// <param name="delimiter">Delimiter to put between individual parameters, may not be null (may be empty)</param>
        public void AppendSwitchIfNotNull(string switchName, ITaskItem[] parameters, string delimiter)
        {
            ErrorUtilities.VerifyThrowArgumentNull(switchName, nameof(switchName));
            ErrorUtilities.VerifyThrowArgumentNull(delimiter, nameof(delimiter));

            if (parameters?.Length > 0)
            {
                AppendSwitch(switchName);
                bool first = true;
                foreach (ITaskItem parameter in parameters)
                {
                    if (!first)
                    {
                        AppendTextUnquoted(delimiter);
                    }
                    first = false;

                    if (parameter != null)
                    {
                        AppendTextWithQuoting(parameter.ItemSpec);
                    }
                }
            }
        }

        #endregion

        #region Append switches with unquoted parameters

        /// <summary>
        /// Appends the literal parameter without trying to quote.
        /// This method appends a space to the command line (if it's not currently empty) before the switch.
        /// </summary>
        /// <example>
        /// AppendSwitchUnquotedIfNotNull("/source:", "File Name.cs") => "/source:File Name.cs"
        /// </example>
        /// <param name="switchName">The switch to append to the command line, may not be null</param>
        /// <param name="parameter">Switch parameter to append, not quoted. If null, this method has no effect.</param>
        public void AppendSwitchUnquotedIfNotNull(string switchName, string parameter)
        {
            ErrorUtilities.VerifyThrowArgumentNull(switchName, nameof(switchName));

            if (parameter != null)
            {
                // Now, stick the parameter in.
                AppendSwitch(switchName);
                AppendTextUnquoted(parameter);
            }
        }

        /// <summary>
        /// Appends the literal parameter without trying to quote.
        /// This method appends a space to the command line (if it's not currently empty) before the switch.
        /// </summary>
        /// <example>
        /// See the string overload version
        /// </example>
        /// <param name="switchName">The switch to append to the command line, may not be null</param>
        /// <param name="parameter">Switch parameter to append, not quoted. If null, this method has no effect.</param>
        public void AppendSwitchUnquotedIfNotNull(string switchName, ITaskItem parameter)
        {
            ErrorUtilities.VerifyThrowArgumentNull(switchName, nameof(switchName));

            if (parameter != null)
            {
                AppendSwitchUnquotedIfNotNull(switchName, parameter.ItemSpec);
            }
        }

        /// <summary>
        /// Appends a command-line switch that takes a string[] parameter, not quoting the individual parameters
        /// This method appends a space to the command line (if it's not currently empty) before the switch.
        /// </summary>
        /// <example>
        /// AppendSwitchUnquotedIfNotNull("/sources:", new string[] {"Alpha.cs", "Be ta.cs"}, ";") => "/sources:Alpha.cs;Be ta.cs"
        /// </example>
        /// <param name="switchName">The switch to append to the command line, may not be null</param>
        /// <param name="parameters">Switch parameters to append, not quoted. If null, this method has no effect.</param>
        /// <param name="delimiter">Delimiter to put between individual parameters, may not be null (may be empty)</param>
        public void AppendSwitchUnquotedIfNotNull(string switchName, string[] parameters, string delimiter)
        {
            ErrorUtilities.VerifyThrowArgumentNull(switchName, nameof(switchName));
            ErrorUtilities.VerifyThrowArgumentNull(delimiter, nameof(delimiter));

            if (parameters?.Length > 0)
            {
                AppendSwitch(switchName);
                bool first = true;
                foreach (string parameter in parameters)
                {
                    if (!first)
                    {
                        AppendTextUnquoted(delimiter);
                    }
                    first = false;
                    AppendTextUnquoted(parameter);
                }
            }
        }

        /// <summary>
        /// Appends a command-line switch that takes a ITaskItem[] parameter, not quoting the individual parameters
        /// This method appends a space to the command line (if it's not currently empty) before the switch.
        /// </summary>
        /// <example>
        /// See the string[] overload version
        /// </example>
        /// <param name="switchName">The switch to append to the command line, may not be null</param>
        /// <param name="parameters">Switch parameters to append, not quoted. If null, this method has no effect.</param>
        /// <param name="delimiter">Delimiter to put between individual parameters, may not be null (may be empty)</param>
        public void AppendSwitchUnquotedIfNotNull(string switchName, ITaskItem[] parameters, string delimiter)
        {
            ErrorUtilities.VerifyThrowArgumentNull(switchName, nameof(switchName));
            ErrorUtilities.VerifyThrowArgumentNull(delimiter, nameof(delimiter));

            if (parameters?.Length > 0)
            {
                AppendSwitch(switchName);
                bool first = true;
                foreach (ITaskItem parameter in parameters)
                {
                    if (!first)
                    {
                        AppendTextUnquoted(delimiter);
                    }
                    first = false;

                    if (parameter != null)
                    {
                        AppendTextUnquoted(parameter.ItemSpec);
                    }
                }
            }
        }

        #endregion
    }
}


<|start_filename|>src/Shared/ReadOnlyCollection.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
using Microsoft.Build.Shared;

namespace Microsoft.Build.Collections
{
    /// <summary>
    /// A read-only live wrapper over a collection.
    /// It does not prevent modification of the values themselves.
    /// </summary>
    /// <remarks>
    /// There is a type with the same name in the BCL, but it is actually a ReadOnlyList and does not accept an ICollection&gt;T&lt;.
    /// Thus this is an omission from the BCL.
    /// </remarks>
    /// <typeparam name="T">Type of element in the collection</typeparam>
    internal class ReadOnlyCollection<T> : ICollection<T>, ICollection
    {
        /// <summary>
        /// Backing live enumerable.
        /// May be a collection.
        /// </summary>
        private IEnumerable<T> _backing;

        /// <summary>
        /// Construct a read only wrapper around the current contents 
        /// of the IEnumerable, or around the backing collection if the 
        /// IEnumerable is in fact a collection. 
        /// </summary>
        internal ReadOnlyCollection(IEnumerable<T> backing)
        {
            ErrorUtilities.VerifyThrow(backing != null, "Need backing collection");

            _backing = backing;
        }

        /// <summary>
        /// Return the number of items in the backing collection
        /// </summary>
        public int Count
        {
            get
            {
                return BackingCollection.Count;
            }
        }

        /// <summary>
        /// Returns true.
        /// </summary>
        public bool IsReadOnly
        {
            get { return true; }
        }

        /// <summary>
        /// Whether collection is synchronized
        /// </summary>
        bool ICollection.IsSynchronized
        {
            get { return false; }
        }

        /// <summary>
        /// Sync root
        /// </summary>
        object ICollection.SyncRoot
        {
            get { return this; }
        }

        /// <summary>
        /// Get a backing ICollection.
        /// </summary>
        private ICollection<T> BackingCollection
        {
            get
            {
                ICollection<T> backingCollection = _backing as ICollection<T>;
                if (backingCollection == null)
                {
                    backingCollection = new List<T>(_backing);
                    _backing = backingCollection;
                }

                return backingCollection;
            }
        }

        /// <summary>
        /// Prohibited on read only collection: throws
        /// </summary>
        public void Add(T item)
        {
            ErrorUtilities.ThrowInvalidOperation("OM_NotSupportedReadOnlyCollection");
        }

        /// <summary>
        /// Prohibited on read only collection: throws
        /// </summary>
        public void Clear()
        {
            ErrorUtilities.ThrowInvalidOperation("OM_NotSupportedReadOnlyCollection");
        }

        /// <summary>
        /// Pass through for underlying collection
        /// </summary>
        public bool Contains(T item)
        {
            // UNDONE: IEnumerable.Contains<T>() does the ICollection check, 
            // so we could just use IEnumerable.Contains<T>() here.  
            if (!(_backing is ICollection<T>))
            {
                return _backing.Contains<T>(item);
            }

            return BackingCollection.Contains(item);
        }

        /// <summary>
        /// Pass through for underlying collection
        /// </summary>
        public void CopyTo(T[] array, int arrayIndex)
        {
            ErrorUtilities.VerifyThrowArgumentNull(array, nameof(array));

            ICollection<T> backingCollection = _backing as ICollection<T>;
            if (backingCollection != null)
            {
                backingCollection.CopyTo(array, arrayIndex);
            }
            else
            {
                int i = arrayIndex;
                foreach (T entry in _backing)
                {
                    array[i] = entry;
                    i++;
                }
            }
        }

        /// <summary>
        /// Prohibited on read only collection: throws
        /// </summary>
        public bool Remove(T item)
        {
            ErrorUtilities.ThrowInvalidOperation("OM_NotSupportedReadOnlyCollection");
            return false;
        }

        /// <summary>
        /// Pass through for underlying collection
        /// </summary>
        /// <comment>
        /// NOTE: This does NOT cause a copy into a List, since the
        /// backing enumerable suffices.
        /// </comment>
        public IEnumerator<T> GetEnumerator()
        {
            return _backing.GetEnumerator();
        }

        /// <summary>
        /// Pass through for underlying collection
        /// </summary>
        /// <comment>
        /// NOTE: This does NOT cause a copy into a List, since the
        /// backing enumerable suffices.
        /// </comment>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable)_backing).GetEnumerator();
        }

        /// <summary>
        /// ICollection version of CopyTo
        /// </summary>
        void ICollection.CopyTo(Array array, int index)
        {
            ErrorUtilities.VerifyThrowArgumentNull(array, nameof(array));

            int i = index;
            foreach (T entry in _backing)
            {
                array.SetValue(entry, i);
                i++;
            }
        }
    }
}


<|start_filename|>src/Build.UnitTests/LogFormatter_Tests.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using Microsoft.Build.BackEnd.Logging;
using System.Globalization;
using Xunit;

namespace Microsoft.Build.UnitTests
{
    public class LogFormatterTest
    {
        /*
        * Method:  TimeSpanMediumDuration
        *
        * Tests the mainline: a medium length duration
        * Note the ToString overload used in FormatTimeSpan is culture insensitive.
        */
        [Fact]
        public void TimeSpanMediumDuration()
        {
            TimeSpan t = new TimeSpan(1254544900);
            string result = LogFormatter.FormatTimeSpan(t);
            Assert.Equal("00:02:05.45", result);
        }


        /*
        * Method:  TimeSpanZeroDuration
        *
        * Format a TimeSpan where the duration is zero.
        * Note the ToString overload used in FormatTimeSpan is culture insensitive.
        */
        [Fact]
        public void TimeSpanZeroDuration()
        {
            TimeSpan t = new TimeSpan(0);
            string result = LogFormatter.FormatTimeSpan(t);
            Assert.Equal("00:00:00", result);
        }

        [Fact]
        public void FormatDateTime()
        {
            DateTime testTime = new DateTime(2007 /*Year*/, 08 /*Month*/, 20 /*Day*/, 10 /*Hour*/, 42 /*Minutes*/, 44 /*Seconds*/, 12 /*Milliseconds*/);
            string result = LogFormatter.FormatLogTimeStamp(testTime);

            Assert.Equal(testTime.ToString("HH:mm:ss.fff", CultureInfo.CurrentCulture), result);

            testTime = new DateTime(2007, 08, 20, 05, 04, 03, 01);
            result = LogFormatter.FormatLogTimeStamp(testTime);
            Assert.Equal(testTime.ToString("HH:mm:ss.fff", CultureInfo.CurrentCulture), result);

            testTime = new DateTime(2007, 08, 20, 0, 0, 0, 0);
            result = LogFormatter.FormatLogTimeStamp(testTime);
            Assert.Equal(testTime.ToString("HH:mm:ss.fff", CultureInfo.CurrentCulture), result);
        }
    }
}


<|start_filename|>src/Xunit.NetCore.Extensions/Discoverers/ConditionalFactDiscoverer.cs<|end_filename|>
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;
using System.Linq;
using Xunit.Abstractions;
using Xunit.Sdk;

namespace Xunit.NetCore.Extensions
{
    public class ConditionalFactDiscoverer : FactDiscoverer
    {
        private readonly IMessageSink _diagnosticMessageSink;

        public ConditionalFactDiscoverer(IMessageSink diagnosticMessageSink) : base(diagnosticMessageSink)
        {
            _diagnosticMessageSink = diagnosticMessageSink;
        }

        public override IEnumerable<IXunitTestCase> Discover(
            ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute)
        {
            IEnumerable<IXunitTestCase> testCases = base.Discover(discoveryOptions, testMethod, factAttribute);
            return ConditionalTestDiscoverer.Discover(discoveryOptions, _diagnosticMessageSink, testMethod, testCases, factAttribute.GetConstructorArguments().ToArray());
        }
    }
}


<|start_filename|>src/Build/Definition/ProjectProperty.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Diagnostics;
using Microsoft.Build.Collections;
using Microsoft.Build.Construction;
using Microsoft.Build.Shared;

using ReservedPropertyNames = Microsoft.Build.Internal.ReservedPropertyNames;

namespace Microsoft.Build.Evaluation
{
    /// <summary>
    /// An evaluated design-time property
    /// </summary>
    [DebuggerDisplay("{Name}={EvaluatedValue} [{UnevaluatedValue}]")]
    public abstract class ProjectProperty : IKeyed, IValued, IProperty, IEquatable<ProjectProperty>
    {
        /// <summary>
        /// Project that this property lives in.
        /// ProjectProperty's always live in a project.
        /// Used to evaluate any updates.
        /// </summary>
        private readonly Project _project;

        /// <summary>
        /// Evaluated value of the property.  Escaped as necessary.
        /// </summary>
        private string _evaluatedValueEscaped;

        internal ProjectProperty(Project project)
        {
            ErrorUtilities.VerifyThrowArgumentNull(project, nameof(project));
            _project = project;
        }

        /// <summary>
        /// Creates a property.
        /// </summary>
        internal ProjectProperty(Project project, string evaluatedValueEscaped)
        {
            ErrorUtilities.VerifyThrowArgumentNull(project, nameof(project));
            ErrorUtilities.VerifyThrowArgumentNull(evaluatedValueEscaped, nameof(evaluatedValueEscaped));

            _project = project;
            _evaluatedValueEscaped = evaluatedValueEscaped;
        }

        internal virtual string EvaluatedValueEscapedInternal => _evaluatedValueEscaped;

        /// <summary>
        /// Name of the property.
        /// Cannot be set.
        /// </summary>
        /// <comment>
        /// If this could be set, it would be necessary to have a callback
        /// so that the containing collections could be updated, as they use the name as
        /// their key.
        /// </comment>
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        public abstract string Name
        {
            [DebuggerStepThrough]
            get;
        }

        /// <summary>
        /// Gets the evaluated property value.
        /// Cannot be set directly: only the unevaluated value can be set.
        /// Is never null.
        /// </summary>
        /// <remarks>
        /// Unescaped value of the evaluated property
        /// </remarks>
        public string EvaluatedValue
        {
            [DebuggerStepThrough]
            get
            { return EscapingUtilities.UnescapeAll(EvaluatedValueEscapedInternal); }
        }

        /// <summary>
        /// Gets the evaluated property value.
        /// Cannot be set directly: only the unevaluated value can be set.
        /// Is never null.
        /// </summary>
        /// <remarks>
        /// Evaluated property escaped as necessary
        /// </remarks>
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        string IProperty.EvaluatedValueEscaped
        {
            [DebuggerStepThrough]
            get => EvaluatedValueEscapedInternal;
        }

        /// <summary>
        /// Gets or sets the unevaluated property value.
        /// Updates the evaluated value in the project, although this is not sure to be correct until re-evaluation.
        /// </summary>
        public abstract string UnevaluatedValue
        {
            [DebuggerStepThrough]
            get;
            set;
        }

        /// <summary>
        /// Whether the property originated from the environment (or the toolset)
        /// </summary>
        public abstract bool IsEnvironmentProperty
        {
            [DebuggerStepThrough]
            get;
        }

        /// <summary>
        /// Whether the property is a global property
        /// </summary>
        public abstract bool IsGlobalProperty
        {
            [DebuggerStepThrough]
            get;
        }

        /// <summary>
        /// Whether the property is a reserved property,
        /// like 'MSBuildProjectFile'.
        /// </summary>
        public abstract bool IsReservedProperty
        {
            [DebuggerStepThrough]
            get;
        }

        /// <summary>
        /// Backing XML property.
        /// Null only if this is a global, environment, or built-in property.
        /// </summary>
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        public abstract ProjectPropertyElement Xml
        {
            [DebuggerStepThrough]
            get;
        }

        /// <summary>
        /// Project that this property lives in.
        /// ProjectProperty's always live in a project.
        /// </summary>
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        public Project Project
        {
            [DebuggerStepThrough]
            get
            { return _project; }
        }

        /// <summary>
        /// Any immediately previous property that was overridden by this one during evaluation.
        /// This would include all properties with the same name that lie above in the logical
        /// project file, and whose conditions evaluated to true.
        /// If there are none above this is null.
        /// If the project has not been reevaluated since the last modification this value may be incorrect.
        /// </summary>
        public abstract ProjectProperty Predecessor
        {
            [DebuggerStepThrough]
            get;
        }

        /// <summary>
        /// If the property originated in an imported file, returns true.
        /// If the property originates from the environment, a global property, or is a built-in property, returns false.
        /// Otherwise returns false.
        /// </summary>
        public abstract bool IsImported
        {
            get;
        }

        /// <summary>
        /// Implementation of IKeyed exposing the property name, so properties
        /// can be put in a dictionary conveniently.
        /// </summary>
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        string IKeyed.Key
        {
            [DebuggerStepThrough]
            get
            { return Name; }
        }

        /// <summary>
        /// Implementation of IValued
        /// </summary>
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        string IValued.EscapedValue
        {
            [DebuggerStepThrough]
            get => EvaluatedValueEscapedInternal;
        }

        #region IEquatable<ProjectProperty> Members

        /// <summary>
        /// Compares this property to another for equivalence.
        /// </summary>
        /// <param name="other">The other property.</param>
        /// <returns>True if the properties are equivalent, false otherwise.</returns>
        bool IEquatable<ProjectProperty>.Equals(ProjectProperty other)
        {
            if (Object.ReferenceEquals(this, other))
            {
                return true;
            }

            if (other == null)
            {
                return false;
            }

            return _project == other._project &&
                   Xml == other.Xml &&
                   EvaluatedValueEscapedInternal == other.EvaluatedValueEscapedInternal &&
                   Name == other.Name;
        }

        #endregion

        /// <summary>
        /// Creates a property without backing XML.
        /// Property MAY BE global, and property MAY HAVE a reserved name (such as "MSBuildProjectDirectory") if indicated.
        /// This is ONLY to be used by the Evaluator (and Project.SetGlobalProperty) and ONLY for Global, Environment, and Built-in properties.
        /// All other properties originate in XML, and should have a backing XML object.
        /// </summary>
        internal static ProjectProperty Create(Project project, string name, string evaluatedValueEscaped, bool isGlobalProperty, bool mayBeReserved)
        {
            return new ProjectPropertyNotXmlBacked(project, name, evaluatedValueEscaped, isGlobalProperty, mayBeReserved);
        }

        /// <summary>
        /// Creates a regular evaluated property, with backing XML.
        /// Called by Project.SetProperty.
        /// Property MAY NOT have reserved name and MAY NOT overwrite a global property.
        /// Predecessor is any immediately previous property that was overridden by this one during evaluation and may be null.
        /// </summary>
        internal static ProjectProperty Create(Project project, ProjectPropertyElement xml, string evaluatedValueEscaped, ProjectProperty predecessor)
        {
            if (predecessor == null)
            {
                return new ProjectPropertyXmlBacked(project, xml, evaluatedValueEscaped);
            }
            else
            {
                return new ProjectPropertyXmlBackedWithPredecessor(project, xml, evaluatedValueEscaped, predecessor);
            }
        }

        /// <summary>
        /// Called ONLY by the project in order to update the evaluated value
        /// after a property set occurring between full evaluations.
        /// </summary>
        /// <remarks>
        /// Method instead of a setter on EvaluatedValue to try to make clear its limited purpose.
        /// </remarks>
        internal void UpdateEvaluatedValue(string evaluatedValueEscaped)
        {
            _evaluatedValueEscaped = evaluatedValueEscaped;
        }

        /// <summary>
        /// Looks for a matching global property.
        /// </summary>
        /// <remarks>
        /// The reason we do this and not just look at project.GlobalProperties is
        /// that when the project is being loaded, the GlobalProperties collection is already populated.  When we do our
        /// evaluation, we may attempt to add some properties, such as environment variables, to the master Properties
        /// collection.  As GlobalProperties are supposed to override these and thus be added last, we can't check against
        /// the GlobalProperties collection as they are being added.  The correct behavior is to always check against the
        /// collection which is accumulating properties as we go, which is the Properties collection.  Once the project has
        /// been fully populated, this method will also ensure that further properties do not attempt to override global
        /// properties, as those will have the global property flag set.
        /// </remarks>
        /// <param name="project">The project to compare with.</param>
        /// <param name="propertyName">The property name to look up</param>
        /// <returns>True if there is a matching global property, false otherwise.</returns>
        private static bool ProjectHasMatchingGlobalProperty(Project project, string propertyName)
        {
            ProjectProperty property = project.GetProperty(propertyName);
            if (property?.IsGlobalProperty == true && !project.GlobalPropertiesToTreatAsLocal.Contains(propertyName))
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Regular property, originating in an XML node, but with no predecessor (property with same name that it overrode during evaluation)
        /// </summary>
        private class ProjectPropertyXmlBacked : ProjectProperty
        {
            /// <summary>
            /// Backing XML property.
            /// Never null.
            /// </summary>
            private readonly ProjectPropertyElement _xml;

            /// <summary>
            /// Creates a regular evaluated property, with backing XML.
            /// Called by Project.SetProperty.
            /// Property MAY NOT have reserved name and MAY NOT overwrite a global property.
            /// Predecessor is any immediately previous property that was overridden by this one during evaluation and may be null.
            /// </summary>
            internal ProjectPropertyXmlBacked(Project project, ProjectPropertyElement xml, string evaluatedValueEscaped)
                : base(project, evaluatedValueEscaped)
            {
                ErrorUtilities.VerifyThrowArgumentNull(xml, nameof(xml));
                ErrorUtilities.VerifyThrowInvalidOperation(!ProjectHasMatchingGlobalProperty(project, xml.Name), "OM_GlobalProperty", xml.Name);

                _xml = xml;
            }

            /// <summary>
            /// Name of the property.
            /// Cannot be set.
            /// </summary>
            /// <comment>
            /// If this could be set, it would be necessary to have a callback
            /// so that the containing collections could be updated, as they use the name as
            /// their key.
            /// </comment>
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            public override string Name
            {
                [DebuggerStepThrough]
                get
                { return _xml.Name; }
            }

            /// <summary>
            /// Gets or sets the unevaluated property value.
            /// Updates the evaluated value in the project, although this is not sure to be correct until re-evaluation.
            /// </summary>
            /// <remarks>
            /// The containing project will be dirtied by the XML modification.
            /// If there is no XML backing, the evaluated value returned is the value of the property that has been
            /// escaped as necessary.
            /// </remarks>
            public override string UnevaluatedValue
            {
                [DebuggerStepThrough]
                get
                {
                    return _xml.Value;
                }

                set
                {
                    Project.VerifyThrowInvalidOperationNotImported(_xml.ContainingProject);
                    ErrorUtilities.VerifyThrowInvalidOperation(_xml.Parent?.Parent != null, "OM_ObjectIsNoLongerActive");

                    _xml.Value = value;

                    _evaluatedValueEscaped = _project.ExpandPropertyValueBestEffortLeaveEscaped(value, _xml.Location);
                }
            }

            /// <summary>
            /// Whether the property originated from the environment (or the toolset)
            /// </summary>
            public override bool IsEnvironmentProperty
            {
                [DebuggerStepThrough]
                get
                { return false; }
            }

            /// <summary>
            /// Whether the property is a global property
            /// </summary>
            public override bool IsGlobalProperty
            {
                [DebuggerStepThrough]
                get
                { return false; }
            }

            /// <summary>
            /// Whether the property is a reserved property,
            /// like 'MSBuildProjectFile'.
            /// </summary>
            public override bool IsReservedProperty
            {
                [DebuggerStepThrough]
                get
                { return false; }
            }

            /// <summary>
            /// Backing XML property.
            /// </summary>
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            public override ProjectPropertyElement Xml
            {
                [DebuggerStepThrough]
                get
                { return _xml; }
            }

            /// <summary>
            /// Any immediately previous property that was overridden by this one during evaluation.
            /// This would include all properties with the same name that lie above in the logical
            /// project file, and whose conditions evaluated to true.
            /// In this class this is null.
            /// If the project has not been reevaluated since the last modification this value may be incorrect.
            /// </summary>
            public override ProjectProperty Predecessor
            {
                [DebuggerStepThrough]
                get
                { return null; }
            }

            /// <summary>
            /// If the property originated in an imported file, returns true.
            /// Otherwise returns false.
            /// </summary>
            public override bool IsImported
            {
                get
                {
                    bool isImported = !Object.ReferenceEquals(_xml.ContainingProject, _project.Xml);

                    return isImported;
                }
            }
        }

        /// <summary>
        /// Regular property, originating in an XML node, and with a predecessor (property with same name that was overridden during evaluation)
        /// </summary>
        private class ProjectPropertyXmlBackedWithPredecessor : ProjectPropertyXmlBacked
        {
            /// <summary>
            /// Any immediately previous property that was overridden by this one during evaluation.
            /// This would include all properties with the same name that lie above in the logical
            /// project file, and whose conditions evaluated to true.
            /// If there are none above this is null.
            /// If the project has not been reevaluated since the last modification this value may be incorrect.
            /// </summary>
            private ProjectProperty _predecessor;

            /// <summary>
            /// Creates a regular evaluated property, with backing XML.
            /// Called by Project.SetProperty.
            /// Property MAY NOT have reserved name and MAY NOT overwrite a global property.
            /// Predecessor is any immediately previous property that was overridden by this one during evaluation and may be null.
            /// </summary>
            internal ProjectPropertyXmlBackedWithPredecessor(Project project, ProjectPropertyElement xml, string evaluatedValueEscaped, ProjectProperty predecessor)
                : base(project, xml, evaluatedValueEscaped)
            {
                ErrorUtilities.VerifyThrowArgumentNull(predecessor, nameof(predecessor));

                _predecessor = predecessor;
            }

            /// <summary>
            /// Any immediately previous property that was overridden by this one during evaluation.
            /// This would include all properties with the same name that lie above in the logical
            /// project file, and whose conditions evaluated to true.
            /// If there are none above this is null.
            /// If the project has not been reevaluated since the last modification this value may be incorrect.
            /// </summary>
            public override ProjectProperty Predecessor
            {
                [DebuggerStepThrough]
                get
                { return _predecessor; }
            }
        }

        /// <summary>
        /// Global/environment/toolset properties are the minority;
        /// they don't originate with XML, so we must store their name (instead)
        /// </summary>
        private class ProjectPropertyNotXmlBacked : ProjectProperty
        {
            /// <summary>
            /// Name of the property.
            /// </summary>
            private readonly string _name;

            /// <summary>
            /// Creates a property without backing XML.
            /// Property MAY BE global, and property MAY HAVE a reserved name (such as "MSBuildProjectDirectory") if indicated.
            /// This is ONLY to be used by the Evaluator (and Project.SetGlobalProperty) and ONLY for Global, Environment, and Built-in properties.
            /// All other properties originate in XML, and should have a backing XML object.
            /// </summary>
            internal ProjectPropertyNotXmlBacked(Project project, string name, string evaluatedValueEscaped, bool isGlobalProperty, bool mayBeReserved)
                : base(project, evaluatedValueEscaped)
            {
                ErrorUtilities.VerifyThrowArgumentLength(name, nameof(name));
                ErrorUtilities.VerifyThrowInvalidOperation(isGlobalProperty || !ProjectHasMatchingGlobalProperty(project, name), "OM_GlobalProperty", name);
                ErrorUtilities.VerifyThrowArgument(!XMakeElements.ReservedItemNames.Contains(name), "OM_ReservedName", name);
                ErrorUtilities.VerifyThrowArgument(mayBeReserved || !ReservedPropertyNames.IsReservedProperty(name), "OM_ReservedName", name);

                _name = name;
            }

            /// <summary>
            /// Name of the property.
            /// Cannot be set.
            /// </summary>
            /// <comment>
            /// If this could be set, it would be necessary to have a callback
            /// so that the containing collections could be updated, as they use the name as
            /// their key.
            /// </comment>
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            public override string Name
            {
                [DebuggerStepThrough]
                get
                { return _name; }
            }

            /// <summary>
            /// Gets or sets the unevaluated property value.
            /// Updates the evaluated value in the project, although this is not sure to be correct until re-evaluation.
            /// </summary>
            /// <remarks>
            /// The containing project will be dirtied.
            /// As there is no XML backing, the evaluated value returned is the value of the property that has been
            /// escaped as necessary.
            /// </remarks>
            public override string UnevaluatedValue
            {
                [DebuggerStepThrough]
                get
                {
                    return ((IProperty)this).EvaluatedValueEscaped;
                }

                set
                {
                    ErrorUtilities.VerifyThrowInvalidOperation(!IsReservedProperty, "OM_ReservedName", _name);
                    ErrorUtilities.VerifyThrowInvalidOperation(!IsGlobalProperty, "OM_GlobalProperty", _name);

                    if (IsEnvironmentProperty)
                    {
                        // Although this is an environment property, the user wants it
                        // to be persisted. So as well as updating this object,
                        // tell the project to add a real persisted property to match.
                        _evaluatedValueEscaped = value;

                        _project.Xml.AddProperty(_name, value);

                        return;
                    }

                    ErrorUtilities.ThrowInternalErrorUnreachable();
                }
            }

            /// <summary>
            /// Whether the property originated from the environment (or the toolset)
            /// </summary>
            public override bool IsEnvironmentProperty
            {
                get { return !IsGlobalProperty && !IsReservedProperty; }
            }

            /// <summary>
            /// Whether the property is a global property
            /// </summary>
            public override bool IsGlobalProperty
            {
                [DebuggerStepThrough]
                get
                { return _project.GlobalProperties.ContainsKey(Name); }
            }

            /// <summary>
            /// Whether the property is a reserved property,
            /// like 'MSBuildProjectFile'.
            /// </summary>
            public override bool IsReservedProperty
            {
                [DebuggerStepThrough]
                get
                { return ReservedPropertyNames.IsReservedProperty(Name); }
            }

            /// <summary>
            /// Backing XML property.
            /// Null because this is a global, environment, or built-in property.
            /// </summary>
            [DebuggerBrowsable(DebuggerBrowsableState.Never)]
            public override ProjectPropertyElement Xml
            {
                [DebuggerStepThrough]
                get
                { return null; }
            }

            /// <summary>
            /// Any immediately previous property that was overridden by this one during evaluation.
            /// Because these properties are not backed by XML, they cannot have precedessors.
            /// </summary>
            public override ProjectProperty Predecessor
            {
                [DebuggerStepThrough]
                get
                { return null; }
            }

            /// <summary>
            /// Whether the property originated in an imported file.
            /// Because these properties did not originate in an XML file, this always returns null.
            /// </summary>
            public override bool IsImported
            {
                get { return false; }
            }
        }
    }
}


<|start_filename|>src/Shared/AssemblyLoadInfo.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.IO;
using Microsoft.Build.BackEnd;
using System.Diagnostics;

namespace Microsoft.Build.Shared
{
    /// <summary>
    /// This class packages information about how to load a given assembly -- an assembly can be loaded by either its assembly
    /// name (strong or weak), or its filename/path.
    /// </summary>
    /// <remarks>
    /// Uses factory to instantiate correct private class to save space: only one field is ever used of the two.
    /// </remarks>
    internal abstract class AssemblyLoadInfo : ITranslatable, IEquatable<AssemblyLoadInfo>
    {
        /// <summary>
        /// This constructor initializes the assembly information.
        /// </summary>
        internal static AssemblyLoadInfo Create(string assemblyName, string assemblyFile)
        {
            ErrorUtilities.VerifyThrow((!string.IsNullOrEmpty(assemblyName)) || (!string.IsNullOrEmpty(assemblyFile)),
                "We must have either the assembly name or the assembly file/path.");
            ErrorUtilities.VerifyThrow((assemblyName == null) || (assemblyFile == null),
                "We must not have both the assembly name and the assembly file/path.");

            if (assemblyName != null)
            {
                return new AssemblyLoadInfoWithName(assemblyName);
            }
            else
            {
                return new AssemblyLoadInfoWithFile(assemblyFile);
            }
        }

        /// <summary>
        /// Gets the assembly's identity denoted by its strong/weak name.
        /// </summary>
        public abstract string AssemblyName
        {
            get;
        }

        /// <summary>
        /// Gets the path to the assembly file.
        /// </summary>
        public abstract string AssemblyFile
        {
            get;
        }

        /// <summary>
        /// Get the assembly location
        /// </summary>
        internal abstract string AssemblyLocation
        {
            get;
        }

        /// <summary>
        /// Computes a hashcode for this assembly info, so this object can be used as a key into
        /// a hash table.
        /// </summary>
        public override int GetHashCode()
        {
            return AssemblyLocation.GetHashCode();
        }

        public bool Equals(AssemblyLoadInfo other)
        {
            return Equals((object)other);
        }

        /// <summary>
        /// Determines if two AssemblyLoadInfos are effectively the same.
        /// </summary>
        public override bool Equals(Object obj)
        {
            if (obj == null)
            {
                return false;
            }

            AssemblyLoadInfo otherAssemblyInfo = obj as AssemblyLoadInfo;

            if (otherAssemblyInfo == null)
            {
                return false;
            }

            return (this.AssemblyName == otherAssemblyInfo.AssemblyName) && (this.AssemblyFile == otherAssemblyInfo.AssemblyFile);
        }

        public void Translate(ITranslator translator)
        {
            ErrorUtilities.VerifyThrow(translator.Mode == TranslationDirection.WriteToStream, "write only");
            string assemblyName = AssemblyName;
            string assemblyFile = AssemblyFile;
            translator.Translate(ref assemblyName);
            translator.Translate(ref assemblyFile);
        }

        static public AssemblyLoadInfo FactoryForTranslation(ITranslator translator)
        {
            string assemblyName = null;
            string assemblyFile = null;
            translator.Translate(ref assemblyName);
            translator.Translate(ref assemblyFile);

            return Create(assemblyName, assemblyFile);
        }

        /// <summary>
        /// Assembly represented by name
        /// </summary>
        [DebuggerDisplay("{AssemblyName}")]
        private sealed class AssemblyLoadInfoWithName : AssemblyLoadInfo
        {
            /// <summary>
            /// Assembly name
            /// </summary>
            private string _assemblyName;

            /// <summary>
            /// Constructor
            /// </summary>
            internal AssemblyLoadInfoWithName(string assemblyName)
            {
                _assemblyName = assemblyName;
            }

            /// <summary>
            /// Gets the assembly's identity denoted by its strong/weak name.
            /// </summary>
            public override string AssemblyName
            {
                get { return _assemblyName; }
            }

            /// <summary>
            /// Gets the path to the assembly file.
            /// </summary>
            public override string AssemblyFile
            {
                get { return null; }
            }

            /// <summary>
            /// Get the assembly location
            /// </summary>
            internal override string AssemblyLocation
            {
                get { return _assemblyName; }
            }
        }

        /// <summary>
        /// Assembly info that uses a file path
        /// </summary>
        [DebuggerDisplay("{AssemblyFile}")]
        private sealed class AssemblyLoadInfoWithFile : AssemblyLoadInfo
        {
            /// <summary>
            /// Path to assembly
            /// </summary>
            private string _assemblyFile;

            /// <summary>
            /// Constructor
            /// </summary>
            internal AssemblyLoadInfoWithFile(string assemblyFile)
            {
                ErrorUtilities.VerifyThrow(Path.IsPathRooted(assemblyFile), "Assembly file path should be rooted");

                _assemblyFile = assemblyFile;
            }

            /// <summary>
            /// Gets the assembly's identity denoted by its strong/weak name.
            /// </summary>
            public override string AssemblyName
            {
                get { return null; }
            }

            /// <summary>
            /// Gets the path to the assembly file.
            /// </summary>
            public override string AssemblyFile
            {
                get { return _assemblyFile; }
            }

            /// <summary>
            /// Get the assembly location
            /// </summary>
            internal override string AssemblyLocation
            {
                get { return _assemblyFile; }
            }
        }
    }
}


<|start_filename|>src/Tasks/AssemblyDependency/GacResolver.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using Microsoft.Build.Shared;

namespace Microsoft.Build.Tasks
{
    /// <summary>
    /// Resolve searchpath type {GAC}
    /// </summary>
    internal class GacResolver : Resolver
    {
        /// <summary>
        /// Delegate to get the assembly path in the GAC
        /// </summary>
        private readonly GetAssemblyPathInGac _getAssemblyPathInGac;

        /// <summary>
        /// Construct.
        /// </summary>
        /// <param name="targetProcessorArchitecture">Like x86 or IA64\AMD64, the processor architecture being targeted.</param>
        /// <param name="searchPathElement">The search path element.</param>
        /// <param name="getAssemblyName">Delegate to get the assembly name object.</param>
        /// <param name="fileExists">Delegate to check if the file exists.</param>
        /// <param name="getRuntimeVersion">Delegate to get the runtime version.</param>
        /// <param name="targetedRuntimeVesion">The targeted runtime version.</param>
        /// <param name="getAssemblyPathInGac">Delegate to get assembly path in the GAC.</param>
        public GacResolver(System.Reflection.ProcessorArchitecture targetProcessorArchitecture, string searchPathElement, GetAssemblyName getAssemblyName, FileExists fileExists, GetAssemblyRuntimeVersion getRuntimeVersion, Version targetedRuntimeVesion, GetAssemblyPathInGac getAssemblyPathInGac)
            : base(searchPathElement, getAssemblyName, fileExists, getRuntimeVersion, targetedRuntimeVesion, targetProcessorArchitecture, true)
        {
            _getAssemblyPathInGac = getAssemblyPathInGac;
        }

        /// <summary>
        /// Resolve a reference to a specific file name.
        /// </summary>
        /// <param name="assemblyName">The assembly name object of the assembly.</param>
        /// <param name="sdkName"></param>
        /// <param name="rawFileNameCandidate">The reference's 'include' treated as a raw file name.</param>
        /// <param name="isPrimaryProjectReference">Whether or not this reference was directly from the project file (and therefore not a dependency)</param>
        /// <param name="wantSpecificVersion">Whether an exact version match is requested.</param>
        /// <param name="executableExtensions">Allowed executable extensions.</param>
        /// <param name="hintPath">The item's hintpath value.</param>
        /// <param name="assemblyFolderKey">Like "hklm\Vendor RegKey" as provided to a reference by the &lt;AssemblyFolderKey&gt; on the reference in the project.</param>
        /// <param name="assembliesConsideredAndRejected">Receives the list of locations that this function tried to find the assembly. May be "null".</param>
        /// <param name="foundPath">The path where the file was found.</param>
        /// <param name="userRequestedSpecificFile">Whether or not the user wanted a specific file (for example, HintPath is a request for a specific file)</param>
        /// <returns>True if the file was resolved.</returns>
        public override bool Resolve
        (
            AssemblyNameExtension assemblyName,
            string sdkName,
            string rawFileNameCandidate,
            bool isPrimaryProjectReference,
            bool wantSpecificVersion,
            string[] executableExtensions,
            string hintPath,
            string assemblyFolderKey,
            List<ResolutionSearchLocation> assembliesConsideredAndRejected,
            out string foundPath,
            out bool userRequestedSpecificFile
        )
        {
            foundPath = null;
            userRequestedSpecificFile = false;

            if (assemblyName != null)
            {
                // {GAC} was passed in.
                string gacResolved = _getAssemblyPathInGac(assemblyName, targetProcessorArchitecture, getRuntimeVersion,
                    targetedRuntimeVersion, fileExists, fullFusionName: false, specificVersion: wantSpecificVersion);

                if (!string.IsNullOrEmpty(gacResolved) && fileExists(gacResolved))
                {
                    foundPath = gacResolved;
                    return true;
                }
                else
                {
                    // Record this as a location that was considered.
                    if (assembliesConsideredAndRejected != null)
                    {
                        var considered = new ResolutionSearchLocation
                        {
                            FileNameAttempted = assemblyName.FullName,
                            SearchPath = searchPathElement,
                            AssemblyName = assemblyName,
                            Reason = NoMatchReason.NotInGac
                        };
                        assembliesConsideredAndRejected.Add(considered);
                    }
                }
            }

            return false;
        }
    }
}


<|start_filename|>src/Samples/TaskUsageLogger/TaskUsageLogger.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Reflection;

using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace TaskUsageLogger
{
    /// <summary>
    /// Sample logger used to gather a CSV-formatted list of all tasks run in the build,
    /// associated by Target, project, targets file they're defined in, and assembly the
    /// task comes from.
    ///
    /// Usage:
    ///   /logger:TaskUsageLogger,[path to TaskUsageLogger.dll];[output csv filename]
    /// </summary>
    /// <remarks>
    /// KNOWN ISSUES:
    /// - Because the task location scraping doesn't currently take into account conditions,
    ///   if a task is defined by more than one UsingTask, even if the conditions are mutually
    ///   exclusive, the logger will pick and return the first one.  In practice, this means that
    ///   most default tasks are incorrectly recorded as coming from Microsoft.Build.Tasks.v4.0.dll,
    ///   but since most other task definitions do not contain multiple mutually exclusive
    ///   conditions, they are in general correct.
    /// - Does not keep track of override tasks, so any overridden task will likewise also be incorrectly
    ///   reported.
    /// - Because MSBuild's property expansion functionality is not publicly exposed, this contains
    ///   a very hacky simplified version sufficient to cover most patterns actually seen in UsingTask
    ///   definitions, but is not guaranteed correct in all cases.
    /// - Keeps everything in memory, so would probably run into issues if run against very large
    ///   builds.
    /// </remarks>
    public class TaskUsageLogger : Logger
    {
        private static readonly Regex s_msbuildPropertyRegex = new Regex(@"[\$][\(](?<name>.*?)[\)]", RegexOptions.ExplicitCapture);
        private static readonly char[] s_semicolonChar = { ';' };
        private static readonly char[] s_disallowedCharactersForExpansion = new char[] { '@', '%' };
        private static readonly char[] s_fullyQualifiedTaskNameSeperators = new char[] { '.', '+' };

        private Dictionary<int, string> _targetIdsToNames;
        private HashSet<TaskData> _tasks;
        private string _logFile;
        private ProjectCollection _privateCollection;
        private Dictionary<int, string> _toolsVersionsByProjectContextId;
        private Dictionary<string, HashSet<UsingTaskData>> _defaultTasksByToolset;
        private Dictionary<int, HashSet<UsingTaskData>> _tasksByProjectContextId;
        private Dictionary<string, string> _assemblyLocationsByName;

        /// <summary>
        /// Sets logger up, including registering for logging events
        /// </summary>
        public override void Initialize(IEventSource eventSource)
        {
            ProcessParameters();

            eventSource.ProjectStarted += HandleProjectStarted;
            eventSource.TargetStarted += HandleTargetStarted;
            eventSource.TaskStarted += HandleTaskStarted;
            eventSource.BuildFinished += HandleBuildFinished;

            _targetIdsToNames = new Dictionary<int, string>();
            _tasks = new HashSet<TaskData>();
            _privateCollection = new ProjectCollection();
            _toolsVersionsByProjectContextId = new Dictionary<int, string>();
            _defaultTasksByToolset = new Dictionary<string, HashSet<UsingTaskData>>();
            _tasksByProjectContextId = new Dictionary<int, HashSet<UsingTaskData>>();
            _assemblyLocationsByName = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        }

        /// <summary>
        /// Validate the logger parameters.  Should only be one: the path to the output csv file.
        /// </summary>
        private void ProcessParameters()
        {
            if (Parameters == null)
            {
            }

            string[] parameters = Parameters.Split(s_semicolonChar);

            if (parameters.Length != 1)
            {
                throw new LoggerException(@"Path to write CSV to required.  Specify using the following pattern: '/logger:TaskUsageLogger,D:\Repos\msbuild\bin\Windows_NT\Debug\TaskUsageLogger.dll;mylog.csv");
            }

            _logFile = parameters[0];
        }

        /// <summary>
        /// Each time we encounter a new project, we want to load it, and grab the task registration information:
        /// - For the default tasks for its ToolsVersion
        /// - For any tasks registered in the project file or its imports
        /// </summary>
        private void HandleProjectStarted(object sender, ProjectStartedEventArgs e)
        {
            if (!ShouldIgnoreProject(e.ProjectFile))
            {
                try
                {
                    // Load up a private copy of the project.
                    Project p = _privateCollection.LoadProject(e.ProjectFile, e.GlobalProperties, e.ToolsVersion);

                    // Save off task registration information for this project
                    GatherAndEvaluateDefaultTasksForToolsVersion(p.ToolsVersion, p);
                    GatherAndEvaluateTasksForProject(p, e.BuildEventContext.ProjectContextId);

                    // Keep a pointer to the ToolsVersion so that we'll be able to reference it
                    // later.  Index off ContextId since it appears to be globally unique within
                    // the build.
                    _toolsVersionsByProjectContextId[e.BuildEventContext.ProjectContextId] = p.ToolsVersion;

                    // unload now that we're done with it.
                    _privateCollection.UnloadProject(p);
                }
                catch (Exception ex)
                {
                    throw new LoggerException(String.Format(CultureInfo.CurrentCulture, "Failed to load and read task registration information from project '{0}'. {1}", e.ProjectFile, ex.Message));
                }
            }
        }

        /// <summary>
        /// Write out the CSV file based on the gathered task information.
        /// </summary>
        private void HandleBuildFinished(object sender, BuildFinishedEventArgs e)
        {
            using (StreamWriter sw = new StreamWriter(_logFile, append: false))
            {
                sw.WriteLine("Task Name, Containing Target, File Path, Project Path, Task Assembly, Task Id");

                foreach (TaskData t in _tasks)
                {
                    sw.WriteLine(t);
                }
            }
        }

        /// <summary>
        /// Save off the target name for later association with tasks
        /// </summary>
        private void HandleTargetStarted(object sender, TargetStartedEventArgs e)
        {
            _targetIdsToNames[e.BuildEventContext.TargetId] = e.TargetName;
        }

        /// <summary>
        /// For each task, save off all the data we care about.  We should already
        /// know or be able to derive everything by this point.
        /// </summary>
        private void HandleTaskStarted(object sender, TaskStartedEventArgs e)
        {
            if (!ShouldIgnoreProject(e.ProjectFile))
            {
                TaskData t = new TaskData
                    (
                        e.TaskName,
                        _targetIdsToNames[e.BuildEventContext.TargetId],
                        e.TaskFile,
                        e.ProjectFile,
                        GetAssemblySpecificationFor(e.TaskName, e.BuildEventContext.ProjectContextId, e.ProjectFile),
                        e.BuildEventContext.TaskId
                    );

                if (!_tasks.Add(t))
                {
                    throw new LoggerException(String.Format(CultureInfo.CurrentCulture, "Why do we have two instances of {0}?", t));
                }
            }
        }

        /// <summary>
        /// For a particular ToolsVersion, gather the list of default task registrations.
        /// </summary>
        private void GatherAndEvaluateDefaultTasksForToolsVersion(string toolsVersion, Project containingProject)
        {
            // Default task registrations are in terms of ToolsVersion, so if we've already seen this
            // ToolsVersion we don't need to redo that work.
            if (!_defaultTasksByToolset.ContainsKey(toolsVersion))
            {
                Toolset t = _privateCollection.GetToolset(toolsVersion);
                if (t == null)
                {
                    throw new LoggerException(String.Format(CultureInfo.CurrentCulture, "Why is toolset '{0}' missing??", toolsVersion));
                }

                // Gather the set of default tasks files.
                // Does NOT currently take into account override tasks.
                string[] defaultTasksFiles = Directory.GetFiles(t.ToolsPath, "*.*tasks", SearchOption.TopDirectoryOnly);

                HashSet<UsingTaskData> usingTasks = new HashSet<UsingTaskData>();
                foreach (string defaultTasksFile in defaultTasksFiles)
                {
                    ProjectRootElement pre = ProjectRootElement.Open(defaultTasksFile);
                    GatherAndEvaluatedTasksInFile(pre, containingProject, usingTasks);
                }

                _defaultTasksByToolset.Add(toolsVersion, usingTasks);
            }
        }

        /// <summary>
        /// Given a particular project, gather all tasks registered in that project or any
        /// of its imported targets files. (In other words, all non-default tasks.)
        /// </summary>
        private void GatherAndEvaluateTasksForProject(Project p, int projectContextId)
        {
            HashSet<UsingTaskData> usingTasks;
            if (!_tasksByProjectContextId.TryGetValue(projectContextId, out usingTasks))
            {
                usingTasks = new HashSet<UsingTaskData>();

                // Tasks in the project file itself
                GatherAndEvaluatedTasksInFile(p.Xml, p, usingTasks);

                // Tasks in each of the imports
                foreach (ResolvedImport import in p.Imports)
                {
                    GatherAndEvaluatedTasksInFile(import.ImportedProject, p, usingTasks);
                }

                _tasksByProjectContextId[projectContextId] = usingTasks;
            }
        }

        /// <summary>
        /// Given a project or targets file (the PRE), and the project context from which it comes, gather
        /// the list of task registrations defined in that file.
        /// </summary>
        /// <remarks>
        /// Does NOT currently take into account conditions on task registrations, so any tasks that are registered
        /// with two or more mutually exclusive conditions may end up associated with the wrong registration.
        /// </remarks>
        private void GatherAndEvaluatedTasksInFile(ProjectRootElement pre, Project containingProject, HashSet<UsingTaskData> usingTasks)
        {
            foreach (ProjectUsingTaskElement usingTask in pre.UsingTasks)
            {
                string evaluatedTaskName = EvaluateIfNecessary(usingTask.TaskName, containingProject);

                // A task registration can define either AssemblyName or AssemblyFile, but not both.
                string evaluatedTaskAssemblyPath;
                if (String.IsNullOrEmpty(usingTask.AssemblyName))
                {
                    evaluatedTaskAssemblyPath = EvaluateIfNecessary(usingTask.AssemblyFile, containingProject);
                    evaluatedTaskAssemblyPath = Path.GetFullPath(evaluatedTaskAssemblyPath);
                }
                else
                {
                    string evaluatedTaskAssemblyName = EvaluateIfNecessary(usingTask.AssemblyName, containingProject);

                    if (!String.IsNullOrEmpty(evaluatedTaskAssemblyName))
                    {
                        if (!_assemblyLocationsByName.TryGetValue(evaluatedTaskAssemblyName, out evaluatedTaskAssemblyPath))
                        {
                            try
                            {
                                // If all we have is an assembly name, try to find the file path so that we can write
                                // that to the CSV instead.
                                AssemblyName name = new AssemblyName(evaluatedTaskAssemblyName);
                                Assembly a = Assembly.Load(name);
                                evaluatedTaskAssemblyPath = a.Location;
                            }
                            catch (Exception)
                            {
                                // But if we can't, it's not critical -- just give them what we have.
                                evaluatedTaskAssemblyPath = evaluatedTaskAssemblyName;
                            }

                            _assemblyLocationsByName[evaluatedTaskAssemblyName] = evaluatedTaskAssemblyPath;
                        }
                    }
                    else
                    {
                        evaluatedTaskAssemblyPath = String.Empty;
                    }
                }

                UsingTaskData taskData = new UsingTaskData(evaluatedTaskName, evaluatedTaskAssemblyPath, pre.FullPath);

                usingTasks.Add(taskData);
            }
        }

        /// <summary>
        /// Extremely simple hacked up version of the MSBuild property expansion logic. Should work for the 90%
        /// case, but is not guaranteed accurate.
        /// </summary>
        private string EvaluateIfNecessary(string unevaluatedString, Project containingProject)
        {
            if (unevaluatedString.IndexOfAny(s_disallowedCharactersForExpansion) != -1)
            {
                throw new LoggerException(String.Format(CultureInfo.CurrentCulture, "This logger doesn't know how to evaluate '{0}'!", unevaluatedString));
            }

            if (unevaluatedString.IndexOf('$') == -1)
            {
                //no evaluation necessary
                return unevaluatedString;
            }

            string evaluatedString = unevaluatedString;
            for (var match = s_msbuildPropertyRegex.Match(unevaluatedString); match.Success; match = match.NextMatch())
            {
                string propertyName = match.Groups["name"].Value.Trim();
                string propertyValue = containingProject.GetPropertyValue(propertyName);

                if (!String.IsNullOrEmpty(propertyName))
                {
                    evaluatedString = evaluatedString.Replace("$(" + propertyName + ")", propertyValue);
                }
            }

            return evaluatedString;
        }

        /// <summary>
        /// Given a task name and its associated project, make a "best guess"
        /// at what assembly the task comes from.
        /// </summary>
        private string GetAssemblySpecificationFor(string taskName, int projectContextId, string projectFile)
        {
            // First let's see if this task is defined in the project anywhere
            HashSet<UsingTaskData> usingTasks = null;
            if (!_tasksByProjectContextId.TryGetValue(projectContextId, out usingTasks))
            {
                throw new LoggerException(String.Format(CultureInfo.CurrentCulture, "Why haven't we collected using task data for {0}?", projectFile));
            }

            // Just grab the first one.  NOT accurate if there are conditioned task registrations
            UsingTaskData matchingData = usingTasks.Where(ut => IsPartialNameMatch(taskName, ut.TaskName)).FirstOrDefault();

            if (matchingData == null)
            {
                // If there isn't a registration for the project, fall back to checking the default tasks for
                // that project's ToolsVersion.
                string parentProjectToolsVersion = null;
                if (!_toolsVersionsByProjectContextId.TryGetValue(projectContextId, out parentProjectToolsVersion))
                {
                    throw new LoggerException(String.Format(CultureInfo.CurrentCulture, "Why don't we have a cached ToolsVersion for {0}?", projectFile));
                }

                HashSet<UsingTaskData> defaultUsingTasks = null;
                if (!_defaultTasksByToolset.TryGetValue(parentProjectToolsVersion, out defaultUsingTasks))
                {
                    throw new LoggerException(String.Format(CultureInfo.CurrentCulture, "Why haven't we collected default using task data for TV {0}?", parentProjectToolsVersion));
                }

                matchingData = defaultUsingTasks.Where(ut => IsPartialNameMatch(taskName, ut.TaskName)).FirstOrDefault();
            }

            if (matchingData == null)
            {
                throw new LoggerException(String.Format(CultureInfo.CurrentCulture, "Why couldn't we find a matching UsingTask for task {0} in project {1}?", taskName, projectFile));
            }

            return matchingData.TaskAssembly;
        }

        /// <summary>
        /// Returns true if the two names "mean" the same thing e.g. "Microsoft.Build.Tasks.AL" vs just "AL".
        /// </summary>
        /// <remarks>
        /// Assumes that name1 is never longer than name2.  Again, a simplified version of MSBuild's actual
        /// fuzzy name resolution logic.
        /// </remarks>
        private static bool IsPartialNameMatch(string name1, string name2)
        {
            // perfect match
            if (String.Equals(name1, name2, StringComparison.OrdinalIgnoreCase))
            {
                return true;
            }

            // fuzzy match
            string[] parts = name2.Split(s_fullyQualifiedTaskNameSeperators);
            if (parts.Length > 1 && String.Equals(name1, parts[parts.Length - 1], StringComparison.OrdinalIgnoreCase))
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Returns 'true' if this is a project we don't want to collect data from.
        ///
        /// Since both the '.sln' and '.metaproj' files are faked up projects used by MSBuild essentially
        /// as plumbing to connect other real projects, they're not very interesting to examine.
        /// </summary>
        /// <param name="projectPath"></param>
        /// <returns></returns>
        private static bool ShouldIgnoreProject(string projectPath)
        {
            string projectExtension = Path.GetExtension(projectPath);

            return String.Equals(projectExtension, ".sln", StringComparison.OrdinalIgnoreCase) ||
                   String.Equals(projectExtension, ".metaproj", StringComparison.OrdinalIgnoreCase);
        }

        /// <summary>
        /// Store data about a particular task invocation
        /// </summary>
        [DebuggerDisplay("{TaskName} {TargetName} {TaskAssembly}")]
        private class TaskData
        {
            public string TaskName;
            public string TargetName;
            public string FilePath;
            public string ProjectPath;
            public string TaskAssembly;
            public int TaskId;

            public TaskData(string taskName, string targetName, string filePath, string projectPath, string taskAssembly, int taskId)
            {
                TaskName = taskName;
                TargetName = targetName;
                FilePath = filePath;
                ProjectPath = projectPath;
                TaskAssembly = taskAssembly;
                TaskId = taskId;
            }

            public override string ToString()
            {
                // CSV format
                return String.Format(CultureInfo.CurrentCulture, "{0}, {1}, {2}, {3}, {4}, {5}", this.TaskName, this.TargetName, this.FilePath, this.ProjectPath, this.TaskAssembly, this.TaskId);
            }
        }

        /// <summary>
        /// Store data about a particular task registration
        /// </summary>
        [DebuggerDisplay("{TaskName} {TaskAssembly} {FilePath}")]
        private class UsingTaskData
        {
            public string TaskName;
            public string TaskAssembly;
            public string FilePath;

            public UsingTaskData(string taskName, string taskAssembly, string filePath)
            {
                TaskName = taskName;
                TaskAssembly = taskAssembly;
                FilePath = filePath;
            }
        }
    }
}


<|start_filename|>src/Build/Construction/ProjectUsingTaskParameterElement.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Diagnostics;
using Microsoft.Build.ObjectModelRemoting;
using Microsoft.Build.Shared;

namespace Microsoft.Build.Construction
{
    /// <summary>
    /// UsingTaskParameterElement class represents the Parameter element in the MSBuild project.
    /// </summary>
    [DebuggerDisplay("Name={Name} ParameterType={ParameterType} Output={Output} Required={Required}")]
    public class ProjectUsingTaskParameterElement : ProjectElement
    {
        ProjectUsingTaskParameterElementLink TaskParameterLink => (ProjectUsingTaskParameterElementLink)Link;
        /// <summary>
        /// External projects support
        /// </summary>
        internal ProjectUsingTaskParameterElement(ProjectUsingTaskParameterElementLink link)
            : base(link)
        {
        }

        /// <summary>
        /// Initialize a parented UsingTaskParameterElement instance
        /// </summary>
        internal ProjectUsingTaskParameterElement(XmlElementWithLocation xmlElement, UsingTaskParameterGroupElement parent, ProjectRootElement containingProject)
            : base(xmlElement, parent, containingProject)
        {
            ErrorUtilities.VerifyThrowArgumentNull(parent, nameof(parent));
        }

        /// <summary>
        /// Initialize an unparented UsingTaskParameterElement instance
        /// </summary>
        private ProjectUsingTaskParameterElement(XmlElementWithLocation xmlElement, ProjectRootElement containingProject)
            : base(xmlElement, null, containingProject)
        {
        }

        /// <summary>
        /// Condition should never be set, but the getter returns null instead of throwing 
        /// because a nonexistent condition is implicitly true
        /// </summary>
        public override string Condition
        {
            get => null;
            set => ErrorUtilities.ThrowInvalidOperation("OM_CannotGetSetCondition");
        }

        /// <summary>
        /// Gets and sets the name of the parameter's name
        /// </summary>
        public string Name
        {
            get => ElementName;

            set
            {
                ErrorUtilities.VerifyThrowArgumentLength(value, nameof(Name));

                if (Link != null) { TaskParameterLink.Name = value; return; }
                // TODO: There seems to be a bug here
                // the Name returns the element name (consistent with XML view aka:)
                // <fooParam .../> => this.Name = fooParan
                // while setter will "set" the "Name" attribute, instead of renaming the XML element aka
                // <fooParam Name="newName".../> instead of (so this.Name still is "fooParam"
                // <newName .../>
                // i have changed the "link" to support either way, should check whether it has to be fix on real object as well.

                XmlElementWithLocation newElement = XmlUtilities.RenameXmlElement(XmlElement, value, XmlElement.NamespaceURI);
                ReplaceElement(newElement);

                 // SetOrRemoveAttribute(XMakeAttributes.name, value, "Set usingtaskparameter {0}", value);
            }
        }

        /// <summary>
        /// Gets or sets the Type attribute returns "System.String" if not set.
        /// If null or empty is set the attribute will be removed from the element.
        /// </summary>
        public string ParameterType
        {
            get
            {
                string typeAttribute = GetAttributeValue(XMakeAttributes.parameterType);
                return String.IsNullOrEmpty(typeAttribute) ? typeof(String).FullName : typeAttribute;
            }

            set
            {
                // If null or empty is passed in remove the attribute from the element
                SetOrRemoveAttribute(XMakeAttributes.parameterType, value, "Set usingtaskparameter ParameterType {0}", value);
            }
        }

        /// <summary>
        /// Gets or sets the output attribute
        /// </summary>
        public string Output
        {
            get
            {
                string outputAttribute = GetAttributeValue(XMakeAttributes.output);
                return String.IsNullOrEmpty(outputAttribute) ? bool.FalseString : outputAttribute;
            }

            set
            {
                SetOrRemoveAttribute(XMakeAttributes.output, value, "Set usingtaskparameter Output {0}", value);
            }
        }

        /// <summary>
        /// Gets or sets the required attribute
        /// </summary>
        public string Required
        {
            get
            {
                string requiredAttribute = GetAttributeValue(XMakeAttributes.required);
                return String.IsNullOrEmpty(requiredAttribute) ? bool.FalseString : requiredAttribute;
            }

            set
            {
                SetOrRemoveAttribute(XMakeAttributes.required, value, "Set usingtaskparameter Required {0}", value);
            }
        }

        /// <summary>
        /// This does not allow conditions, so it should not be called.
        /// </summary>
        public override ElementLocation ConditionLocation
        {
            get
            {
                ErrorUtilities.ThrowInternalError("Should not evaluate this");
                return null;
            }
        }

        /// <summary>
        /// Location of the Type attribute.
        /// If there is no such attribute, returns the location of the element,
        /// in lieu of the default value it uses for the attribute.
        /// </summary>
        public ElementLocation ParameterTypeLocation => GetAttributeLocation(XMakeAttributes.parameterType) ?? Location;

        /// <summary>
        /// Location of the Output attribute.
        /// If there is no such attribute, returns the location of the element,
        /// in lieu of the default value it uses for the attribute.
        /// </summary>
        public ElementLocation OutputLocation => GetAttributeLocation(XMakeAttributes.output) ?? Location;

        /// <summary>
        /// Location of the Required attribute.
        /// If there is no such attribute, returns the location of the element,
        /// in lieu of the default value it uses for the attribute.
        /// </summary>
        public ElementLocation RequiredLocation => GetAttributeLocation(XMakeAttributes.required) ?? Location;

        /// <summary>
        /// Creates an unparented UsingTaskParameterElement, wrapping an unparented XmlElement.
        /// Caller should then ensure the element is added to a parent.
        /// </summary>
        internal static ProjectUsingTaskParameterElement CreateDisconnected(string parameterName, string output, string required, string parameterType, ProjectRootElement containingProject)
        {
            XmlUtilities.VerifyThrowArgumentValidElementName(parameterName);
            XmlElementWithLocation element = containingProject.CreateElement(parameterName);
            var parameter =
                new ProjectUsingTaskParameterElement(element, containingProject)
                {
                    Output = output,
                    Required = required,
                    ParameterType = parameterType
                };

            return parameter;
        }

        /// <summary>
        /// Overridden to verify that the potential parent and siblings
        /// are acceptable. Throws InvalidOperationException if they are not.
        /// </summary>
        internal override void VerifyThrowInvalidOperationAcceptableLocation(ProjectElementContainer parent, ProjectElement previousSibling, ProjectElement nextSibling)
        {
            ErrorUtilities.VerifyThrowInvalidOperation(parent is UsingTaskParameterGroupElement, "OM_CannotAcceptParent");
        }

        /// <inheritdoc />
        protected override ProjectElement CreateNewInstance(ProjectRootElement owner)
        {
            return owner.CreateUsingTaskParameterElement(Name, Output, Required, ParameterType);
        }
    }
}


<|start_filename|>src/Shared/AssemblyNameComparer.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections;
using System.Collections.Generic;

namespace Microsoft.Build.Shared
{
    /// <summary>
    /// IKeyComparer implementation that compares AssemblyNames for using in Hashtables.
    /// </summary>
    [Serializable]
    internal sealed class AssemblyNameComparer : IComparer, IEqualityComparer, IEqualityComparer<AssemblyNameExtension>
    {
        /// <summary>
        /// Comparer for two assembly name extensions
        /// </summary>
        internal static readonly IComparer Comparer = new AssemblyNameComparer(false);

        /// <summary>
        /// Comparer for two assembly name extensions
        /// </summary>
        internal static readonly IComparer ComparerConsiderRetargetable = new AssemblyNameComparer(true);

        /// <summary>
        /// Comparer for two assembly name extensions
        /// </summary>
        internal static readonly IEqualityComparer<AssemblyNameExtension> GenericComparer = Comparer as IEqualityComparer<AssemblyNameExtension>;

        /// <summary>
        /// Comparer for two assembly name extensions
        /// </summary>
        internal static readonly IEqualityComparer<AssemblyNameExtension> GenericComparerConsiderRetargetable = ComparerConsiderRetargetable as IEqualityComparer<AssemblyNameExtension>;

        /// <summary>
        /// Should the comparer consider the retargetable flag when doing comparisons
        /// </summary>
        private readonly bool considerRetargetableFlag;

        /// <summary>
        /// Private construct so there's only one instance.
        /// </summary>
        private AssemblyNameComparer(bool considerRetargetableFlag)
        {
            this.considerRetargetableFlag = considerRetargetableFlag;
        }

        /// <summary>
        /// Compare o1 and o2 as AssemblyNames.
        /// </summary>
        public int Compare(object o1, object o2)
        {
            AssemblyNameExtension a1 = (AssemblyNameExtension)o1;
            AssemblyNameExtension a2 = (AssemblyNameExtension)o2;

            int result = a1.CompareTo(a2, considerRetargetableFlag);
            return result;
        }

        /// <summary>
        /// Treat o1 and o2 as AssemblyNames. Are they equal?
        /// </summary>
        public new bool Equals(object o1, object o2)
        {
            AssemblyNameExtension a1 = (AssemblyNameExtension)o1;
            AssemblyNameExtension a2 = (AssemblyNameExtension)o2;
            return Equals(a1, a2);
        }

        /// <summary>
        /// Get a hashcode for AssemblyName.
        /// </summary>
        public int GetHashCode(object o)
        {
            AssemblyNameExtension a = (AssemblyNameExtension)o;
            return GetHashCode(a);
        }

        #region IEqualityComparer<AssemblyNameExtension> Members

        /// <summary>
        /// Determine if the assembly name extensions are equal
        /// </summary>
        public bool Equals(AssemblyNameExtension x, AssemblyNameExtension y)
        {
            bool result = x.Equals(y, considerRetargetableFlag);
            return result;
        }

        /// <summary>
        /// Get a hashcode for AssemblyName.
        /// </summary>
        public int GetHashCode(AssemblyNameExtension obj)
        {
            int result = obj.GetHashCode();
            return result;
        }

        #endregion
    }
}


<|start_filename|>src/Utilities/TrackedDependencies/TrackedDependencies.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Generic;
using System.IO;

using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using Microsoft.Build.Shared.FileSystem;

namespace Microsoft.Build.Utilities
{
    /// <summary>
    /// This class contains utility functions to assist with tracking dependencies
    /// </summary>
    public static class TrackedDependencies
    {
        #region Methods
        /// <summary>
        /// Expand wildcards in the item list.
        /// </summary>
        /// <param name="expand"></param>
        /// <returns>Array of items expanded</returns>
        public static ITaskItem[] ExpandWildcards(ITaskItem[] expand)
        {
            if (expand == null)
            {
                return null;
            }

            var expanded = new List<ITaskItem>(expand.Length);
            foreach (ITaskItem item in expand)
            {
                if (FileMatcher.HasWildcards(item.ItemSpec))
                {
                    string[] files;
                    string directoryName = Path.GetDirectoryName(item.ItemSpec);
                    string searchPattern = Path.GetFileName(item.ItemSpec);

                    // Very often with TLog files we're talking about
                    // a directory and a simply wildcarded filename
                    // Optimize for that case here.
                    if (!FileMatcher.HasWildcards(directoryName) && FileSystems.Default.DirectoryExists(directoryName))
                    {
                        files = Directory.GetFiles(directoryName, searchPattern);
                    }
                    else
                    {
                        files = FileMatcher.Default.GetFiles(null, item.ItemSpec);
                    }

                    foreach (string file in files)
                    {
                        expanded.Add(new TaskItem(item) { ItemSpec = file });
                    }
                }
                else
                {
                    expanded.Add(item);
                }
            }
            return expanded.ToArray();
        }

        /// <summary>
        /// This method checks that all the files exist
        /// </summary>
        /// <param name="files"></param>
        /// <returns>bool</returns>
        internal static bool ItemsExist(ITaskItem[] files)
        {
            bool allExist = true;

            if (files?.Length > 0)
            {
                foreach (ITaskItem item in files)
                {
                    if (!FileUtilities.FileExistsNoThrow(item.ItemSpec))
                    {
                        allExist = false;
                        break;
                    }
                }
            }
            else
            {
                allExist = false;
            }
            return allExist;
        }
        #endregion
    }
}


<|start_filename|>src/Build.UnitTests/Definition/ItemDefinitionGroup_Tests.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using System.Xml;
using Microsoft.Build.Execution;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;

using TaskItem = Microsoft.Build.Execution.ProjectItemInstance.TaskItem;
using InvalidProjectFileException = Microsoft.Build.Exceptions.InvalidProjectFileException;
using Xunit;

namespace Microsoft.Build.UnitTests.Definition
{
    /// <summary>
    /// Class containing tests for the ProjectItemDefinition and related functionality.
    /// </summary>
    public class ItemDefinitionGroup_Tests
    {
        /// <summary>
        /// Test for item definition group definitions showing up in project.
        /// </summary>
        [Fact]
        public void ItemDefinitionGroupExistsInProject()
        {
            Project p = new Project(XmlReader.Create(new StringReader(
            @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    <ItemDefinitionGroup>
                        <Compile>
                            <First>1st</First>
                            <Second>2nd</Second>
                        </Compile>
                    </ItemDefinitionGroup>
	                <Target Name='Build' />
	            </Project>")));

            Assert.True(ContainsMetadata(p.ItemDefinitions["Compile"].Metadata, "First", "1st"));
            Assert.True(ContainsMetadata(p.ItemDefinitions["Compile"].Metadata, "Second", "2nd"));
        }

        /// <summary>
        /// Test for multiple item definition group definitions showing up in project.
        /// </summary>
        [Fact]
        public void MultipleItemDefinitionGroupExistsInProject()
        {
            Project p = new Project(XmlReader.Create(new StringReader(
            @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    <ItemDefinitionGroup>
                        <Compile>
                            <First>1st</First>
                            <Second>2nd</Second>
                        </Compile>
                    </ItemDefinitionGroup>
                    <ItemDefinitionGroup>
                        <Link>
                            <Third>3rd</Third>
                            <Fourth>4th</Fourth>
                        </Link>
                    </ItemDefinitionGroup>
	                <Target Name='Build' />
	            </Project>")));

            Assert.True(ContainsMetadata(p.ItemDefinitions["Compile"].Metadata, "First", "1st"));
            Assert.True(ContainsMetadata(p.ItemDefinitions["Compile"].Metadata, "Second", "2nd"));
            Assert.True(ContainsMetadata(p.ItemDefinitions["Link"].Metadata, "Third", "3rd"));
            Assert.True(ContainsMetadata(p.ItemDefinitions["Link"].Metadata, "Fourth", "4th"));
        }

        /// <summary>
        /// Tests that items with no metadata inherit from item definition groups
        /// </summary>
        [Fact]
        public void EmptyItemsInheritValues()
        {
            Project p = new Project(XmlReader.Create(new StringReader(
            @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    <ItemDefinitionGroup>
                        <Compile>
                            <First>1st</First>
                            <Second>2nd</Second>
                        </Compile>
                    </ItemDefinitionGroup>
                    <ItemDefinitionGroup>
                        <Link>
                            <Third>3rd</Third>
                            <Fourth>4th</Fourth>
                        </Link>
                    </ItemDefinitionGroup>
                    <ItemGroup>
                        <Compile Include='a.cs;b.cs' />
                    </ItemGroup>
	                <Target Name='Build' />
	            </Project>")));

            Assert.True(ItemContainsMetadata(p, "Compile", "a.cs", "First", "1st"));
            Assert.True(ItemContainsMetadata(p, "Compile", "b.cs", "First", "1st"));
            Assert.True(ItemContainsMetadata(p, "Compile", "a.cs", "Second", "2nd"));
            Assert.True(ItemContainsMetadata(p, "Compile", "b.cs", "Second", "2nd"));
            Assert.False(ItemContainsMetadata(p, "Compile", "a.cs", "Third", "3rd"));
        }

        /// <summary>
        /// Tests that items with metadata override inherited metadata of the same name
        /// </summary>
        [Fact]
        public void ItemMetadataOverridesInheritedValues()
        {
            Project p = new Project(XmlReader.Create(new StringReader(
            @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    <ItemDefinitionGroup>
                        <Compile>
                            <First>1st</First>
                            <Second>2nd</Second>
                        </Compile>
                    </ItemDefinitionGroup>
                    <ItemDefinitionGroup>
                        <Link>
                            <Third>3rd</Third>
                            <Fourth>4th</Fourth>
                        </Link>
                    </ItemDefinitionGroup>
                    <ItemGroup>
                        <Compile Include='a.cs'>
                            <Foo>Bar</Foo>
                            <First>Not1st</First>
                        </Compile>
                        <Compile Include='b.cs'>
                            <Foo>Bar</Foo>
                        </Compile>
                    </ItemGroup>
                    <ItemGroup>
                        <Link Include='a.o'/>
                    </ItemGroup>
	                <Target Name='Build' />
	            </Project>")));

            Assert.True(ItemContainsMetadata(p, "Compile", "a.cs", "First", "Not1st"));
            Assert.True(ItemContainsMetadata(p, "Compile", "a.cs", "Second", "2nd"));
            Assert.True(ItemContainsMetadata(p, "Compile", "b.cs", "First", "1st"));
            Assert.True(ItemContainsMetadata(p, "Compile", "b.cs", "Second", "2nd"));
            Assert.True(ItemContainsMetadata(p, "Link", "a.o", "Third", "3rd"));
            Assert.True(ItemContainsMetadata(p, "Link", "a.o", "Fourth", "4th"));
        }

        /// <summary>
        /// Tests that item definition doesn't allow item expansion for the conditional.
        /// </summary>
        [Fact]
        public void ItemDefinitionDoesntAllowItemExpansion()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                Project p = new Project(XmlReader.Create(new StringReader(
                @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    <ItemGroup>
                        <Compile Include='a.cs'>
                            <Foo>Bar</Foo>
                            <First>Not1st</First>
                        </Compile>
                        <Compile Include='b.cs'>
                            <Foo>Bar</Foo>
                        </Compile>
                    </ItemGroup>
                    <ItemDefinitionGroup>
                        <Compile Condition=""'@(Compile)'!=''"">
                            <First>1st</First>
                            <Second>2nd</Second>
                        </Compile>
                    </ItemDefinitionGroup>
	                <Target Name='Build' />
	            </Project>")));
            }
           );
        }
        /// <summary>
        /// Tests that item definition metadata doesn't allow item expansion for the conditional.
        /// </summary>
        [Fact]
        public void ItemDefinitionMetadataConditionDoesntAllowItemExpansion()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                Project p = new Project(XmlReader.Create(new StringReader(
                @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    <ItemGroup>
                        <Compile Include='a.cs'>
                            <Foo>Bar</Foo>
                            <First>Not1st</First>
                        </Compile>
                        <Compile Include='b.cs'>
                            <Foo>Bar</Foo>
                        </Compile>
                    </ItemGroup>
                    <ItemDefinitionGroup>
                        <Compile>
                            <First  Condition=""'@(Compile)'!=''"">1st</First>
                        </Compile>
                    </ItemDefinitionGroup>
	                <Target Name='Build' />
	            </Project>")));
            }
           );
        }
        /// <summary>
        /// Tests that item definition metadata doesn't allow item expansion for the value.
        /// </summary>
        [Fact]
        public void ItemDefinitionMetadataDoesntAllowItemExpansion()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                Project p = new Project(XmlReader.Create(new StringReader(
                @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    <ItemGroup>
                        <Compile Include='a.cs'>
                            <Foo>Bar</Foo>
                            <First>Not1st</First>
                        </Compile>
                        <Compile Include='b.cs'>
                            <Foo>Bar</Foo>
                        </Compile>
                    </ItemGroup>
                    <ItemDefinitionGroup>
                        <Compile>
                            <First>@(Compile)</First>
                        </Compile>
                    </ItemDefinitionGroup>
	                <Target Name='Build' />
	            </Project>")));
            }
           );
        }
        /// <summary>
        /// Tests that item metadata which contains a metadata expansion referring to an item type other
        /// than the one this item definition refers to expands to blank.
        /// </summary>
        [Fact]
        public void ItemMetadataReferringToDifferentItemGivesEmptyValue()
        {
            Project p = new Project(XmlReader.Create(new StringReader(
            @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    <ItemDefinitionGroup>
                        <Compile>
                            <First>1st</First>
                            <Second>2nd</Second>
                        </Compile>
                    </ItemDefinitionGroup>
                    <ItemDefinitionGroup>
                        <Link>
                            <Third>--%(Compile.First)--</Third>
                            <Fourth>4th</Fourth>
                        </Link>
                    </ItemDefinitionGroup>
                    <ItemGroup>
                        <Compile Include='a.cs'>
                            <Foo>Bar</Foo>
                            <First>Not1st</First>
                        </Compile>
                        <Compile Include='b.cs'>
                            <Foo>Bar</Foo>
                        </Compile>
                    </ItemGroup>
                    <ItemGroup>
                        <Link Include='a.o'/>
                    </ItemGroup>
	                <Target Name='Build' />
	            </Project>")));

            Assert.True(ItemContainsMetadata(p, "Link", "a.o", "Third", "----"));
        }

        /// <summary>
        /// Tests that empty item definition groups are OK.
        /// </summary>
        [Fact]
        public void EmptyItemDefinitionGroup()
        {
            Project p = new Project(XmlReader.Create(new StringReader(
            @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    <ItemDefinitionGroup>
                    </ItemDefinitionGroup>
                    <ItemGroup>
                        <Compile Include='a.cs;b.cs' />
                    </ItemGroup>
	                <Target Name='Build' />
	            </Project>")));
        }

        /// <summary>
        /// Tests that item definition groups with empty item definitions are OK.
        /// </summary>
        [Fact]
        public void EmptyItemDefinitions()
        {
            Project p = new Project(XmlReader.Create(new StringReader(
            @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    <ItemDefinitionGroup>
                        <Compile />
                    </ItemDefinitionGroup>
                    <ItemGroup>
                        <Compile Include='a.cs;b.cs'>
                            <Foo>Bar</Foo>
                        </Compile>
                    </ItemGroup>
	                <Target Name='Build' />
	            </Project>")));

            Assert.True(ItemContainsMetadata(p, "Compile", "a.cs", "Foo", "Bar"));
            Assert.True(ItemContainsMetadata(p, "Compile", "b.cs", "Foo", "Bar"));
        }

        [Fact]
        public void SelfReferencingMetadataReferencesUseItemDefinition()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
   <Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>

    <ItemDefinitionGroup>
      <CppCompile>
        <Defines>DEBUG</Defines>
      </CppCompile>
    </ItemDefinitionGroup>

    <ItemGroup>
      <CppCompile Include='a.cpp'>
        <Defines>%(Defines);CODEANALYSIS</Defines>
      </CppCompile>
    </ItemGroup>

    <Target Name='Build'>
      <Message Text='[{@(CppCompile)}{%(CppCompile.Defines)}]' />
    </Target>
  </Project>")));

            p.Build(new string[] { "Build" }, new ILogger[] { logger });
            logger.AssertLogContains("[{a.cpp}{DEBUG;CODEANALYSIS}]"); // Unexpected value after evaluation
        }


        [Fact]
        public void SelfReferencingMetadataReferencesUseItemDefinitionInTarget()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
   <Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>

    <ItemDefinitionGroup>
      <CppCompile>
        <Defines>DEBUG</Defines>
      </CppCompile>
    </ItemDefinitionGroup>

    <Target Name='Build'>
      <ItemGroup>
        <CppCompile Include='a.cpp'>
          <Defines>%(Defines);CODEANALYSIS</Defines>
        </CppCompile>
      </ItemGroup>

      <Message Text='[{@(CppCompile)}{%(CppCompile.Defines)}]' />
    </Target>
  </Project>")));

            p.Build(new string[] { "Build" }, new ILogger[] { logger });
            logger.AssertLogContains("[{a.cpp}{DEBUG;CODEANALYSIS}]"); // Unexpected value after evaluation
        }

        [Fact]
        public void SelfReferencingMetadataReferencesUseItemDefinitionInTargetModify()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
   <Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>

    <ItemDefinitionGroup>
      <CppCompile>
        <Defines>DEBUG</Defines>
      </CppCompile>
    </ItemDefinitionGroup>
    <ItemGroup>
      <CppCompile Include='a.cpp' />
    </ItemGroup>

    <Target Name='Build'>
      <ItemGroup>
        <CppCompile>
          <Defines>%(Defines);CODEANALYSIS</Defines>
        </CppCompile>
      </ItemGroup>

      <Message Text='[{@(CppCompile)}{%(CppCompile.Defines)}]' />
    </Target>
  </Project>")));

            p.Build(new string[] { "Build" }, new ILogger[] { logger });
            logger.AssertLogContains("[{a.cpp}{DEBUG;CODEANALYSIS}]"); // Unexpected value after evaluation
        }

        /// <summary>
        /// Tests that item definition groups with false conditions don't produce definitions
        /// </summary>
        [Fact]
        public void ItemDefinitionGroupWithFalseCondition()
        {
            Project p = new Project(XmlReader.Create(new StringReader(
            @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    <ItemDefinitionGroup Condition=""'$(Foo)'!=''"">
                        <Compile>
                            <First>1st</First>
                        </Compile>
                    </ItemDefinitionGroup>
                    <ItemGroup>
                        <Compile Include='a.cs;b.cs'>
                            <Foo>Bar</Foo>
                        </Compile>
                    </ItemGroup>
	                <Target Name='Build' />
	            </Project>")));

            Assert.False(p.ItemDefinitions.ContainsKey("Compile"));
            Assert.True(ItemContainsMetadata(p, "Compile", "a.cs", "Foo", "Bar"));
            Assert.False(ItemContainsMetadata(p, "Compile", "a.cs", "First", "1st"));
        }

        /// <summary>
        /// Tests that item definition groups with true conditions produce definitions
        /// </summary>
        [Fact]
        public void ItemDefinitionGroupWithTrueCondition()
        {
            Project p = new Project(XmlReader.Create(new StringReader(
            @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    <ItemDefinitionGroup Condition=""'$(Foo)'==''"">
                        <Compile>
                            <First>1st</First>
                        </Compile>
                    </ItemDefinitionGroup>
                    <ItemGroup>
                        <Compile Include='a.cs;b.cs'>
                            <Foo>Bar</Foo>
                        </Compile>
                    </ItemGroup>
	                <Target Name='Build' />
	            </Project>")));

            Assert.True(p.ItemDefinitions.ContainsKey("Compile"));
            Assert.True(ItemContainsMetadata(p, "Compile", "a.cs", "Foo", "Bar"));
            Assert.True(ItemContainsMetadata(p, "Compile", "a.cs", "First", "1st"));
        }

        /// <summary>
        /// Tests that item definition with false conditions don't produce definitions
        /// </summary>
        [Fact]
        public void ItemDefinitionWithFalseCondition()
        {
            Project p = new Project(XmlReader.Create(new StringReader(
            @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    <ItemDefinitionGroup>
                        <Compile  Condition=""'$(Foo)'!=''"">
                            <First>1st</First>
                        </Compile>
                    </ItemDefinitionGroup>
                    <ItemGroup>
                        <Compile Include='a.cs;b.cs'>
                            <Foo>Bar</Foo>
                        </Compile>
                    </ItemGroup>
	                <Target Name='Build' />
	            </Project>")));

            Assert.False(p.ItemDefinitions.ContainsKey("Compile"));
            Assert.True(ItemContainsMetadata(p, "Compile", "a.cs", "Foo", "Bar"));
            Assert.False(ItemContainsMetadata(p, "Compile", "a.cs", "First", "1st"));
        }

        /// <summary>
        /// Tests that item definition with true conditions produce definitions
        /// </summary>
        [Fact]
        public void ItemDefinitionWithTrueCondition()
        {
            Project p = new Project(XmlReader.Create(new StringReader(
            @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    <ItemDefinitionGroup>
                        <Compile Condition=""'$(Foo)'==''"">
                            <First>1st</First>
                        </Compile>
                    </ItemDefinitionGroup>
                    <ItemGroup>
                        <Compile Include='a.cs;b.cs'>
                            <Foo>Bar</Foo>
                        </Compile>
                    </ItemGroup>
	                <Target Name='Build' />
	            </Project>")));

            Assert.True(p.ItemDefinitions.ContainsKey("Compile"));
            Assert.True(ItemContainsMetadata(p, "Compile", "a.cs", "Foo", "Bar"));
            Assert.True(ItemContainsMetadata(p, "Compile", "a.cs", "First", "1st"));
        }

        /// <summary>
        /// Tests that item definition metadata with false conditions don't produce definitions
        /// </summary>
        [Fact]
        public void ItemDefinitionMetadataWithFalseCondition()
        {
            Project p = new Project(XmlReader.Create(new StringReader(
            @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    <ItemDefinitionGroup>
                        <Compile>
                            <First Condition=""'$(Foo)'!=''"">1st</First>
                        </Compile>
                    </ItemDefinitionGroup>
                    <ItemGroup>
                        <Compile Include='a.cs;b.cs'>
                            <Foo>Bar</Foo>
                        </Compile>
                    </ItemGroup>
	                <Target Name='Build' />
	            </Project>")));

            Assert.True(p.ItemDefinitions.ContainsKey("Compile"));
            Assert.True(ItemContainsMetadata(p, "Compile", "a.cs", "Foo", "Bar"));
            Assert.False(ItemContainsMetadata(p, "Compile", "a.cs", "First", "1st"));
        }

        /// <summary>
        /// Tests that item definition metadata with true conditions produce definitions
        /// </summary>
        [Fact]
        public void ItemDefinitionMetadataWithTrueCondition()
        {
            Project p = new Project(XmlReader.Create(new StringReader(
            @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    <ItemDefinitionGroup>
                        <Compile>
                            <First Condition=""'$(Foo)'==''"">1st</First>
                        </Compile>
                    </ItemDefinitionGroup>
                    <ItemGroup>
                        <Compile Include='a.cs;b.cs'>
                            <Foo>Bar</Foo>
                        </Compile>
                    </ItemGroup>
	                <Target Name='Build' />
	            </Project>")));

            Assert.True(p.ItemDefinitions.ContainsKey("Compile"));
            Assert.True(ItemContainsMetadata(p, "Compile", "a.cs", "Foo", "Bar"));
            Assert.True(ItemContainsMetadata(p, "Compile", "a.cs", "First", "1st"));
        }

        /// <summary>
        /// Tests that item definition metadata is correctly copied to a destination item
        /// </summary>
        [Fact]
        public void ItemDefinitionMetadataCopiedToTaskItem()
        {
            Project p = new Project(XmlReader.Create(new StringReader(
            @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                <ItemDefinitionGroup>
                    <ItemA>
                        <MetaA>M-A(b)</MetaA>
                        <MetaB>M-B(b)</MetaB>
                    </ItemA>
                </ItemDefinitionGroup>
            </Project>")));

            Assert.True(p.ItemDefinitions.ContainsKey("ItemA"));

            ProjectInstance pi = p.CreateProjectInstance();
            ITaskItem withMetaItem;

            List<ProjectItemDefinitionInstance> itemdefs = new List<ProjectItemDefinitionInstance>();
            itemdefs.Add(pi.ItemDefinitions["ItemA"]);

            ITaskItem noMetaItem = new TaskItem("NoMetaItem", pi.FullPath);
            withMetaItem = new TaskItem("WithMetaItem", "WithMetaItem", null, itemdefs, ".", false, pi.FullPath);

            // Copy the metadata on the item with no metadata onto the item with metadata
            // from an item definition. The destination item's metadata should be maintained
            noMetaItem.CopyMetadataTo(withMetaItem);

            Assert.Equal("M-A(b)", withMetaItem.GetMetadata("MetaA"));
            Assert.Equal("M-B(b)", withMetaItem.GetMetadata("MetaB"));
        }

        /// <summary>
        /// Tests that item definition metadata is correctly copied to a destination item
        /// </summary>
        [Fact]
        public void ItemDefinitionMetadataCopiedToTaskItem2()
        {
            Project p = new Project(XmlReader.Create(new StringReader(
            @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                <ItemDefinitionGroup>
                    <ItemA>
                        <MetaA>M-A(b)</MetaA>
                        <MetaB>M-B(b)</MetaB>
                    </ItemA>
                </ItemDefinitionGroup>
            </Project>")));

            Assert.True(p.ItemDefinitions.ContainsKey("ItemA"));

            ProjectInstance pi = p.CreateProjectInstance();
            ITaskItem withMetaItem;

            List<ProjectItemDefinitionInstance> itemdefs = new List<ProjectItemDefinitionInstance>();
            itemdefs.Add(pi.ItemDefinitions["ItemA"]);

            ITaskItem noMetaItem = new TaskItem("NoMetaItem", pi.FullPath);
            noMetaItem.SetMetadata("MetaA", "NEWMETA_A");

            withMetaItem = new TaskItem("WithMetaItem", "WithMetaItem", null, itemdefs, ".", false, pi.FullPath);

            // Copy the metadata on the item with no metadata onto the item with metadata
            // from an item definition. The destination item's metadata should be maintained
            noMetaItem.CopyMetadataTo(withMetaItem);

            // New direct metadata takes precedence over item definitions on the destination item
            Assert.Equal("NEWMETA_A", withMetaItem.GetMetadata("MetaA"));
            Assert.Equal("M-B(b)", withMetaItem.GetMetadata("MetaB"));
        }

        /// <summary>
        /// Tests that item definition metadata is correctly copied to a destination item
        /// </summary>
        [Fact]
        public void ItemDefinitionMetadataCopiedToTaskItem3()
        {
            Project p = new Project(XmlReader.Create(new StringReader(
            @"<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                <ItemDefinitionGroup>
                    <ItemA>
                        <MetaA>M-A(b)</MetaA>
                        <MetaB>M-B(b)</MetaB>
                    </ItemA>
                </ItemDefinitionGroup>
                <ItemGroup>
                    <ItemA Include='SomeItemA' />
                </ItemGroup>
            </Project>")));

            Assert.True(p.ItemDefinitions.ContainsKey("ItemA"));

            ProjectInstance pi = p.CreateProjectInstance();
            ITaskItem withMetaItem = null;

            List<ProjectItemDefinitionInstance> itemdefs = new List<ProjectItemDefinitionInstance>();
            itemdefs.Add(pi.ItemDefinitions["ItemA"]);

            ITaskItem noMetaItem = new TaskItem("NoMetaItem", pi.FullPath);

            // No the ideal way to get the first item, but there is no other way since GetItems returns an IEnumerable :(
            foreach (ProjectItemInstance item in pi.GetItems("ItemA"))
            {
                withMetaItem = item;
            }

            // Copy the metadata on the item with no metadata onto the item with metadata
            // from an item definition. The destination item's metadata should be maintained
            noMetaItem.CopyMetadataTo(withMetaItem);

            Assert.Equal("M-A(b)", withMetaItem.GetMetadata("MetaA"));
            Assert.Equal("M-B(b)", withMetaItem.GetMetadata("MetaB"));
        }

        #region Project tests

        [Fact]
        public void BasicItemDefinitionInProject()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemGroup>
                    <CppCompile Include='a.cpp'/>
                  </ItemGroup>
                  <ItemDefinitionGroup>
                    <CppCompile>
                      <Defines>DEBUG</Defines>
                    </CppCompile>
                  </ItemDefinitionGroup> 
                  <ItemGroup>
                    <CppCompile Include='b.cpp'/>
                  </ItemGroup>
                  <Target Name=""t"">
                    <Message Text=""[%(CppCompile.Identity)==%(CppCompile.Defines)]""/>
                  </Target>
                </Project>
            ")));
            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[a.cpp==DEBUG]", "[b.cpp==DEBUG]");
        }

        [Fact]
        public void EscapingInItemDefinitionInProject()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemGroup>
                    <i Include='i1'/>
                  </ItemGroup>
                  <ItemDefinitionGroup Condition=""'%24'=='$'"">
                    <i Condition=""'%24'=='$'"">
                      <m Condition=""'%24'=='$'"">%24(xyz)</m>
                    </i>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"">
                    <Message Text=""[%(i.m)]""/>
                  </Target>
                </Project>
            ")));
            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[$(xyz)]");
        }


        [Fact]
        public void ItemDefinitionForOtherItemType()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemGroup>
                    <i Include='i1'/>
                  </ItemGroup>
                  <ItemDefinitionGroup>
                    <j>
                      <m>m1</m>
                    </j>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"">
                    <Message Text=""[%(i.m)]""/>
                  </Target>
                </Project>
            ")));
            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[]");
        }

        [Fact]
        public void RedefinitionLastOneWins()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemGroup>
                    <i Include='i1'/>
                  </ItemGroup>
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                      <n>n1</n>
                    </i>
                  </ItemDefinitionGroup> 
                  <ItemDefinitionGroup>
                    <i>
                      <m>m2</m>
                      <o>o1</o>
                    </i>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"">
                    <Message Text=""[%(i.m)-%(i.n)-%(i.o)]""/>
                  </Target>
                </Project>
            ")));
            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[m2-n1-o1]");
        }

        [Fact]
        public void ItemExpressionInDefaultMetadataValueErrors()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                // We don't allow item expressions on an ItemDefinitionGroup because there are no items when IDG is evaluated.
                MockLogger logger = new MockLogger();
                Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemDefinitionGroup>
                    <i>
                      <m>@(x)</m>
                    </i>
                  </ItemDefinitionGroup> 
                </Project>
            ")));
                p.Build("t", new ILogger[] { logger });
            }
           );
        }
        [Fact]
        public void UnqualifiedMetadataConditionOnItemDefinitionGroupErrors()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                // We don't allow unqualified metadata on an ItemDefinitionGroup because we don't know what item type it refers to.
                MockLogger logger = new MockLogger();
                Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemDefinitionGroup Condition=""'%(m)'=='m1'""/>
                </Project>
            ")));
                p.Build("t", new ILogger[] { logger });
            }
           );
        }

        [Fact]
        public void QualifiedMetadataConditionOnItemDefinitionGroupErrors()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                // We don't allow qualified metadata because it's not worth distinguishing from unqualified, when you can just move the condition to the child.
                MockLogger logger = new MockLogger();
                Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemDefinitionGroup Condition=""'%(x.m)'=='m1'""/>
                </Project>
            ")));
                p.Build("t", new ILogger[] { logger });
            }
           );
        }
        [Fact]
        public void MetadataConditionOnItemDefinition()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemGroup>
                    <i Include='i1'/>
                    <j Include='j1'/>
                  </ItemGroup>
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                    </i>
                    <j>
                      <n>n1</n>
                    </j>
                  </ItemDefinitionGroup> 
                  <ItemDefinitionGroup>
                    <i Condition=""'%(m)'=='m1'"">
                      <m>m2</m>
                    </i>
                    <!-- verify j metadata is distinct -->
                    <j Condition=""'%(j.n)'=='n1' and '%(n)'=='n1'"">
                      <n>n2</n>   
                    </j>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"">
                    <Message Text=""[%(i.m)]""/>
                    <Message Text=""[%(j.n)]""/>
                  </Target>
                </Project>
            ")));
            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[m2]", "[n2]");
        }

        [Fact]
        public void QualifiedMetadataConditionOnItemDefinitionBothQualifiedAndUnqualified()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemGroup>
                    <i Include='i1'/>
                  </ItemGroup>
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                    </i>
                  </ItemDefinitionGroup> 
                  <ItemDefinitionGroup>
                    <i Condition=""'%(i.m)'=='m1' and '%(m)'=='m1'"">
                      <m>m2</m>
                    </i>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"">
                    <Message Text=""[%(i.m)]""/>
                  </Target>
                </Project>
            ")));
            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[m2]");
        }

        [Fact]
        public void FalseMetadataConditionOnItemDefinitionBothQualifiedAndUnqualified()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemGroup>
                    <i Include='i1'/>
                  </ItemGroup>
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                    </i>
                  </ItemDefinitionGroup> 
                  <ItemDefinitionGroup>
                    <i Condition=""'%(m)'=='m2' or '%(i.m)'!='m1'"">
                      <m>m3</m>
                    </i>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"">
                    <Message Text=""[%(i.m)]""/>
                  </Target>
                </Project>
            ")));
            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[m1]");
        }

        [Fact]
        public void MetadataConditionOnItemDefinitionChildBothQualifiedAndUnqualified()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemGroup>
                    <i Include='i1'/>
                  </ItemGroup>
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                      <n>n1</n>
                    </i>
                  </ItemDefinitionGroup> 
                  <ItemDefinitionGroup>
                    <i>
                      <m Condition=""'%(m)'=='m1' and '%(n)'=='n1' and '%(i.m)'=='m1'"">m2</m>
                    </i>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"">
                    <Message Text=""[%(i.m)]""/>
                  </Target>
                </Project>
            ")));
            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[m2]");
        }

        [Fact]
        public void FalseMetadataConditionOnItemDefinitionChildBothQualifiedAndUnqualified()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemGroup>
                    <i Include='i1'/>
                  </ItemGroup>
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                      <n>n1</n>
                    </i>
                  </ItemDefinitionGroup> 
                  <ItemDefinitionGroup>
                    <i>
                      <m Condition=""'%(m)'=='m2' or !('%(n)'=='n1') or '%(i.m)' != 'm1'"">m3</m>
                    </i>
                  </ItemDefinitionGroup>
                  <Target Name=""t"">
                    <Message Text=""[%(i.m)]""/>
                  </Target>
                </Project>
            ")));
            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[m1]");
        }

        [Fact]
        public void MetadataConditionOnItemDefinitionAndChildQualifiedWithUnrelatedItemType()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemGroup>
                    <i Include='i1'/>
                  </ItemGroup>
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                    </i>
                  </ItemDefinitionGroup> 
                  <ItemDefinitionGroup>
                    <i Condition=""'%(j.m)'=='' and '%(j.m)'!='x'"">
                      <m Condition=""'%(j.m)'=='' and '%(j.m)'!='x'"">m2</m>
                    </i>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"">
                    <Message Text=""[%(i.m)]""/>
                  </Target>
                </Project>
            ")));
            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[m2]");
        }

        /// <summary>
        /// Make ItemDefinitionGroup inside a target produce a nice error.
        /// It will normally produce an error due to the invalid child tag, but 
        /// we want to error even if there's no child tag. This will make it 
        /// easier to support it inside targets in a future version.
        /// </summary>
        [Fact]
        public void ItemDefinitionInTargetErrors()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                MockLogger logger = new MockLogger();
                Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <Target Name=""t"">
                    <ItemDefinitionGroup/>
                  </Target>
                </Project>
            ")));
                bool result = p.Build("t", new ILogger[] { logger });
            }
           );
        }

#if FEATURE_ASSEMBLY_LOCATION
        // Verify that anyone with a task named "ItemDefinitionGroup" can still
        // use it by fully qualifying the name.
        [Fact]
        public void ItemDefinitionGroupTask()
        {
            MockLogger ml = Helpers.BuildProjectWithNewOMExpectSuccess(String.Format(@"
                    <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                        <UsingTask TaskName=""ItemDefinitionGroup"" AssemblyFile=""{0}""/>
                        <Target Name=""Build"">
                            <Microsoft.Build.UnitTests.Definition.ItemDefinitionGroup/>
                        </Target>
                    </Project>
               ", new Uri(Assembly.GetExecutingAssembly().EscapedCodeBase).LocalPath));

            Assert.Contains("In ItemDefinitionGroup task.", ml.FullLog);
        }
#endif

        [Fact]
        public void MetadataOnItemWins()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemGroup>
                    <CppCompile Include='a.cpp'>
                      <Defines>RETAIL</Defines>
                    </CppCompile>
                    <CppCompile Include='b.cpp'/>
                  </ItemGroup>
                  <ItemDefinitionGroup>
                    <CppCompile>
                      <Defines>DEBUG</Defines>
                    </CppCompile>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"">
                    <Message Text=""[%(CppCompile.Identity)==%(CppCompile.Defines)]""/>
                  </Target>
                </Project>
            ")));
            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[a.cpp==RETAIL]", "[b.cpp==DEBUG]");
        }

        [Fact]
        public void MixtureOfItemAndDefaultMetadata()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemGroup>
                    <CppCompile Include='a.cpp'>
                      <WarningLevel>4</WarningLevel>
                    </CppCompile>
                  </ItemGroup>
                  <ItemDefinitionGroup>
                    <CppCompile>
                      <Defines>DEBUG</Defines>
                    </CppCompile>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"">
                    <Message Text=""[%(CppCompile.Identity)==%(CppCompile.Defines)]""/>
                    <Message Text=""[%(CppCompile.Identity)==%(CppCompile.WarningLevel)]""/>
                  </Target>
                </Project>
            ")));
            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[a.cpp==DEBUG]", "[a.cpp==4]");
        }

        [Fact]
        public void IntrinsicTaskModifyingDefaultMetadata()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemGroup>
                    <i Include='i1'/>
                  </ItemGroup>
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                    </i>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"">
                    <ItemGroup>
                      <i>
                        <m>m2</m>
                      </i>
                    </ItemGroup>
                    <Message Text=""[%(i.m)]""/>
                  </Target>
                </Project>
            ")));
            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[m2]");
        }

        [Fact]
        public void IntrinsicTaskConsumingDefaultMetadata()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemGroup>
                    <i Include='i1'/>
                  </ItemGroup>
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                    </i>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"">
                    <ItemGroup>
                      <i Condition=""'%(i.m)'=='m1'"">
                        <n Condition=""'%(m)'=='m1'"">n2</n>
                      </i>
                    </ItemGroup>
                    <Message Text=""[%(i.n)]""/>
                  </Target>
                </Project>
            ")));
            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[n2]");
        }

        [Fact]
        public void DefinitionInImportedFile()
        {
            MockLogger logger = new MockLogger();
            string importedFile = null;

            try
            {
                importedFile = FileUtilities.GetTemporaryFile();
                File.WriteAllText(importedFile, @"
                <Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                  <ItemDefinitionGroup>
                    <CppCompile>
                      <Defines>DEBUG</Defines>
                    </CppCompile>
                  </ItemDefinitionGroup> 
                </Project>
            ");
                Project p = new Project(XmlReader.Create(new StringReader(@"
                    <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                      <ItemGroup>
                        <CppCompile Include='a.cpp'/>                      
                      </ItemGroup>
                      <Import Project='" + importedFile + @"'/>
                      <Target Name=""t"">
                        <Message Text=""[%(CppCompile.Identity)==%(CppCompile.Defines)]""/>
                      </Target>
                    </Project>
                ")));
                p.Build("t", new ILogger[] { logger });

                logger.AssertLogContains("[a.cpp==DEBUG]");
            }
            finally
            {
                ObjectModelHelpers.DeleteTempFiles(new string[] { importedFile });
            }
        }

        /// <summary>
        /// Item added to project should pick up the item
        /// definitions that project has.
        /// </summary>
        [Fact]
        public void ProjectAddNewItemPicksUpProjectItemDefinitions()
        {
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                    </i>
                  </ItemDefinitionGroup> 
                </Project>
                ")));

            p.AddItem("i", "i1");
            p.ReevaluateIfNecessary();

            Assert.True(ItemContainsMetadata(p, "i", "i1", "m", "m1"));
        }

        /// <summary>
        /// Item added to project should pick up the item
        /// definitions that project has.
        /// </summary>
        [Fact]
        public void ProjectAddNewItemExistingGroupPicksUpProjectItemDefinitions()
        {
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                    </i>
                  </ItemDefinitionGroup> 
                  <ItemGroup>
                    <i Include='i2'>
                      <m>m2</m>
                    </i>
                  </ItemGroup>
                </Project>
                ")));

            p.AddItem("i", "i1");
            p.ReevaluateIfNecessary();

            Assert.True(ItemContainsMetadata(p, "i", "i1", "m", "m1"));
            Assert.True(ItemContainsMetadata(p, "i", "i2", "m", "m2"));
        }

        [Fact]
        public void ItemsEmittedByTaskPickUpItemDefinitions()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                      <n>n1</n>
                    </i>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"">
                    <CreateItem Include=""i1"" AdditionalMetadata=""n=n2"">
                      <Output ItemName=""i"" TaskParameter=""Include""/>
                    </CreateItem>
                    <Message Text=""[%(i.m)][%(i.n)]""/>
                  </Target>
                </Project>
            ")));

            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[m1][n2]");
        }

        [Fact]
        public void ItemsEmittedByIntrinsicTaskPickUpItemDefinitions()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                      <n>n1</n>
                    </i>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"">
                    <ItemGroup>
                      <i Include=""i1"">
                        <n>n2</n>
                      </i>
                    </ItemGroup>
                    <Message Text=""[%(i.m)][%(i.n)]""/>
                  </Target>
                </Project>
            ")));

            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[m1][n2]");
        }

        /// <summary>
        /// When items are passed with an item list expression, default metadata values on the source
        /// items should become regular metadata values on the new items, unless overridden.
        /// </summary>
        [Fact]
        public void ItemsEmittedByIntrinsicTaskConsumingItemExpression_SourceDefaultMetadataPassed()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                    </i>
                  </ItemDefinitionGroup> 
                  <ItemGroup>
                    <i Include=""i1""/>
                  </ItemGroup>
                  <Target Name=""t"">
                    <ItemGroup>
                      <j Include=""@(i)""/>
                    </ItemGroup>
                    <Message Text=""[%(j.m)]""/>
                  </Target>
                </Project>
            ")));

            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[m1]");
        }

        /// <summary>
        /// Default metadata on the source item list is overridden by matching metadata explicitly on the destination
        /// </summary>
        [Fact]
        public void ItemsEmittedByIntrinsicTaskConsumingItemExpression_DestinationExplicitMetadataBeatsSourceDefaultMetadata()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                    </i>
                  </ItemDefinitionGroup> 
                  <ItemGroup>
                    <i Include=""i1""/>
                  </ItemGroup>
                  <Target Name=""t"">
                    <ItemGroup>
                      <j Include=""@(i)"">
                        <m>m2</m>
                      </j>
                    </ItemGroup>
                    <Message Text=""[%(j.m)]""/>
                  </Target>
                </Project>
            ")));

            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[m2]");
        }

        /// <summary>
        /// When items of type X are copied into a list of type Y, default metadata applicable to type X override
        /// any matching default metadata applicable to type Y.
        /// </summary>
        /// <remarks>
        /// Either behavior here is fairly reasonable. We decided on this way around based on feedback from VC.
        /// Note: this differs from how Orcas did it.
        /// </remarks>
        [Fact]
        public void ItemsEmittedByIntrinsicTaskConsumingItemExpression_DestinationDefaultMetadataOverriddenBySourceDefaultMetadata()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                    </i>
                    <j>
                      <m>m2</m>
                    </j>
                  </ItemDefinitionGroup> 
                  <ItemGroup>
                    <i Include=""n1""/>
                    <j Include=""@(i)""/>
                  </ItemGroup>
                  <Target Name=""t"">
                    <ItemGroup>
                      <i Include=""n2""/>
                      <j Include=""@(i)""/>
                    </ItemGroup>
                    <Message Text=""[%(j.m)]""/>
                  </Target>
                </Project>
            ")));

            Assert.Equal("m1", p.GetItems("j").First().GetMetadataValue("m"));

            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[m1]");
            logger.AssertLogDoesntContain("[m2]");
        }

        /// <summary>
        /// Default and explicit metadata on both source and destination.
        /// Item definition metadata from the source override item definition on the destination.
        /// </summary>
        [Fact]
        public void ItemsEmittedByIntrinsicTaskConsumingItemExpression_Combination_OutsideTarget()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemDefinitionGroup>
                    <i>
                      <m>im1</m>
                      <n>in1</n>
                      <o>io1</o>
                      <p>ip1</p>
                    </i>
                    <j>
                      <m>jm3</m>
                      <n>jn3</n>
                      <q>jq3</q>
                    </j>
                    <k>
                      <m>km4</m>
                      <q>kq4</q>
                      <r>kr4</r>
                    </k>
                  </ItemDefinitionGroup> 
                  <ItemGroup>
                    <i Include=""1"">
                      <o>io2</o>
                      <s>is2</s>
                    </i>
                    <j Include=""2""/>
                    <k Include=""3"">
                      <M>km5</M>
                    </k>
                  </ItemGroup>
                  <ItemGroup>
                    <j Include=""@(i)"">
                      <m>jm6</m>
                    </j>
                    <k Include=""@(j)"">
                      <s>ks3</s>
                    </k>
                  </ItemGroup>
                </Project>
            ")));

            Assert.Equal("im1", p.GetItems("i").First().GetMetadataValue("m"));
            Assert.Equal("in1", p.GetItems("i").First().GetMetadataValue("n"));
            Assert.Equal("io2", p.GetItems("i").First().GetMetadataValue("o"));
            Assert.Equal("ip1", p.GetItems("i").First().GetMetadataValue("p"));
            Assert.Equal("", p.GetItems("i").First().GetMetadataValue("q"));

            Assert.Equal("jm3", p.GetItems("j").First().GetMetadataValue("m"));
            Assert.Equal("jn3", p.GetItems("j").First().GetMetadataValue("n"));
            Assert.Equal("", p.GetItems("j").First().GetMetadataValue("o"));
            Assert.Equal("", p.GetItems("j").First().GetMetadataValue("p"));
            Assert.Equal("jq3", p.GetItems("j").First().GetMetadataValue("q"));

            Assert.Equal("jm6", p.GetItems("j").ElementAt(1).GetMetadataValue("m"));
            Assert.Equal("in1", p.GetItems("j").ElementAt(1).GetMetadataValue("n"));
            Assert.Equal("io2", p.GetItems("j").ElementAt(1).GetMetadataValue("o"));
            Assert.Equal("ip1", p.GetItems("j").ElementAt(1).GetMetadataValue("p"));
            Assert.Equal("jq3", p.GetItems("j").ElementAt(1).GetMetadataValue("q"));

            Assert.Equal("km5", p.GetItems("k").ElementAt(0).GetMetadataValue("m"));
            Assert.Equal("", p.GetItems("k").ElementAt(0).GetMetadataValue("n"));
            Assert.Equal("", p.GetItems("k").ElementAt(0).GetMetadataValue("o"));
            Assert.Equal("", p.GetItems("k").ElementAt(0).GetMetadataValue("p"));
            Assert.Equal("kq4", p.GetItems("k").ElementAt(0).GetMetadataValue("q"));
            Assert.Equal("kr4", p.GetItems("k").ElementAt(0).GetMetadataValue("r"));
            Assert.Equal("", p.GetItems("k").ElementAt(0).GetMetadataValue("s"));

            Assert.Equal("jm3", p.GetItems("k").ElementAt(1).GetMetadataValue("m"));
            Assert.Equal("jn3", p.GetItems("k").ElementAt(1).GetMetadataValue("n"));
            Assert.Equal("", p.GetItems("k").ElementAt(1).GetMetadataValue("o"));
            Assert.Equal("", p.GetItems("k").ElementAt(1).GetMetadataValue("p"));
            Assert.Equal("jq3", p.GetItems("k").ElementAt(1).GetMetadataValue("q"));
            Assert.Equal("kr4", p.GetItems("k").ElementAt(1).GetMetadataValue("r"));
            Assert.Equal("ks3", p.GetItems("k").ElementAt(1).GetMetadataValue("s"));

            Assert.Equal("jm6", p.GetItems("k").ElementAt(2).GetMetadataValue("m"));
            Assert.Equal("in1", p.GetItems("k").ElementAt(2).GetMetadataValue("n"));
            Assert.Equal("io2", p.GetItems("k").ElementAt(2).GetMetadataValue("o"));
            Assert.Equal("ip1", p.GetItems("k").ElementAt(2).GetMetadataValue("p"));
            Assert.Equal("jq3", p.GetItems("k").ElementAt(2).GetMetadataValue("q"));
            Assert.Equal("kr4", p.GetItems("k").ElementAt(2).GetMetadataValue("r"));
            Assert.Equal("ks3", p.GetItems("k").ElementAt(1).GetMetadataValue("s"));
        }

        /// <summary>
        /// Default and explicit metadata on both source and destination.
        /// Item definition metadata from the source override item definition on the destination.
        /// </summary>
        [Fact]
        public void ItemsEmittedByIntrinsicTaskConsumingItemExpression_Combination_InsideTarget()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemDefinitionGroup>
                    <i>
                      <m>im1</m>
                      <n>in1</n>
                      <o>io1</o>
                      <p>ip1</p>
                    </i>
                    <j>
                      <m>jm3</m>
                      <n>jn3</n>
                      <q>jq3</q>
                    </j>
                    <k>
                      <m>km4</m>
                      <q>kq4</q>
                    </k>
                  </ItemDefinitionGroup> 
                  <ItemGroup>
                    <i Include=""1"">
                      <o>io2</o>
                    </i>
                    <j Include=""2""/>
                    <k Include=""3"">
                      <M>km5</M>
                    </k>
                  </ItemGroup>
                  <Target Name=""t"">
                    <ItemGroup>
                      <j Include=""@(i)"">
                        <m>jm6</m>
                      </j>
                      <k Include=""@(j)""/>
                    </ItemGroup>
                    <Message Text=""i:%(identity) [%(i.m)][%(i.n)][%(i.o)][%(i.p)][%(i.q)]""/>
                    <Message Text=""j:%(identity) [%(j.m)][%(j.n)][%(j.o)][%(j.p)][%(j.q)]""/>
                    <Message Text=""k:%(identity) [%(k.m)][%(k.n)][%(k.o)][%(k.p)][%(k.q)]""/>
                  </Target>
                </Project>
            ")));

            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("i:1 [im1][in1][io2][ip1][]");
            logger.AssertLogContains("j:2 [jm3][jn3][][][jq3]");
            logger.AssertLogContains("j:1 [jm6][in1][io2][ip1][jq3]");
            logger.AssertLogContains("k:3 [km5][][][][kq4]");
            logger.AssertLogContains("k:2 [jm3][jn3][][][jq3]");
            logger.AssertLogContains("k:1 [jm6][in1][io2][ip1][jq3]");
        }

        [Fact]
        public void MutualReferenceToDefinition1()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                      <n>~%(m)~</n>
                    </i>
                  </ItemDefinitionGroup> 
                    <ItemGroup>
                      <i Include=""i1""/>
                    </ItemGroup>   
                  <Target Name=""t"">
                    <Message Text=""[%(i.m)][%(i.n)]""/>
                  </Target>
                </Project>
            ")));

            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[m1][~m1~]");
        }

        [Fact]
        public void MutualReferenceToDefinition2()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemDefinitionGroup>
                    <i>
                      <m>~%(n)~</m>
                      <n>n1</n>
                    </i>
                  </ItemDefinitionGroup> 
                    <ItemGroup>
                      <i Include=""i1""/>
                    </ItemGroup>   
                  <Target Name=""t"">
                    <Message Text=""[%(i.m)][%(i.n)]""/>
                  </Target>
                </Project>
            ")));

            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[~~][n1]");
        }

        [Fact]
        public void MutualReferenceToDefinition3()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                      <n>%(i.m)</n>
                      <o>%(j.m)</o>
                    </i>
                  </ItemDefinitionGroup> 
                    <ItemGroup>
                      <i Include=""i1""/>
                    </ItemGroup>   
                  <Target Name=""t"">
                    <Message Text=""[%(i.m)][%(i.n)][%(i.o)]""/>
                  </Target>
                </Project>
            ")));

            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[m1][m1][]");
        }

        [Fact]
        public void ProjectReevaluationReevaluatesItemDefinitions()
        {
            MockLogger logger = new MockLogger();
            Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <PropertyGroup>
                    <Defines>CODEANALYSIS</Defines>
                  </PropertyGroup>
                  <ItemGroup>
                    <CppCompile Include='a.cpp'/>
                  </ItemGroup>
                  <ItemDefinitionGroup>
                    <CppCompile>
                      <Defines Condition=""'$(BuildFlavor)'=='ret'"">$(Defines);RETAIL</Defines>
                      <Defines Condition=""'$(BuildFlavor)'=='chk'"">$(Defines);DEBUG</Defines>
                    </CppCompile>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"">
                    <Message Text=""[%(CppCompile.Identity)==%(CppCompile.Defines)]""/>
                  </Target>
                </Project>
            ")));

            p.SetProperty("BuildFlavor", "ret");

            p.Build("t", new ILogger[] { logger });

            logger.AssertLogContains("[a.cpp==CODEANALYSIS;RETAIL]");

            Assert.True(ItemContainsMetadata(p, "CppCompile", "a.cpp", "Defines", "CODEANALYSIS;RETAIL"));

            p.SetProperty("BuildFlavor", "chk");
            p.ReevaluateIfNecessary();

            Assert.True(ItemContainsMetadata(p, "CppCompile", "a.cpp", "Defines", "CODEANALYSIS;DEBUG"));
        }

        [Fact]
        public void MSBuildCallDoesNotAffectCallingProjectsDefinitions()
        {
            string otherProject = null;

            try
            {
                otherProject = FileUtilities.GetTemporaryFile();
                string otherProjectContent = @"<Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemGroup>
                    <i Include='i1'/>
                  </ItemGroup>
                  <ItemDefinitionGroup>
                    <i>
                      <m>m2</m>
                    </i>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"">
                    <Message Text=""[CHILD:%(i.m)]""/>
                  </Target>
                </Project>";

                using (StreamWriter writer = FileUtilities.OpenWrite(otherProject, false))
                {
                    writer.Write(otherProjectContent);
                }

                MockLogger logger = new MockLogger();
                Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemGroup>
                    <i Include='i1'/>
                  </ItemGroup>
                  <ItemDefinitionGroup>
                    <i>
                      <m>m1</m>
                    </i>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"">
                    <Message Text=""[PARENT-before:%(i.m)]""/>
                    <MSBuild Projects=""" + otherProject + @"""/>
                    <Message Text=""[PARENT-after:%(i.m)]""/>
                  </Target>
                </Project>
            ")));

                p.Build("t", new ILogger[] { logger });

                logger.AssertLogContains("[PARENT-before:m1]", "[CHILD:m2]", "[PARENT-after:m1]");
            }
            finally
            {
                File.Delete(otherProject);
            }
        }

        [Fact]
        public void DefaultMetadataTravelWithTargetOutputs()
        {
            string otherProject = null;

            try
            {
                otherProject = FileUtilities.GetTemporaryFile();
                string otherProjectContent = @"<Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <ItemGroup>
                    <i Include='i1'>
                       <m>m1</m>
                    </i>
                  </ItemGroup>
                  <ItemDefinitionGroup>
                    <i>
                      <n>n1</n>
                    </i>
                  </ItemDefinitionGroup> 
                  <Target Name=""t"" Outputs=""@(i)"">
                    <Message Text=""[CHILD:%(i.Identity):m=%(i.m),n=%(i.n)]""/>
                  </Target>
                </Project>";

                using (StreamWriter writer = FileUtilities.OpenWrite(otherProject, false))
                {
                    writer.Write(otherProjectContent);
                }

                MockLogger logger = new MockLogger();
                Project p = new Project(XmlReader.Create(new StringReader(@"
                <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
                  <Target Name=""t"">
                    <MSBuild Projects=""" + otherProject + @""">
                       <Output TaskParameter='TargetOutputs' ItemName='i'/>
                    </MSBuild>
                    <Message Text=""[PARENT:%(i.Identity):m=%(i.m),n=%(i.n)]""/>
                  </Target>
                </Project>
            ")));

                p.Build("t", new ILogger[] { logger });

                logger.AssertLogContains("[CHILD:i1:m=m1,n=n1]", "[PARENT:i1:m=m1,n=n1]");
            }
            finally
            {
                File.Delete(otherProject);
            }
        }

        #endregion
        /// <summary>
        /// Determines if the specified item contains the specified metadata
        /// </summary>
        /// <param name="project">The project.</param>
        /// <param name="itemType">The item type.</param>
        /// <param name="itemInclude">The item include.</param>
        /// <param name="name">The metadata name.</param>
        /// <param name="value">The metadata value.</param>
        /// <returns>True if the item contains the metadata, false otherwise.</returns>
        private bool ItemContainsMetadata(Project project, string itemType, string itemInclude, string name, string value)
        {
            foreach (ProjectItem item in project.GetItems(itemType))
            {
                if (item.EvaluatedInclude == itemInclude)
                {
                    return ContainsMetadata(item.Metadata, name, value);
                }
            }

            return false;
        }

        /// <summary>
        /// Determines if the metadata collection contains the named metadata with the specified value
        /// </summary>
        /// <param name="metadata">The collection.</param>
        /// <param name="name">The metadata name.</param>
        /// <param name="value">The metadata value.</param>
        /// <returns>True if the collection contains the metadata, false otherwise.</returns>
        private bool ContainsMetadata(IEnumerable<ProjectMetadata> metadata, string name, string value)
        {
            foreach (ProjectMetadata metadataEntry in metadata)
            {
                if (metadataEntry.Name == name && metadataEntry.EvaluatedValue == value)
                {
                    return true;
                }
            }

            return false;
        }
    }

    public class ItemDefinitionGroup : Microsoft.Build.Utilities.Task
    {
        public override bool Execute()
        {
            Log.LogMessage("In ItemDefinitionGroup task.");
            return true;
        }
    }
}


<|start_filename|>src/Tasks/FileState.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Build.Shared;

namespace Microsoft.Build.Tasks
{
    /// <summary>
    /// CopyFile delegate
    /// 
    /// returns  Success = true, Failure = false; Retry = null
    /// </summary>
    /// <param name="source">Source file</param>
    /// <param name="destination">Destination file</param>
    internal delegate bool? CopyFileWithState(FileState source, FileState destination);

    /// <summary>
    /// Short-term cache saves the result of IO operations on a filename. Should only be
    /// used in cases where it is know there will be no exogenous changes to the filesystem
    /// for this file.
    /// </summary>
    /// <remarks>
    /// Uses PInvoke rather than FileInfo because the latter does all kinds of expensive checks.
    /// 
    /// Deficiency: some of the properties eat some or all exceptions. If they are called first, they will
    /// trigger the population and eat. Subsequent calls will then not throw, but instead eg return zero.
    /// This could be fixed by storing the exception from the population, and throwing no matter who does
    /// the population and whether it's been done before.
    /// </remarks>
    internal class FileState
    {
        private class FileDirInfo
        {
            /// <summary>
            /// The name of the file.
            /// </summary>
            private readonly string _filename;

            /// <summary>
            /// Set to true if file or directory exists
            /// </summary>
            public readonly bool Exists;

            /// <summary>
            /// Set to true if the path referred to a directory.
            /// </summary>
            public readonly bool IsDirectory;

            /// <summary>
            /// File length
            /// </summary>
            public readonly long Length;

            /// <summary>
            /// Last time the file was updated
            /// </summary>
            public readonly DateTime LastWriteTimeUtc;

            /// <summary>
            /// True if the file is readonly
            /// </summary>
            public readonly bool IsReadOnly;

            /// <summary>
            /// Exception thrown on creation
            /// </summary>
            private readonly Exception _exceptionThrown;

            /// <summary>
            /// Constructor gets the data for the filename.
            /// On Win32 it uses native means. Otherwise,
            /// uses standard .NET FileInfo/DirInfo
            /// </summary>
            public FileDirInfo(string filename)
            {
                Exists = false;

                // If file/directory does not exist, return 12 midnight 1/1/1601.
                LastWriteTimeUtc = new DateTime(1601, 1, 1);

                _filename = FileUtilities.AttemptToShortenPath(filename); // This is no-op unless the path actually is too long

                int oldMode = 0;

                if (NativeMethodsShared.IsWindows)
                {
                    // THIS COPIED FROM THE BCL:
                    //
                    // For floppy drives, normally the OS will pop up a dialog saying
                    // there is no disk in drive A:, please insert one.  We don't want that. 
                    // SetErrorMode will let us disable this, but we should set the error
                    // mode back, since this may have wide-ranging effects.
                    oldMode = NativeMethodsShared.SetErrorMode(1 /* ErrorModes.SEM_FAILCRITICALERRORS */);
                }

                try
                {
                    if (NativeMethodsShared.IsWindows)
                    {
                        var data = new NativeMethodsShared.WIN32_FILE_ATTRIBUTE_DATA();
                        bool success = NativeMethodsShared.GetFileAttributesEx(_filename, 0, ref data);

                        if (!success)
                        {
                            int error = Marshal.GetLastWin32Error();

                            // File not found is the most common case, for example we're copying
                            // somewhere without a file yet. Don't do something like FileInfo.Exists to
                            // get a nice error, or we're doing IO again! Don't even format our own string:
                            // that turns out to be unacceptably expensive here as well. Set a flag for this particular case.
                            //
                            // Also, when not under debugger (!) it will give error == 3 for path too long. Make that consistently throw instead.
                            if ((error == 2 /* ERROR_FILE_NOT_FOUND */|| error == 3 /* ERROR_PATH_NOT_FOUND */)
                                && _filename.Length <= NativeMethodsShared.MaxPath)
                            {
                                Exists = false;
                                return;
                            }

                            // Throw nice message as far as we can. At this point IO is OK.
                            Length = new FileInfo(_filename).Length;

                            // Otherwise this will give at least something
                            NativeMethodsShared.ThrowExceptionForErrorCode(error);
                            ErrorUtilities.ThrowInternalErrorUnreachable();
                        }

                        Exists = true;
                        IsDirectory = (data.fileAttributes & NativeMethodsShared.FILE_ATTRIBUTE_DIRECTORY) != 0;
                        IsReadOnly = !IsDirectory
                                      && (data.fileAttributes & NativeMethodsShared.FILE_ATTRIBUTE_READONLY) != 0;
                        LastWriteTimeUtc =
                            DateTime.FromFileTimeUtc(((long)data.ftLastWriteTimeHigh << 0x20) | data.ftLastWriteTimeLow);
                        Length = IsDirectory ? 0 : (((long)data.fileSizeHigh << 0x20) | data.fileSizeLow);
                    }
                    else
                    {
                        var fileInfo = new FileInfo(_filename);

                        if (fileInfo.Exists)
                        {
                            // Use FileInfo to get readonly and last write date
                            Exists = true;
                            IsReadOnly = fileInfo.IsReadOnly;
                            LastWriteTimeUtc = fileInfo.LastWriteTimeUtc;
                            Length = fileInfo.Length;
                        }
                        else
                        {
                            var directoryInfo = new DirectoryInfo(_filename);

                            if (directoryInfo.Exists)
                            {
                                // Use DirectoryInfo to get the last write date
                                Exists = true;
                                IsDirectory = true;
                                IsReadOnly = false;
                                LastWriteTimeUtc = directoryInfo.LastWriteTimeUtc;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    // Save the exception thrown and assume the file does not exist
                    _exceptionThrown = ex;
                    Exists = false;
                }
                finally
                {
                    // Reset the error mode on Windows
                    if (NativeMethodsShared.IsWindows)
                    {
                        NativeMethodsShared.SetErrorMode(oldMode);
                    }
                }
            }

            /// <summary>
            /// Throw exception as if the FileInfo did it. We
            /// know that getting the length of a file would
            /// throw exception if there are IO problems
            /// </summary>
            public void ThrowFileInfoException(bool doThrow)
            {
                if (doThrow)
                {
                    // Provoke exception
                    var length = (new FileInfo(_filename)).Length;
                }
            }

            /// <summary>
            /// Throw non-IO-related exception if occurred during creation.
            /// Return true if exception did occur, but was IO-related
            /// </summary>
            public bool ThrowNonIoExceptionIfPending()
            {
                if (_exceptionThrown != null)
                {
                    if (!ExceptionHandling.IsIoRelatedException(_exceptionThrown))
                    {
                        throw _exceptionThrown;
                    }

                    return true;
                }

                return false;
            }

            /// <summary>
            /// Throw any exception collected during construction
            /// </summary>
            public void ThrowException()
            {
                if (_exceptionThrown != null)
                {
                    throw _exceptionThrown;
                }
            }
        }

        /// <summary>
        /// The name of the file.
        /// </summary>
        private readonly string _filename;

        /// <summary>
        /// Actual file or directory information
        /// </summary>
        private Lazy<FileDirInfo> _data;

        /// <summary>
        /// Constructor.
        /// Only stores file name: does not grab the file state until first request.
        /// </summary>
        internal FileState(string filename)
        {
            ErrorUtilities.VerifyThrowArgumentLength(filename, nameof(filename));
            _filename = filename;
            _data = new Lazy<FileDirInfo>(() => new FileDirInfo(_filename));
        }

        /// <summary>
        /// Whether the file is readonly.
        /// Returns false for directories.
        /// Throws if file does not exist.
        /// </summary>
        internal bool IsReadOnly => !DirectoryExists && _data.Value.IsReadOnly;

        /// <summary>
        /// Whether the file exists.
        /// Returns false if it is a directory, even if it exists.
        /// Returns false instead of IO related exceptions.
        /// </summary>
        internal bool FileExists => !_data.Value.ThrowNonIoExceptionIfPending() && (_data.Value.Exists && !_data.Value.IsDirectory);

        /// <summary>
        /// Whether the directory exists.
        /// Returns false for files.
        /// Returns false instead of IO related exceptions.
        /// </summary>
        internal bool DirectoryExists => !_data.Value.ThrowNonIoExceptionIfPending() && (_data.Value.Exists && _data.Value.IsDirectory);

        /// <summary>
        /// Last time the file was written.
        /// Works for directories.
        /// </summary>
        internal DateTime LastWriteTime => LastWriteTimeUtcFast.ToLocalTime();

        /// <summary>
        /// Last time the file was written, in UTC. Avoids translation for daylight savings, time zone etc which isn't needed for just comparisons.
        /// If file does not exist, returns 12 midnight 1/1/1601.
        /// Works for directories.
        /// </summary>
        internal DateTime LastWriteTimeUtcFast
        {
            get
            {
                _data.Value.ThrowException();
                return _data.Value.Exists ? _data.Value.LastWriteTimeUtc : new DateTime(1601, 1, 1);
            }
        }

        /// <summary>
        /// Length of the file in bytes.
        /// Throws if it is a directory.
        /// Throws if it does not exist.
        /// </summary>
        internal long Length
        {
            get
            {
                _data.Value.ThrowException();
                _data.Value.ThrowFileInfoException(!_data.Value.Exists || _data.Value.IsDirectory);
                return _data.Value.Length;
            }
        }

        /// <summary>
        /// Name of the file as it was passed in.
        /// Not normalized.
        /// </summary>
        internal string Name => _filename;

        /// <summary>
        /// Whether this is a directory.
        /// Throws if it does not exist.
        /// </summary>
        internal bool IsDirectory
        {
            get
            {
                _data.Value.ThrowException();
                _data.Value.ThrowFileInfoException(!_data.Value.Exists);
                return _data.Value.IsDirectory;
            }
        }

        /// <summary>
        /// Use in case the state is known to have changed exogenously.
        /// </summary>
        internal void Reset()
        {
            _data = new Lazy<FileDirInfo>(() => new FileDirInfo(_filename));
        }
    }
}


<|start_filename|>src/Build.UnitTests/BackEnd/CentralForwardingLogger_Tests.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Build.Framework;
using Microsoft.Build.BackEnd.Logging;
using Microsoft.Build.Shared;
using Xunit;

namespace Microsoft.Build.UnitTests.Logging
{
    /// <summary>
    /// Test the central forwarding logger by initializing a new one and sending events through it.
    /// </summary>
    public class CentralForwardingLogger_Tests
    {
        /// <summary>
        /// Tests the basic getting and setting of the logger parameters
        /// </summary>
        [Fact]
        public void GetandSetLoggerParameters()
        {
            CentralForwardingLogger centralLogger = new CentralForwardingLogger();

            // Verify NodeId can be get and set properly
            Assert.Equal(0, centralLogger.NodeId);
            centralLogger.NodeId = 4;
            Assert.Equal(4, centralLogger.NodeId);

            // Verify Parameters can be get and set properly
            Assert.True(string.IsNullOrEmpty(centralLogger.Parameters)); // "Expected parameters to be null or empty"
            centralLogger.Parameters = "MyParameters";
            Assert.Equal("MyParameters", centralLogger.Parameters); // "Expected parameters equal MyParameters"

            // Verify Verbosity can be get and set properly
            Assert.Equal(LoggerVerbosity.Quiet, centralLogger.Verbosity); // "Expected default to be Quiet"
            centralLogger.Verbosity = LoggerVerbosity.Detailed;
            Assert.Equal(LoggerVerbosity.Detailed, centralLogger.Verbosity); // "Expected default to be Detailed"

            // Verify BuildEventRedirector can be get and set properly
            Assert.Null(centralLogger.BuildEventRedirector); // "Expected BuildEventRedirector to be null"
            TestEventRedirector eventRedirector = new TestEventRedirector(null);
            centralLogger.BuildEventRedirector = eventRedirector;
            Assert.Equal(centralLogger.BuildEventRedirector, eventRedirector); // "Expected the BuildEventRedirector to match the passed in eventRedirector"
        }

        /// <summary>
        /// Verify the correct exception is thrown when the logger is initialized with a null 
        /// event source.
        /// </summary>
        [Fact]
        public void InitializeWithNullEventSourceILogger()
        {
            Assert.Throws<InternalErrorException>(() =>
            {
                CentralForwardingLogger centralLogger = new CentralForwardingLogger();
                centralLogger.Initialize(null);
            }
           );
        }
        /// <summary>
        /// Verify the correct exception is thrown when the logger is initialized with a null 
        /// event source.
        /// </summary>
        [Fact]
        public void InitializeWithNullEventSourceINodeLogger()
        {
            Assert.Throws<InternalErrorException>(() =>
            {
                CentralForwardingLogger centralLogger = new CentralForwardingLogger();
                centralLogger.Initialize(null, 4);
            }
           );
        }
        /// <summary>
        /// Verify the shutdown method will null out the event redirector
        /// </summary>
        [Fact]
        public void TestShutDown()
        {
            CentralForwardingLogger centralLogger = new CentralForwardingLogger();
            centralLogger.BuildEventRedirector = new TestEventRedirector(null);

            Assert.NotNull(centralLogger.BuildEventRedirector);

            centralLogger.Shutdown();
            Assert.Null(centralLogger.BuildEventRedirector);
        }

        /// <summary>
        /// Verify that the forwarding logger correctly forwards events when passed to it.
        /// </summary>
        [Fact]
        public void ForwardEvents()
        {
            BuildStartedEventArgs buildStarted = new BuildStartedEventArgs("Message", "Help");
            BuildFinishedEventArgs buildFinished = new BuildFinishedEventArgs("Message", "Keyword", true);
            BuildMessageEventArgs normalMessage = new BuildMessageEventArgs("Message2", "help", "sender", MessageImportance.Normal);

            EventSourceSink loggerSource = AttachForwardingLoggerAndRedirector(buildStarted);
            loggerSource.Consume(buildStarted);

            loggerSource = AttachForwardingLoggerAndRedirector(buildFinished);
            loggerSource.Consume(buildFinished);

            loggerSource = AttachForwardingLoggerAndRedirector(normalMessage);
            loggerSource.Consume(normalMessage);
        }

        /// <summary>
        /// Verify no exception is thrown when an event is raised but no
        /// event redirector is registered on the logger. This could happen
        /// if no central logger is registered with the system.
        /// </summary>
        [Fact]
        public void RaiseEventWithNoBuildEventRedirector()
        {
            BuildMessageEventArgs normalMessage = new BuildMessageEventArgs("Message2", "help", "sender", MessageImportance.Normal);
            EventSourceSink loggerSource = new EventSourceSink();
            CentralForwardingLogger forwardingLogger = new CentralForwardingLogger();
            forwardingLogger.Initialize(loggerSource);
            loggerSource.Consume(normalMessage);
        }

        /// <summary>
        /// Create a new forwarding logger, event redirector, and event source.
        /// The returned event source can then have and event raised on it and it can 
        /// check to see if the event raised matches the one we were expecting.
        /// </summary>
        /// <param name="buildEventToCheck">A build event we are expecting to be forwarded by the forwarding logger</param>
        /// <returns>An event source on which one can raise an event.</returns>
        private static EventSourceSink AttachForwardingLoggerAndRedirector(BuildEventArgs buildEventToCheck)
        {
            EventSourceSink loggerEventSource = new EventSourceSink();
            CentralForwardingLogger forwardingLogger = new CentralForwardingLogger();
            TestEventRedirector eventRedirector = new TestEventRedirector(buildEventToCheck);
            forwardingLogger.BuildEventRedirector = eventRedirector;
            forwardingLogger.Initialize(loggerEventSource);
            return loggerEventSource;
        }

        /// <summary>
        /// An event redirector which takes in an expected event 
        /// and when the forwarding logger forwards and event 
        /// we check to see if the events match. This allows
        /// us to check to see if the forwarding logger is
        /// sending us the events we send in.
        /// </summary>
        private class TestEventRedirector : IEventRedirector
        {
            #region Data

            /// <summary>
            /// Event we expect to see in the ForwardEvent method. 
            /// This helps us verify that a logger is correctly forwarding 
            /// an event.
            /// </summary>
            private BuildEventArgs _expectedEvent;

            #endregion

            /// <summary>
            /// Take in an expected event and when the event is forwarded make sure
            /// the events are the same.
            /// </summary>
            /// <param name="eventToExpect">Event we expect to see in the ForwardEvent method</param>
            public TestEventRedirector(BuildEventArgs eventToExpect)
            {
                _expectedEvent = eventToExpect;
            }

            #region Members

            /// <summary>
            /// When a forwarding logger forwards an event we need to check to see
            /// if the event the logger sent us is the same one we sent in.
            /// </summary>
            /// <param name="buildEvent">Build event to forward</param>
            public void ForwardEvent(BuildEventArgs buildEvent)
            {
                Assert.Equal(_expectedEvent, buildEvent); // "Expected the forwarded event to match the expected event"
            }

            #endregion
        }
    }
}

<|start_filename|>src/Build.OM.UnitTests/Construction/SolutionFile_Tests.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Build.Construction;
using Microsoft.Build.Shared;
using Microsoft.Build.Exceptions;
using Shouldly;
using Xunit;
using System.Text;

namespace Microsoft.Build.UnitTests.Construction
{
    /// <summary>
    /// Tests for the parts of SolutionFile that are surfaced as public API
    /// </summary>
    public class SolutionFile_Tests
    {
        [Theory]
        [InlineData(@"
                {
                  ""solution"": {
                    ""path"": ""C:\\notAPath\\MSBuild.Dev.sln"",
                    ""projects2"": [
                      ""src\\Build\\Microsoft.Build.csproj"",
                      ""src\\Framework\\Microsoft.Build.Framework.csproj"",
                      ""src\\MSBuild\\MSBuild.csproj"",
                      ""src\\Tasks.UnitTests\\Microsoft.Build.Tasks.UnitTests.csproj""
                    ]
                    }
                }
                ", "MSBuild.SolutionFilterJsonParsingError")]
        [InlineData(@"
                [{
                  ""solution"": {
                    ""path"": ""C:\\notAPath\\MSBuild.Dev.sln"",
                    ""projects"": [
                      ""src\\Build\\Microsoft.Build.csproj"",
                      ""src\\Framework\\Microsoft.Build.Framework.csproj"",
                      ""src\\MSBuild\\MSBuild.csproj"",
                      ""src\\Tasks.UnitTests\\Microsoft.Build.Tasks.UnitTests.csproj""
                    ]
                    }
                }]
                ", "MSBuild.SolutionFilterJsonParsingError")]
        [InlineData(@"
                {
                  ""solution"": {
                    ""path"": ""C:\\notAPath\\MSBuild.Dev.sln"",
                    ""projects"": [
                      {""path"": ""src\\Build\\Microsoft.Build.csproj""},
                      {""path"": ""src\\Framework\\Microsoft.Build.Framework.csproj""},
                      {""path"": ""src\\MSBuild\\MSBuild.csproj""},
                      {""path"": ""src\\Tasks.UnitTests\\Microsoft.Build.Tasks.UnitTests.csproj""}
                    ]
                    }
                }
                ", "MSBuild.SolutionFilterJsonParsingError")]
        [InlineData(@"
                {
                  ""solution"": {
                    ""path"": ""C:\\notAPath2\\MSBuild.Dev.sln"",
                    ""projects"": [
                      {""path"": ""src\\Build\\Microsoft.Build.csproj""},
                      {""path"": ""src\\Framework\\Microsoft.Build.Framework.csproj""},
                      {""path"": ""src\\MSBuild\\MSBuild.csproj""},
                      {""path"": ""src\\Tasks.UnitTests\\Microsoft.Build.Tasks.UnitTests.csproj""}
                    ]
                    }
                }
                ", "MSBuild.SolutionFilterMissingSolutionError")]
        public void InvalidSolutionFilters(string slnfValue, string exceptionReason)
        {
            Assert.False(File.Exists("C:\\notAPath2\\MSBuild.Dev.sln"));
            using (TestEnvironment testEnvironment = TestEnvironment.Create())
            {
                TransientTestFolder folder = testEnvironment.CreateFolder(createFolder: true);
                TransientTestFile sln = testEnvironment.CreateFile(folder, "Dev.sln");
                TransientTestFile slnf = testEnvironment.CreateFile(folder, "Dev.slnf", slnfValue.Replace(@"C:\\notAPath\\MSBuild.Dev.sln", sln.Path.Replace("\\", "\\\\")));
                InvalidProjectFileException e = Should.Throw<InvalidProjectFileException>(() => SolutionFile.Parse(slnf.Path));
                e.HelpKeyword.ShouldBe(exceptionReason);
            }
        }

        /// <summary>
        /// Test that a project with the C++ project guid and an extension of vcproj is seen as invalid.
        /// </summary>
        [Fact]
        public void ParseSolution_VC()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                string solutionFileContents =
                    @"
                Microsoft Visual Studio Solution File, Format Version 9.00
                # Visual Studio 2005
                Project('{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}') = 'Project name.vcproj', 'Relative path\to\Project name.vcproj', '{0ABED153-9451-483C-8140-9E8D7306B216}'
                EndProject
                Global
                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
                        Debug|AnyCPU = Debug|AnyCPU
                        Release|AnyCPU = Release|AnyCPU
                    EndGlobalSection
                    GlobalSection(ProjectConfigurationPlatforms) = postSolution
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Debug|AnyCPU.ActiveCfg = Debug|AnyCPU
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Debug|AnyCPU.Build.0 = Debug|AnyCPU
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Release|AnyCPU.ActiveCfg = Release|AnyCPU
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Release|AnyCPU.Build.0 = Release|AnyCPU
                    EndGlobalSection
                    GlobalSection(SolutionProperties) = preSolution
                        HideSolutionNode = FALSE
                    EndGlobalSection
                EndGlobal
                ";

                ParseSolutionHelper(solutionFileContents);
                Assert.True(false, "Should not get here");
            }
           );
        }
        /// <summary>
        /// Test that a project with the C++ project guid and an arbitrary extension is seen as valid -- 
        /// we assume that all C++ projects except .vcproj are MSBuild format. 
        /// </summary>
        [Fact]
        public void ParseSolution_VC2()
        {
            string solutionFileContents =
                @"
                Microsoft Visual Studio Solution File, Format Version 9.00
                # Visual Studio 2005
                Project('{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}') = 'Project name.myvctype', 'Relative path\to\Project name.myvctype', '{0ABED153-9451-483C-8140-9E8D7306B216}'
                EndProject
                Global
                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
                        Debug|AnyCPU = Debug|AnyCPU
                        Release|AnyCPU = Release|AnyCPU
                    EndGlobalSection
                    GlobalSection(ProjectConfigurationPlatforms) = postSolution
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Debug|AnyCPU.ActiveCfg = Debug|AnyCPU
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Debug|AnyCPU.Build.0 = Debug|AnyCPU
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Release|AnyCPU.ActiveCfg = Release|AnyCPU
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Release|AnyCPU.Build.0 = Release|AnyCPU
                    EndGlobalSection
                    GlobalSection(SolutionProperties) = preSolution
                        HideSolutionNode = FALSE
                    EndGlobalSection
                EndGlobal
                ";

            SolutionFile solution = ParseSolutionHelper(solutionFileContents);

            Assert.Equal("Project name.myvctype", solution.ProjectsInOrder[0].ProjectName);
            Assert.Equal("Relative path\\to\\Project name.myvctype", solution.ProjectsInOrder[0].RelativePath);
            Assert.Equal("{0ABED153-9451-483C-8140-9E8D7306B216}", solution.ProjectsInOrder[0].ProjectGuid);
        }

        /// <summary>
        /// A slightly more complicated test where there is some different whitespace.
        /// </summary>
        [Fact]
        public void ParseSolutionWithDifferentSpacing()
        {
            string solutionFileContents =
                @"
                Microsoft Visual Studio Solution File, Format Version 9.00
                # Visual Studio 2005
                Project(' { Project GUID} ')  = ' Project name ',  ' Relative path to project file '    , ' {0ABED153-9451-483C-8140-9E8D7306B216} '
                EndProject
                Global
                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
                        Debug|AnyCPU = Debug|AnyCPU
                        Release|AnyCPU = Release|AnyCPU
                    EndGlobalSection
                    GlobalSection(ProjectConfigurationPlatforms) = postSolution
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Debug|AnyCPU.ActiveCfg = Debug|AnyCPU
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Debug|AnyCPU.Build.0 = Debug|AnyCPU
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Release|AnyCPU.ActiveCfg = Release|AnyCPU
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Release|AnyCPU.Build.0 = Release|AnyCPU
                    EndGlobalSection
                    GlobalSection(SolutionProperties) = preSolution
                        HideSolutionNode = FALSE
                    EndGlobalSection
                EndGlobal
                ";

            SolutionFile solution = ParseSolutionHelper(solutionFileContents);

            Assert.Equal("Project name", solution.ProjectsInOrder[0].ProjectName);
            Assert.Equal("Relative path to project file", solution.ProjectsInOrder[0].RelativePath);
            Assert.Equal("{0ABED153-9451-483C-8140-9E8D7306B216}", solution.ProjectsInOrder[0].ProjectGuid);
        }

        /// <summary>
        /// Solution with an empty project name.  This is somewhat malformed, but we should
        /// still behave reasonably instead of crashing.
        /// </summary>
        [Fact]
        public void ParseSolution_EmptyProjectName()
        {
            string solutionFileContents =
                           @"
                Microsoft Visual Studio Solution File, Format Version 9.00
                # Visual Studio 2005
                Project('{Project GUID}') = '', 'src\.proj', '{0ABED153-9451-483C-8140-9E8D7306B216}'
                EndProject
                Global
                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
                        Debug|AnyCPU = Debug|AnyCPU
                        Release|AnyCPU = Release|AnyCPU
                    EndGlobalSection
                    GlobalSection(ProjectConfigurationPlatforms) = postSolution
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Debug|AnyCPU.ActiveCfg = Debug|AnyCPU
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Debug|AnyCPU.Build.0 = Debug|AnyCPU
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Release|AnyCPU.ActiveCfg = Release|AnyCPU
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Release|AnyCPU.Build.0 = Release|AnyCPU
                    EndGlobalSection
                    GlobalSection(SolutionProperties) = preSolution
                        HideSolutionNode = FALSE
                    EndGlobalSection
                EndGlobal
                ";

            SolutionFile solution = ParseSolutionHelper(solutionFileContents);

            Assert.StartsWith("EmptyProjectName", solution.ProjectsInOrder[0].ProjectName);
            Assert.Equal("src\\.proj", solution.ProjectsInOrder[0].RelativePath);
            Assert.Equal("{0ABED153-9451-483C-8140-9E8D7306B216}", solution.ProjectsInOrder[0].ProjectGuid);
        }

        /// <summary>
        /// Test some characters that are valid in a file name but that also could be
        /// considered a delimiter by a parser. Does quoting work for special characters?
        /// </summary>
        [Fact]
        public void ParseSolutionWhereProjectNameHasSpecialCharacters()
        {
            string solutionFileContents =
                           @"
                Microsoft Visual Studio Solution File, Format Version 9.00
                # Visual Studio 2005
                Project('{Project GUID}')  = 'MyProject,(=IsGreat)',  'Relative path to project file'    , '{0ABED153-9451-483C-8140-9E8D7306B216}'
                EndProject
                Global
                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
                        Debug|AnyCPU = Debug|AnyCPU
                        Release|AnyCPU = Release|AnyCPU
                    EndGlobalSection
                    GlobalSection(ProjectConfigurationPlatforms) = postSolution
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Debug|AnyCPU.ActiveCfg = Debug|AnyCPU
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Debug|AnyCPU.Build.0 = Debug|AnyCPU
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Release|AnyCPU.ActiveCfg = Release|AnyCPU
                        {0ABED153-9451-483C-8140-9E8D7306B216}.Release|AnyCPU.Build.0 = Release|AnyCPU
                    EndGlobalSection
                    GlobalSection(SolutionProperties) = preSolution
                        HideSolutionNode = FALSE
                    EndGlobalSection
                EndGlobal
                ";

            SolutionFile solution = ParseSolutionHelper(solutionFileContents);

            Assert.Equal("MyProject,(=IsGreat)", solution.ProjectsInOrder[0].ProjectName);
            Assert.Equal("Relative path to project file", solution.ProjectsInOrder[0].RelativePath);
            Assert.Equal("{0ABED153-9451-483C-8140-9E8D7306B216}", solution.ProjectsInOrder[0].ProjectGuid);
        }

        /// <summary>
        /// Ensure that a bogus version stamp in the .SLN file results in an
        /// InvalidProjectFileException.
        /// </summary>
        [Fact]
        public void BadVersionStamp()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                string solutionFileContents =
                    @"
                Microsoft Visual Studio Solution File, Format Version a.b
                # Visual Studio 2005
                ";

                ParseSolutionHelper(solutionFileContents);
            }
           );
        }
        /// <summary>
        /// Expected version numbers less than 7 to cause an invalid project file exception.
        /// </summary>
        [Fact]
        public void VersionTooLow()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                string solutionFileContents =
                    @"
                Microsoft Visual Studio Solution File, Format Version 6.0
                # Visual Studio 2005
                ";

                ParseSolutionHelper(solutionFileContents);
            }
           );
        }
        /// <summary>
        /// Test to parse a very basic .sln file to validate that description property in a solution file 
        /// is properly handled.
        /// </summary>
        [Fact]
        public void ParseSolutionFileWithDescriptionInformation()
        {
            string solutionFileContents =
                @"
                Microsoft Visual Studio Solution File, Format Version 9.00
                # Visual Studio 2005
                Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'AnyProject', 'AnyProject\AnyProject.csproj', '{2CAB0FBD-15D8-458B-8E63-1B5B840E9798}'
                EndProject
                Global
	                GlobalSection(SolutionConfigurationPlatforms) = preSolution
		                Debug|Any CPU = Debug|Any CPU
		                Release|Any CPU = Release|Any CPU
		                Description = Some description of this solution
	                EndGlobalSection
	                GlobalSection(ProjectConfigurationPlatforms) = postSolution
		                {2CAB0FBD-15D8-458B-8E63-1B5B840E9798}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		                {2CAB0FBD-15D8-458B-8E63-1B5B840E9798}.Debug|Any CPU.Build.0 = Debug|Any CPU
		                {2CAB0FBD-15D8-458B-8E63-1B5B840E9798}.Release|Any CPU.ActiveCfg = Release|Any CPU
		                {2CAB0FBD-15D8-458B-8E63-1B5B840E9798}.Release|Any CPU.Build.0 = Release|Any CPU
	                EndGlobalSection
	                GlobalSection(SolutionProperties) = preSolution
		                HideSolutionNode = FALSE
	                EndGlobalSection
                EndGlobal
                ";
            try
            {
                ParseSolutionHelper(solutionFileContents);
            }
            catch (Exception ex)
            {
                Assert.True(false, "Failed to parse solution containing description information. Error: " + ex.Message);
            }
        }

        /// <summary>
        /// Tests the parsing of a very basic .SLN file with three independent projects.
        /// </summary>
        [Fact]
        public void BasicSolution()
        {
            string solutionFileContents =
                @"
                Microsoft Visual Studio Solution File, Format Version 9.00
                # Visual Studio 2005
                Project('{F184B08F-C81C-45F6-A57F-5ABD9991F28F}') = 'ConsoleApplication1', 'ConsoleApplication1\ConsoleApplication1.vbproj', '{AB3413A6-D689-486D-B7F0-A095371B3F13}'
                EndProject
                Project('{F184B08F-C81C-45F6-A57F-5ABD9991F28F}') = 'vbClassLibrary', 'vbClassLibrary\vbClassLibrary.vbproj', '{BA333A76-4511-47B8-8DF4-CA51C303AD0B}'
                EndProject
                Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'ClassLibrary1\ClassLibrary1.csproj', '{DEBCE986-61B9-435E-8018-44B9EF751655}'
                EndProject
                Global
                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
                        Debug|AnyCPU = Debug|AnyCPU
                        Release|AnyCPU = Release|AnyCPU
                    EndGlobalSection
                    GlobalSection(ProjectConfigurationPlatforms) = postSolution
                        {AB3413A6-D689-486D-B7F0-A095371B3F13}.Debug|AnyCPU.ActiveCfg = Debug|AnyCPU
                        {AB3413A6-D689-486D-B7F0-A095371B3F13}.Debug|AnyCPU.Build.0 = Debug|AnyCPU
                        {AB3413A6-D689-486D-B7F0-A095371B3F13}.Release|AnyCPU.ActiveCfg = Release|AnyCPU
                        {AB3413A6-D689-486D-B7F0-A095371B3F13}.Release|AnyCPU.Build.0 = Release|AnyCPU
                        {BA333A76-4511-47B8-8DF4-CA51C303AD0B}.Debug|AnyCPU.ActiveCfg = Debug|AnyCPU
                        {BA333A76-4511-47B8-8DF4-CA51C303AD0B}.Debug|AnyCPU.Build.0 = Debug|AnyCPU
                        {BA333A76-4511-47B8-8DF4-CA51C303AD0B}.Release|AnyCPU.ActiveCfg = Release|AnyCPU
                        {BA333A76-4511-47B8-8DF4-CA51C303AD0B}.Release|AnyCPU.Build.0 = Release|AnyCPU
                        {DEBCE986-61B9-435E-8018-44B9EF751655}.Debug|AnyCPU.ActiveCfg = Debug|AnyCPU
                        {DEBCE986-61B9-435E-8018-44B9EF751655}.Debug|AnyCPU.Build.0 = Debug|AnyCPU
                        {DEBCE986-61B9-435E-8018-44B9EF751655}.Release|AnyCPU.ActiveCfg = Release|AnyCPU
                        {DEBCE986-61B9-435E-8018-44B9EF751655}.Release|AnyCPU.Build.0 = Release|AnyCPU
                    EndGlobalSection
                    GlobalSection(SolutionProperties) = preSolution
                        HideSolutionNode = FALSE
                    EndGlobalSection
                EndGlobal
                ";

            SolutionFile solution = ParseSolutionHelper(solutionFileContents);

            Assert.Equal(3, solution.ProjectsInOrder.Count);

            Assert.Equal("ConsoleApplication1", solution.ProjectsInOrder[0].ProjectName);
            Assert.Equal(@"ConsoleApplication1\ConsoleApplication1.vbproj", solution.ProjectsInOrder[0].RelativePath);
            Assert.Equal("{AB3413A6-D689-486D-B7F0-A095371B3F13}", solution.ProjectsInOrder[0].ProjectGuid);
            Assert.Empty(solution.ProjectsInOrder[0].Dependencies);
            Assert.Null(solution.ProjectsInOrder[0].ParentProjectGuid);

            Assert.Equal("vbClassLibrary", solution.ProjectsInOrder[1].ProjectName);
            Assert.Equal(@"vbClassLibrary\vbClassLibrary.vbproj", solution.ProjectsInOrder[1].RelativePath);
            Assert.Equal("{BA333A76-4511-47B8-8DF4-CA51C303AD0B}", solution.ProjectsInOrder[1].ProjectGuid);
            Assert.Empty(solution.ProjectsInOrder[1].Dependencies);
            Assert.Null(solution.ProjectsInOrder[1].ParentProjectGuid);

            Assert.Equal("ClassLibrary1", solution.ProjectsInOrder[2].ProjectName);
            Assert.Equal(@"ClassLibrary1\ClassLibrary1.csproj", solution.ProjectsInOrder[2].RelativePath);
            Assert.Equal("{DEBCE986-61B9-435E-8018-44B9EF751655}", solution.ProjectsInOrder[2].ProjectGuid);
            Assert.Empty(solution.ProjectsInOrder[2].Dependencies);
            Assert.Null(solution.ProjectsInOrder[2].ParentProjectGuid);
        }

        /// <summary>
        /// Exercises solution folders, and makes sure that samely named projects in different
        /// solution folders will get correctly uniquified.
        /// </summary>
        [Fact]
        public void SolutionFolders()
        {
            string solutionFileContents =
                @"
                Microsoft Visual Studio Solution File, Format Version 9.00
                # Visual Studio 2005
                Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'ClassLibrary1\ClassLibrary1.csproj', '{34E0D07D-CF8F-459D-9449-C4188D8C5564}'
                EndProject
                Project('{2150E333-8FDC-42A3-9474-1A3956D46DE8}') = 'MySlnFolder', 'MySlnFolder', '{E0F97730-25D2-418A-A7BD-02CAFDC6E470}'
                EndProject
                Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'MyPhysicalFolder\ClassLibrary1\ClassLibrary1.csproj', '{A5EE8128-B08E-4533-86C5-E46714981680}'
                EndProject
                Project('{2150E333-8FDC-42A3-9474-1A3956D46DE8}') = 'MySubSlnFolder', 'MySubSlnFolder', '{2AE8D6C4-FB43-430C-8AEB-15E5EEDAAE4B}'
                EndProject
                Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary2', 'ClassLibrary2\ClassLibrary2.csproj', '{6DB98C35-FDCC-4818-B5D4-1F0A385FDFD4}'
                EndProject
                Global
                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
                        Debug|Any CPU = Debug|Any CPU
                        Release|Any CPU = Release|Any CPU
                    EndGlobalSection
                    GlobalSection(ProjectConfigurationPlatforms) = postSolution
                        {34E0D07D-CF8F-459D-9449-C4188D8C5564}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                        {34E0D07D-CF8F-459D-9449-C4188D8C5564}.Debug|Any CPU.Build.0 = Debug|Any CPU
                        {34E0D07D-CF8F-459D-9449-C4188D8C5564}.Release|Any CPU.ActiveCfg = Release|Any CPU
                        {34E0D07D-CF8F-459D-9449-C4188D8C5564}.Release|Any CPU.Build.0 = Release|Any CPU
                        {A5EE8128-B08E-4533-86C5-E46714981680}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                        {A5EE8128-B08E-4533-86C5-E46714981680}.Debug|Any CPU.Build.0 = Debug|Any CPU
                        {A5EE8128-B08E-4533-86C5-E46714981680}.Release|Any CPU.ActiveCfg = Release|Any CPU
                        {A5EE8128-B08E-4533-86C5-E46714981680}.Release|Any CPU.Build.0 = Release|Any CPU
                        {6DB98C35-FDCC-4818-B5D4-1F0A385FDFD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                        {6DB98C35-FDCC-4818-B5D4-1F0A385FDFD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
                        {6DB98C35-FDCC-4818-B5D4-1F0A385FDFD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
                        {6DB98C35-FDCC-4818-B5D4-1F0A385FDFD4}.Release|Any CPU.Build.0 = Release|Any CPU
                    EndGlobalSection
                    GlobalSection(SolutionProperties) = preSolution
                        HideSolutionNode = FALSE
                    EndGlobalSection
                    GlobalSection(NestedProjects) = preSolution
                        {A5EE8128-B08E-4533-86C5-E46714981680} = {E0F97730-25D2-418A-A7BD-02CAFDC6E470}
                        {2AE8D6C4-FB43-430C-8AEB-15E5EEDAAE4B} = {E0F97730-25D2-418A-A7BD-02CAFDC6E470}
                        {6DB98C35-FDCC-4818-B5D4-1F0A385FDFD4} = {2AE8D6C4-FB43-430C-8AEB-15E5EEDAAE4B}
                    EndGlobalSection
                EndGlobal
                ";

            SolutionFile solution = ParseSolutionHelper(solutionFileContents);

            Assert.Equal(5, solution.ProjectsInOrder.Count);

            Assert.Equal(@"ClassLibrary1\ClassLibrary1.csproj", solution.ProjectsInOrder[0].RelativePath);
            Assert.Equal("{34E0D07D-CF8F-459D-9449-C4188D8C5564}", solution.ProjectsInOrder[0].ProjectGuid);
            Assert.Empty(solution.ProjectsInOrder[0].Dependencies);
            Assert.Null(solution.ProjectsInOrder[0].ParentProjectGuid);

            Assert.Equal("{E0F97730-25D2-418A-A7BD-02CAFDC6E470}", solution.ProjectsInOrder[1].ProjectGuid);
            Assert.Empty(solution.ProjectsInOrder[1].Dependencies);
            Assert.Null(solution.ProjectsInOrder[1].ParentProjectGuid);

            Assert.Equal(@"MyPhysicalFolder\ClassLibrary1\ClassLibrary1.csproj", solution.ProjectsInOrder[2].RelativePath);
            Assert.Equal("{A5EE8128-B08E-4533-86C5-E46714981680}", solution.ProjectsInOrder[2].ProjectGuid);
            Assert.Empty(solution.ProjectsInOrder[2].Dependencies);
            Assert.Equal("{E0F97730-25D2-418A-A7BD-02CAFDC6E470}", solution.ProjectsInOrder[2].ParentProjectGuid);

            Assert.Equal("{2AE8D6C4-FB43-430C-8AEB-15E5EEDAAE4B}", solution.ProjectsInOrder[3].ProjectGuid);
            Assert.Empty(solution.ProjectsInOrder[3].Dependencies);
            Assert.Equal("{E0F97730-25D2-418A-A7BD-02CAFDC6E470}", solution.ProjectsInOrder[3].ParentProjectGuid);

            Assert.Equal(@"ClassLibrary2\ClassLibrary2.csproj", solution.ProjectsInOrder[4].RelativePath);
            Assert.Equal("{6DB98C35-FDCC-4818-B5D4-1F0A385FDFD4}", solution.ProjectsInOrder[4].ProjectGuid);
            Assert.Empty(solution.ProjectsInOrder[4].Dependencies);
            Assert.Equal("{2AE8D6C4-FB43-430C-8AEB-15E5EEDAAE4B}", solution.ProjectsInOrder[4].ParentProjectGuid);
        }

        /// <summary>
        /// Exercises shared projects.
        /// </summary>
        [Fact]
        public void SharedProjects()
        {
            string solutionFileContents =
                @"
                Microsoft Visual Studio Solution File, Format Version 12.00
                # Visual Studio 15
                VisualStudioVersion = 15.0.27610.1
                MinimumVisualStudioVersion = 10.0.40219.1
                Project('{D954291E-2A0B-460D-934E-DC6B0785DB48}') = 'SharedProject1', 'SharedProject1\SharedProject1.shproj', '{14686F51-D0C2-4832-BBAA-6FBAEC676995}'
                EndProject
                Project('{D954291E-2A0B-460D-934E-DC6B0785DB48}') = 'SharedProject2', 'SharedProject2\SharedProject2.shproj', '{BAE750E8-4656-4947-B06B-3961E1051DF7}'
                EndProject
                Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'ClassLibrary1\ClassLibrary1.csproj', '{3A0EC360-A42A-417F-BDEF-619682CF6119}'
                EndProject
                Project('{F184B08F-C81C-45F6-A57F-5ABD9991F28F}') = 'ClassLibrary2', 'ClassLibrary2\ClassLibrary2.vbproj', '{6DEF6DE8-FBF0-4240-B469-282DEE87899C}'
                EndProject
                Global
                    GlobalSection(SharedMSBuildProjectFiles) = preSolution
                        SharedProject1\SharedProject1.projitems*{14686f51-d0c2-4832-bbaa-6fbaec676995}*SharedItemsImports = 13
                        SharedProject1\SharedProject1.projitems*{3a0ec360-a42a-417f-bdef-619682cf6119}*SharedItemsImports = 4
                        SharedProject2\SharedProject2.projitems*{6def6de8-fbf0-4240-b469-282dee87899c}*SharedItemsImports = 4
                        SharedProject2\SharedProject2.projitems*{bae750e8-4656-4947-b06b-3961e1051df7}*SharedItemsImports = 13
                    EndGlobalSection
                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
                        Debug|Any CPU = Debug|Any CPU
                        Release|Any CPU = Release|Any CPU
                    EndGlobalSection
                    GlobalSection(ProjectConfigurationPlatforms) = postSolution
                        {3A0EC360-A42A-417F-BDEF-619682CF6119}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                        {3A0EC360-A42A-417F-BDEF-619682CF6119}.Debug|Any CPU.Build.0 = Debug|Any CPU
                        {3A0EC360-A42A-417F-BDEF-619682CF6119}.Release|Any CPU.ActiveCfg = Release|Any CPU
                        {3A0EC360-A42A-417F-BDEF-619682CF6119}.Release|Any CPU.Build.0 = Release|Any CPU
                        {6DEF6DE8-FBF0-4240-B469-282DEE87899C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                        {6DEF6DE8-FBF0-4240-B469-282DEE87899C}.Debug|Any CPU.Build.0 = Debug|Any CPU
                        {6DEF6DE8-FBF0-4240-B469-282DEE87899C}.Release|Any CPU.ActiveCfg = Release|Any CPU
                        {6DEF6DE8-FBF0-4240-B469-282DEE87899C}.Release|Any CPU.Build.0 = Release|Any CPU
                    EndGlobalSection
                    GlobalSection(SolutionProperties) = preSolution
                        HideSolutionNode = FALSE
                    EndGlobalSection
                    GlobalSection(ExtensibilityGlobals) = postSolution
                        SolutionGuid = {1B671EF6-A62A-4497-8351-3EE8679CA86F}
                    EndGlobalSection
                EndGlobal
                ";

            SolutionFile solution = ParseSolutionHelper(solutionFileContents);

            Assert.Equal(4, solution.ProjectsInOrder.Count);

            Assert.Equal(@"SharedProject1\SharedProject1.shproj", solution.ProjectsInOrder[0].RelativePath);
            Assert.Equal("{14686F51-D0C2-4832-BBAA-6FBAEC676995}", solution.ProjectsInOrder[0].ProjectGuid);
            Assert.Empty(solution.ProjectsInOrder[0].Dependencies);
            Assert.Null(solution.ProjectsInOrder[0].ParentProjectGuid);

            Assert.Equal(@"SharedProject2\SharedProject2.shproj", solution.ProjectsInOrder[1].RelativePath);
            Assert.Equal("{BAE750E8-4656-4947-B06B-3961E1051DF7}", solution.ProjectsInOrder[1].ProjectGuid);
            Assert.Empty(solution.ProjectsInOrder[1].Dependencies);
            Assert.Null(solution.ProjectsInOrder[1].ParentProjectGuid);

            Assert.Equal(@"ClassLibrary1\ClassLibrary1.csproj", solution.ProjectsInOrder[2].RelativePath);
            Assert.Equal("{3A0EC360-A42A-417F-BDEF-619682CF6119}", solution.ProjectsInOrder[2].ProjectGuid);
            Assert.Empty(solution.ProjectsInOrder[2].Dependencies);
            Assert.Null(solution.ProjectsInOrder[2].ParentProjectGuid);

            Assert.Equal(@"ClassLibrary2\ClassLibrary2.vbproj", solution.ProjectsInOrder[3].RelativePath);
            Assert.Equal("{6DEF6DE8-FBF0-4240-B469-282DEE87899C}", solution.ProjectsInOrder[3].ProjectGuid);
            Assert.Empty(solution.ProjectsInOrder[3].Dependencies);
            Assert.Null(solution.ProjectsInOrder[3].ParentProjectGuid);
        }

        /// <summary>
        /// Tests situation where there's a nonexistent project listed in the solution folders.  We should 
        /// error with a useful message. 
        /// </summary>
        [Fact]
        public void MissingNestedProject()
        {
            string solutionFileContents =
                @"
                Microsoft Visual Studio Solution File, Format Version 9.00
                # Visual Studio 2005
                Project('{2150E333-8FDC-42A3-9474-1A3956D46DE8}') = 'MySlnFolder', 'MySlnFolder', '{E0F97730-25D2-418A-A7BD-02CAFDC6E470}'
                EndProject
                Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'MyPhysicalFolder\ClassLibrary1\ClassLibrary1.csproj', '{A5EE8128-B08E-4533-86C5-E46714981680}'
                EndProject
                Global
                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
                        Debug|Any CPU = Debug|Any CPU
                        Release|Any CPU = Release|Any CPU
                    EndGlobalSection
                    GlobalSection(ProjectConfigurationPlatforms) = postSolution
                        {34E0D07D-CF8F-459D-9449-C4188D8C5564}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                        {34E0D07D-CF8F-459D-9449-C4188D8C5564}.Debug|Any CPU.Build.0 = Debug|Any CPU
                        {34E0D07D-CF8F-459D-9449-C4188D8C5564}.Release|Any CPU.ActiveCfg = Release|Any CPU
                        {34E0D07D-CF8F-459D-9449-C4188D8C5564}.Release|Any CPU.Build.0 = Release|Any CPU
                        {A5EE8128-B08E-4533-86C5-E46714981680}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                        {A5EE8128-B08E-4533-86C5-E46714981680}.Debug|Any CPU.Build.0 = Debug|Any CPU
                        {A5EE8128-B08E-4533-86C5-E46714981680}.Release|Any CPU.ActiveCfg = Release|Any CPU
                        {A5EE8128-B08E-4533-86C5-E46714981680}.Release|Any CPU.Build.0 = Release|Any CPU
                        {6DB98C35-FDCC-4818-B5D4-1F0A385FDFD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                        {6DB98C35-FDCC-4818-B5D4-1F0A385FDFD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
                        {6DB98C35-FDCC-4818-B5D4-1F0A385FDFD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
                        {6DB98C35-FDCC-4818-B5D4-1F0A385FDFD4}.Release|Any CPU.Build.0 = Release|Any CPU
                    EndGlobalSection
                    GlobalSection(SolutionProperties) = preSolution
                        HideSolutionNode = FALSE
                    EndGlobalSection
                    GlobalSection(NestedProjects) = preSolution
                        {A5EE8128-B08E-4533-86C5-E46714981680} = {E0F97730-25D2-418A-A7BD-02CAFDC6E470}
                        {2AE8D6C4-FB43-430C-8AEB-15E5EEDAAE4B} = {E0F97730-25D2-418A-A7BD-02CAFDC6E470}
                    EndGlobalSection
                EndGlobal
                ";

            try
            {
                ParseSolutionHelper(solutionFileContents);
            }
            catch (InvalidProjectFileException e)
            {
                Assert.Equal("MSB5023", e.ErrorCode);
                Assert.Contains("{2AE8D6C4-FB43-430C-8AEB-15E5EEDAAE4B}", e.Message);
                return;
            }

            // Should not get here
            Assert.True(false);
        }

        /// <summary>
        /// Verifies that hand-coded project-to-project dependencies listed in the .SLN file
        /// are correctly recognized by our solution parser.
        /// </summary>
        [Fact]
        public void SolutionDependencies()
        {
            string solutionFileContents =
                @"
                Microsoft Visual Studio Solution File, Format Version 9.00
                # Visual Studio 2005
                Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'ClassLibrary1\ClassLibrary1.csproj', '{05A5AD00-71B5-4612-AF2F-9EA9121C4111}'
                    ProjectSection(ProjectDependencies) = postProject
                        {FAB4EE06-6E01-495A-8926-5514599E3DD9} = {FAB4EE06-6E01-495A-8926-5514599E3DD9}
                    EndProjectSection
                EndProject
                Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary2', 'ClassLibrary2\ClassLibrary2.csproj', '{7F316407-AE3E-4F26-BE61-2C50D30DA158}'
                    ProjectSection(ProjectDependencies) = postProject
                        {FAB4EE06-6E01-495A-8926-5514599E3DD9} = {FAB4EE06-6E01-495A-8926-5514599E3DD9}
                        {05A5AD00-71B5-4612-AF2F-9EA9121C4111} = {05A5AD00-71B5-4612-AF2F-9EA9121C4111}
                    EndProjectSection
                EndProject
                Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary3', 'ClassLibrary3\ClassLibrary3.csproj', '{FAB4EE06-6E01-495A-8926-5514599E3DD9}'
                EndProject
                Global
                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
                        Debug|Any CPU = Debug|Any CPU
                        Release|Any CPU = Release|Any CPU
                    EndGlobalSection
                    GlobalSection(ProjectConfigurationPlatforms) = postSolution
                        {05A5AD00-71B5-4612-AF2F-9EA9121C4111}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                        {05A5AD00-71B5-4612-AF2F-9EA9121C4111}.Debug|Any CPU.Build.0 = Debug|Any CPU
                        {05A5AD00-71B5-4612-AF2F-9EA9121C4111}.Release|Any CPU.ActiveCfg = Release|Any CPU
                        {05A5AD00-71B5-4612-AF2F-9EA9121C4111}.Release|Any CPU.Build.0 = Release|Any CPU
                        {7F316407-AE3E-4F26-BE61-2C50D30DA158}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                        {7F316407-AE3E-4F26-BE61-2C50D30DA158}.Debug|Any CPU.Build.0 = Debug|Any CPU
                        {7F316407-AE3E-4F26-BE61-2C50D30DA158}.Release|Any CPU.ActiveCfg = Release|Any CPU
                        {7F316407-AE3E-4F26-BE61-2C50D30DA158}.Release|Any CPU.Build.0 = Release|Any CPU
                        {FAB4EE06-6E01-495A-8926-5514599E3DD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                        {FAB4EE06-6E01-495A-8926-5514599E3DD9}.Debug|Any CPU.Build.0 = Debug|Any CPU
                        {FAB4EE06-6E01-495A-8926-5514599E3DD9}.Release|Any CPU.ActiveCfg = Release|Any CPU
                        {FAB4EE06-6E01-495A-8926-5514599E3DD9}.Release|Any CPU.Build.0 = Release|Any CPU
                    EndGlobalSection
                    GlobalSection(SolutionProperties) = preSolution
                        HideSolutionNode = FALSE
                    EndGlobalSection
                EndGlobal
                ";

            SolutionFile solution = ParseSolutionHelper(solutionFileContents);

            Assert.Equal(3, solution.ProjectsInOrder.Count);

            Assert.Equal(@"ClassLibrary1\ClassLibrary1.csproj", solution.ProjectsInOrder[0].RelativePath);
            Assert.Equal("{05A5AD00-71B5-4612-AF2F-9EA9121C4111}", solution.ProjectsInOrder[0].ProjectGuid);
            Assert.Single(solution.ProjectsInOrder[0].Dependencies);
            Assert.Equal("{FAB4EE06-6E01-495A-8926-5514599E3DD9}", (string)solution.ProjectsInOrder[0].Dependencies[0]);
            Assert.Null(solution.ProjectsInOrder[0].ParentProjectGuid);

            Assert.Equal(@"ClassLibrary2\ClassLibrary2.csproj", solution.ProjectsInOrder[1].RelativePath);
            Assert.Equal("{7F316407-AE3E-4F26-BE61-2C50D30DA158}", solution.ProjectsInOrder[1].ProjectGuid);
            Assert.Equal(2, solution.ProjectsInOrder[1].Dependencies.Count);
            Assert.Equal("{FAB4EE06-6E01-495A-8926-5514599E3DD9}", (string)solution.ProjectsInOrder[1].Dependencies[0]);
            Assert.Equal("{05A5AD00-71B5-4612-AF2F-9EA9121C4111}", (string)solution.ProjectsInOrder[1].Dependencies[1]);
            Assert.Null(solution.ProjectsInOrder[1].ParentProjectGuid);

            Assert.Equal(@"ClassLibrary3\ClassLibrary3.csproj", solution.ProjectsInOrder[2].RelativePath);
            Assert.Equal("{FAB4EE06-6E01-495A-8926-5514599E3DD9}", solution.ProjectsInOrder[2].ProjectGuid);
            Assert.Empty(solution.ProjectsInOrder[2].Dependencies);
            Assert.Null(solution.ProjectsInOrder[2].ParentProjectGuid);
        }

        /// <summary>
        /// Make sure the solution configurations get parsed correctly for a simple mixed C#/VC solution
        /// </summary>
        [Fact]
        public void ParseSolutionConfigurations()
        {
            string solutionFileContents =
                @"
                Microsoft Visual Studio Solution File, Format Version 9.00
                # Visual Studio 2005
                Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'ClassLibrary1\ClassLibrary1.csproj', '{6185CC21-BE89-448A-B3C0-D1C27112E595}'
                EndProject
                Project('{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}') = 'MainApp', 'MainApp\MainApp.vcxproj', '{A6F99D27-47B9-4EA4-BFC9-25157CBDC281}'
                EndProject
                Global
                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
                        Debug|ARM = Debug|ARM
                        Debug|Any CPU = Debug|Any CPU
                        Debug|Mixed Platforms = Debug|Mixed Platforms
                        Debug|Win32 = Debug|Win32
                        Release|Any CPU = Release|Any CPU
                        Release|Mixed Platforms = Release|Mixed Platforms
                        Release|Win32 = Release|Win32
                    EndGlobalSection
                    GlobalSection(ProjectConfigurationPlatforms) = postSolution
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|ARM.ActiveCfg = Debug|ARM
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|ARM.Build.0 = Debug|ARM
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.Build.0 = Debug|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Mixed Platforms.ActiveCfg = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Mixed Platforms.Build.0 = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Win32.ActiveCfg = Debug|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.ActiveCfg = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.Build.0 = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Mixed Platforms.Build.0 = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Win32.ActiveCfg = Release|Any CPU
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Debug|Any CPU.ActiveCfg = Debug|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Debug|Mixed Platforms.Build.0 = Debug|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Debug|Win32.ActiveCfg = Debug|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Debug|Win32.Build.0 = Debug|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Release|Any CPU.ActiveCfg = Release|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Release|Mixed Platforms.ActiveCfg = Release|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Release|Mixed Platforms.Build.0 = Release|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Release|Win32.ActiveCfg = Release|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Release|Win32.Build.0 = Release|Win32
                    EndGlobalSection
                    GlobalSection(SolutionProperties) = preSolution
                        HideSolutionNode = FALSE
                    EndGlobalSection
                EndGlobal
                ";

            SolutionFile solution = ParseSolutionHelper(solutionFileContents);

            Assert.Equal(7, solution.SolutionConfigurations.Count);

            List<string> configurationNames = new List<string>(6);
            foreach (SolutionConfigurationInSolution configuration in solution.SolutionConfigurations)
            {
                configurationNames.Add(configuration.FullName);
            }

            Assert.Contains("Debug|Any CPU", configurationNames);
            Assert.Contains("Debug|Mixed Platforms", configurationNames);
            Assert.Contains("Debug|Win32", configurationNames);
            Assert.Contains("Release|Any CPU", configurationNames);
            Assert.Contains("Release|Mixed Platforms", configurationNames);
            Assert.Contains("Release|Win32", configurationNames);

            Assert.Equal("Debug", solution.GetDefaultConfigurationName()); // "Default solution configuration"
            Assert.Equal("Mixed Platforms", solution.GetDefaultPlatformName()); // "Default solution platform"
        }

        /// <summary>
        /// Make sure the solution configurations get parsed correctly for a simple C# application
        /// </summary>
        [Fact]
        public void ParseSolutionConfigurationsNoMixedPlatform()
        {
            string solutionFileContents =
                @"
                Microsoft Visual Studio Solution File, Format Version 9.00
                # Visual Studio 2005
                Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'ClassLibrary1\ClassLibrary1.csproj', '{6185CC21-BE89-448A-B3C0-D1C27112E595}'
                EndProject
                Global
                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
                        Debug|ARM = Debug|ARM
                        Debug|Any CPU = Debug|Any CPU
                        Debug|x86 = Debug|x86
                        Release|ARM = Release|ARM
                        Release|Any CPU = Release|Any CPU
                        Release|x86 = Release|x86
                    EndGlobalSection
                    GlobalSection(ProjectConfigurationPlatforms) = postSolution
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.Build.0 = Debug|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|ARM.ActiveCfg = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|ARM.Build.0 = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|x86.ActiveCfg = Debug|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.ActiveCfg = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.Build.0 = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|ARM.ActiveCfg = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|ARM.Build.0 = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|x86.ActiveCfg = Release|Any CPU
                   EndGlobalSection
                    GlobalSection(SolutionProperties) = preSolution
                        HideSolutionNode = FALSE
                    EndGlobalSection
                EndGlobal
                ";

            SolutionFile solution = ParseSolutionHelper(solutionFileContents);

            Assert.Equal(6, solution.SolutionConfigurations.Count);

            List<string> configurationNames = new List<string>(6);
            foreach (SolutionConfigurationInSolution configuration in solution.SolutionConfigurations)
            {
                configurationNames.Add(configuration.FullName);
            }

            Assert.Contains("Debug|Any CPU", configurationNames);
            Assert.Contains("Debug|ARM", configurationNames);
            Assert.Contains("Debug|x86", configurationNames);
            Assert.Contains("Release|Any CPU", configurationNames);
            Assert.Contains("Release|ARM", configurationNames);
            Assert.Contains("Release|x86", configurationNames);

            Assert.Equal("Debug", solution.GetDefaultConfigurationName()); // "Default solution configuration"
            Assert.Equal("Any CPU", solution.GetDefaultPlatformName()); // "Default solution platform"
        }

        /// <summary>
        /// Test some invalid cases for solution configuration parsing.
        /// There can be only one '=' character in a sln cfg entry, separating two identical names
        /// </summary>
        [Fact]
        public void ParseInvalidSolutionConfigurations1()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                string solutionFileContents =
                    @"
                Microsoft Visual Studio Solution File, Format Version 9.00
                # Visual Studio 2005
                Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'ClassLibrary1\ClassLibrary1.csproj', '{6185CC21-BE89-448A-B3C0-D1C27112E595}'
                EndProject
                Global
                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
                        Debug|Any=CPU = Debug|Any=CPU
                        Release|Any CPU = Release|Any CPU
                    EndGlobalSection
                EndGlobal
                ";

                ParseSolutionHelper(solutionFileContents);
            }
           );
        }
        /// <summary>
        /// Test some invalid cases for solution configuration parsing
        /// There can be only one '=' character in a sln cfg entry, separating two identical names
        /// </summary>
        [Fact]
        public void ParseInvalidSolutionConfigurations2()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                string solutionFileContents =
                    @"
                Microsoft Visual Studio Solution File, Format Version 9.00
                # Visual Studio 2005
                Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'ClassLibrary1\ClassLibrary1.csproj', '{6185CC21-BE89-448A-B3C0-D1C27112E595}'
                EndProject
                Global
                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
                        Debug|Any CPU = Something|Else
                        Release|Any CPU = Release|Any CPU
                    EndGlobalSection
                EndGlobal
                ";

                ParseSolutionHelper(solutionFileContents);
            }
           );
        }
        /// <summary>
        /// Test some invalid cases for solution configuration parsing
        /// Solution configurations must include the platform part
        /// </summary>
        [Fact]
        public void ParseInvalidSolutionConfigurations3()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                string solutionFileContents =
                    @"
                Microsoft Visual Studio Solution File, Format Version 9.00
                # Visual Studio 2005
                Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'ClassLibrary1\ClassLibrary1.csproj', '{6185CC21-BE89-448A-B3C0-D1C27112E595}'
                EndProject
                Global
                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
                        Debug = Debug
                        Release|Any CPU = Release|Any CPU
                    EndGlobalSection
                EndGlobal
                ";

                ParseSolutionHelper(solutionFileContents);
            }
           );
        }
        /// <summary>
        /// Make sure the project configurations in solution configurations get parsed correctly 
        /// for a simple mixed C#/VC solution
        /// </summary>
        [Fact]
        public void ParseProjectConfigurationsInSolutionConfigurations1()
        {
            string solutionFileContents =
                @"
                Microsoft Visual Studio Solution File, Format Version 9.00
                # Visual Studio 2005
                Project('{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}') = 'ClassLibrary1', 'ClassLibrary1\ClassLibrary1.csproj', '{6185CC21-BE89-448A-B3C0-D1C27112E595}'
                EndProject
                Project('{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}') = 'MainApp', 'MainApp\MainApp.vcxproj', '{A6F99D27-47B9-4EA4-BFC9-25157CBDC281}'
                EndProject
                Global
                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
                        Debug|Any CPU = Debug|Any CPU
                        Debug|Mixed Platforms = Debug|Mixed Platforms
                        Debug|Win32 = Debug|Win32
                        Release|Any CPU = Release|Any CPU
                        Release|Mixed Platforms = Release|Mixed Platforms
                        Release|Win32 = Release|Win32
                    EndGlobalSection
                    GlobalSection(ProjectConfigurationPlatforms) = postSolution
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Any CPU.Build.0 = Debug|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Mixed Platforms.ActiveCfg = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Mixed Platforms.Build.0 = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Debug|Win32.ActiveCfg = Debug|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.ActiveCfg = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Any CPU.Build.0 = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Mixed Platforms.Build.0 = Release|Any CPU
                        {6185CC21-BE89-448A-B3C0-D1C27112E595}.Release|Win32.ActiveCfg = Release|Any CPU
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Debug|Any CPU.ActiveCfg = Debug|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Debug|Mixed Platforms.Build.0 = Debug|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Debug|Win32.ActiveCfg = Debug|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Debug|Win32.Build.0 = Debug|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Release|Any CPU.ActiveCfg = Release|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Release|Mixed Platforms.ActiveCfg = Release|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Release|Mixed Platforms.Build.0 = Release|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Release|Win32.ActiveCfg = Release|Win32
                        {A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Release|Win32.Build.0 = Release|Win32
                    EndGlobalSection
                    GlobalSection(SolutionProperties) = preSolution
                        HideSolutionNode = FALSE
                    EndGlobalSection
                EndGlobal
                ";

            SolutionFile solution = ParseSolutionHelper(solutionFileContents);

            ProjectInSolution csharpProject = (ProjectInSolution)solution.ProjectsByGuid["{6185CC21-BE89-448A-B3C0-D1C27112E595}"];
            ProjectInSolution vcProject = (ProjectInSolution)solution.ProjectsByGuid["{A6F99D27-47B9-4EA4-BFC9-25157CBDC281}"];

            Assert.Equal(6, csharpProject.ProjectConfigurations.Count);

            Assert.Equal("Debug|AnyCPU", csharpProject.ProjectConfigurations["Debug|Any CPU"].FullName);
            Assert.True(csharpProject.ProjectConfigurations["Debug|Any CPU"].IncludeInBuild);

            Assert.Equal("Release|AnyCPU", csharpProject.ProjectConfigurations["Debug|Mixed Platforms"].FullName);
            Assert.True(csharpProject.ProjectConfigurations["Debug|Mixed Platforms"].IncludeInBuild);

            Assert.Equal("Debug|AnyCPU", csharpProject.ProjectConfigurations["Debug|Win32"].FullName);
            Assert.False(csharpProject.ProjectConfigurations["Debug|Win32"].IncludeInBuild);

            Assert.Equal("Release|AnyCPU", csharpProject.ProjectConfigurations["Release|Any CPU"].FullName);
            Assert.True(csharpProject.ProjectConfigurations["Release|Any CPU"].IncludeInBuild);

            Assert.Equal("Release|AnyCPU", csharpProject.ProjectConfigurations["Release|Mixed Platforms"].FullName);
            Assert.True(csharpProject.ProjectConfigurations["Release|Mixed Platforms"].IncludeInBuild);

            Assert.Equal("Release|AnyCPU", csharpProject.ProjectConfigurations["Release|Win32"].FullName);
            Assert.False(csharpProject.ProjectConfigurations["Release|Win32"].IncludeInBuild);

            Assert.Equal(6, vcProject.ProjectConfigurations.Count);

            Assert.Equal("Debug|Win32", vcProject.ProjectConfigurations["Debug|Any CPU"].FullName);
            Assert.False(vcProject.ProjectConfigurations["Debug|Any CPU"].IncludeInBuild);

            Assert.Equal("Debug|Win32", vcProject.ProjectConfigurations["Debug|Mixed Platforms"].FullName);
            Assert.True(vcProject.ProjectConfigurations["Debug|Mixed Platforms"].IncludeInBuild);

            Assert.Equal("Debug|Win32", vcProject.ProjectConfigurations["Debug|Win32"].FullName);
            Assert.True(vcProject.ProjectConfigurations["Debug|Win32"].IncludeInBuild);

            Assert.Equal("Release|Win32", vcProject.ProjectConfigurations["Release|Any CPU"].FullName);
            Assert.False(vcProject.ProjectConfigurations["Release|Any CPU"].IncludeInBuild);

            Assert.Equal("Release|Win32", vcProject.ProjectConfigurations["Release|Mixed Platforms"].FullName);
            Assert.True(vcProject.ProjectConfigurations["Release|Mixed Platforms"].IncludeInBuild);

            Assert.Equal("Release|Win32", vcProject.ProjectConfigurations["Release|Win32"].FullName);
            Assert.True(vcProject.ProjectConfigurations["Release|Win32"].IncludeInBuild);
        }

        /// <summary>
        /// Make sure the project configurations in solution configurations get parsed correctly 
        /// for a more tricky solution
        /// </summary>
        [Fact]
        public void ParseProjectConfigurationsInSolutionConfigurations2()
        {
            string solutionFileContents =
                @"
                Microsoft Visual Studio Solution File, Format Version 9.00
                # Visual Studio 2005
                Project('{E24C65DC-7377-472B-9ABA-BC803B73C61A}') = 'C:\solutions\WebSite1\', '..\WebSite1\', '{E8E75132-67E4-4D6F-9CAE-8DA4C883F418}'
                EndProject
                Project('{E24C65DC-7377-472B-9ABA-BC803B73C61A}') = 'C:\solutions\WebSite2\', '..\WebSite2\', '{E8E75132-67E4-4D6F-9CAE-8DA4C883F419}'
                EndProject
                Project('{2150E333-8FDC-42A3-9474-1A3956D46DE8}') = 'NewFolder1', 'NewFolder1', '{54D20FFE-84BE-4066-A51E-B25D040A4235}'
                EndProject
                Project('{2150E333-8FDC-42A3-9474-1A3956D46DE8}') = 'NewFolder2', 'NewFolder2', '{D2633E4D-46FF-4C4E-8340-4BC7CDF78615}'
                EndProject
                Project('{8BC9CEB9-8B4A-11D0-8D11-00A0C91BC942}') = 'MSBuild.exe', '..\..\dd\binaries.x86dbg\bin\i386\MSBuild.exe', '{25FD9E7C-F37E-48E0-9A7C-607FE4AACCC0}'
                EndProject
                Global
                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
                        Debug|.NET = Debug|.NET
                    EndGlobalSection
                    GlobalSection(ProjectConfigurationPlatforms) = postSolution
                        {E8E75132-67E4-4D6F-9CAE-8DA4C883F418}.Debug|.NET.ActiveCfg = Debug|.NET
                        {E8E75132-67E4-4D6F-9CAE-8DA4C883F418}.Debug|.NET.Build.0 = Debug|.NET
                        {25FD9E7C-F37E-48E0-9A7C-607FE4AACCC0}.Debug|.NET.ActiveCfg = Debug
                    EndGlobalSection
                    GlobalSection(SolutionProperties) = preSolution
                        HideSolutionNode = FALSE
                    EndGlobalSection
                    GlobalSection(NestedProjects) = preSolution
                        {25FD9E7C-F37E-48E0-9A7C-607FE4AACCC0} = {D2633E4D-46FF-4C4E-8340-4BC7CDF78615}
                    EndGlobalSection
                EndGlobal
                ";

            SolutionFile solution = ParseSolutionHelper(solutionFileContents);

            ProjectInSolution webProject = (ProjectInSolution)solution.ProjectsByGuid["{E8E75132-67E4-4D6F-9CAE-8DA4C883F418}"];
            ProjectInSolution exeProject = (ProjectInSolution)solution.ProjectsByGuid["{25FD9E7C-F37E-48E0-9A7C-607FE4AACCC0}"];
            ProjectInSolution missingWebProject = (ProjectInSolution)solution.ProjectsByGuid["{E8E75132-67E4-4D6F-9CAE-8DA4C883F419}"];

            Assert.Single(webProject.ProjectConfigurations);

            Assert.Equal("Debug|.NET", webProject.ProjectConfigurations["Debug|.NET"].FullName);
            Assert.True(webProject.ProjectConfigurations["Debug|.NET"].IncludeInBuild);

            Assert.Single(exeProject.ProjectConfigurations);

            Assert.Equal("Debug", exeProject.ProjectConfigurations["Debug|.NET"].FullName);
            Assert.False(exeProject.ProjectConfigurations["Debug|.NET"].IncludeInBuild);

            Assert.Empty(missingWebProject.ProjectConfigurations);

            Assert.Equal("Debug", solution.GetDefaultConfigurationName()); // "Default solution configuration"
            Assert.Equal(".NET", solution.GetDefaultPlatformName()); // "Default solution platform"
        }

        /// <summary>
        /// Parse solution file with comments
        /// </summary>
        [Fact]
        public void ParseSolutionWithComments()
        {
            const string solutionFileContent = @"
                    Microsoft Visual Studio Solution File, Format Version 12.00
                    # Visual Studio Version 16
                    VisualStudioVersion = 16.0.29123.89
                    MinimumVisualStudioVersion = 10.0.40219.1
                    Project('{9A19103F-16F7-4668-BE54-9A1E7A4F7556}') = 'SlnCommentTest', 'SlnCommentTest.csproj', '{00000000-0000-0000-FFFF-FFFFFFFFFFFF}'
                    EndProject
                    Project('{2150E333-8FDC-42A3-9474-1A3956D46DE8}') = 'Solution Items', 'Solution Items', '{054DED3B-B890-4652-B449-839F581E5D86}'
	                    ProjectSection(SolutionItems) = preProject
		                    SlnFile.txt = SlnFile.txt
	                    EndProjectSection
                    EndProject
                    Global
	                    GlobalSection(SolutionConfigurationPlatforms) = preSolution
		                    Debug|Any CPU = Debug|Any CPU
		                    Release|Any CPU = Release|Any CPU
	                    EndGlobalSection
	                    GlobalSection(ProjectConfigurationPlatforms) = postSolution
		                    {00000000-0000-0000-FFFF-FFFFFFFFFFFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		                    {00000000-0000-0000-FFFF-FFFFFFFFFFFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
		                    {00000000-0000-0000-FFFF-FFFFFFFFFFFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
		                    {00000000-0000-0000-FFFF-FFFFFFFFFFFF}.Release|Any CPU.Build.0 = Release|Any CPU
	                    EndGlobalSection
	                    GlobalSection(SolutionProperties) = preSolution
		                    HideSolutionNode = FALSE
	                    EndGlobalSection
	                    GlobalSection(ExtensibilityGlobals) = postSolution
		                    SolutionGuid = {FFFFFFFF-FFFF-FFFF-0000-000000000000}
	                    EndGlobalSection
                    EndGlobal
                    ";

            StringBuilder stringBuilder = new StringBuilder();

            // Put comment between all lines
            const string comment = "\t# comment";
            string[] lines = solutionFileContent.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < lines.Length; i++)
            {
                stringBuilder.AppendLine(comment);
                stringBuilder.AppendLine(lines[i]);
            }
            stringBuilder.AppendLine(comment);

            Should.NotThrow(() => ParseSolutionHelper(stringBuilder.ToString()));
        }

        /// <summary>
        /// Helper method to create a SolutionFile object, and call it to parse the SLN file
        /// represented by the string contents passed in.
        /// </summary>
        private static SolutionFile ParseSolutionHelper(string solutionFileContents)
        {
            solutionFileContents = solutionFileContents.Replace('\'', '"');
            string solutionPath = FileUtilities.GetTemporaryFile(".sln");

            try
            {
                File.WriteAllText(solutionPath, solutionFileContents);
                SolutionFile sp = SolutionFile.Parse(solutionPath);
                return sp;
            }
            finally
            {
                File.Delete(solutionPath);
            }
        }
    }
}


<|start_filename|>src/Build.UnitTests/BackEnd/ConfigurationMetadata_Tests.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Xml;
using System.Collections.Generic;
using Microsoft.Build.Collections;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Execution;
using Microsoft.Build.BackEnd;
using System.IO;
using Shouldly;
using Xunit;

namespace Microsoft.Build.UnitTests.BackEnd
{
    /// <summary>
    /// Unit tests for ConfigurationMetadata
    /// </summary>
    public class ConfigurationMetadata_Tests
    {
        /// <summary>
        /// Prepares to run the test
        /// </summary>
        public ConfigurationMetadata_Tests()
        {
            ProjectCollection.GlobalProjectCollection.UnloadAllProjects();
        }

        /// <summary>
        /// Verify that a null config throws an ArgumentNullException.
        /// </summary>
        [Fact]
        public void TestConstructorNullConfiguration()
        {
            Assert.Throws<ArgumentNullException>(() =>
            {
                BuildRequestConfiguration config = null;
                ConfigurationMetadata metadata = new ConfigurationMetadata(config);
            }
           );
        }
        /// <summary>
        /// Verify that a null project thrown an ArgumentNullException
        /// </summary>
        [Fact]
        public void TestConstructorNullProject()
        {
            Assert.Throws<ArgumentNullException>(() =>
            {
                Project project = null;
                ConfigurationMetadata metadata = new ConfigurationMetadata(project);
            }
           );
        }
        /// <summary>
        /// Verify that we get the project path and tools version from the configuration
        /// </summary>
        [Fact]
        public void TestValidConfiguration()
        {
            BuildRequestData data = new BuildRequestData("file", new Dictionary<string, string>(), "toolsVersion", new string[0], null);
            BuildRequestConfiguration config = new BuildRequestConfiguration(1, data, "2.0");
            ConfigurationMetadata metadata = new ConfigurationMetadata(config);
            Assert.Equal(data.ProjectFullPath, metadata.ProjectFullPath);
            Assert.Equal(data.ExplicitlySpecifiedToolsVersion, metadata.ToolsVersion);
        }

        /// <summary>
        /// Verify that we get the project path and tools version from the project.
        /// </summary>
        [Fact]
        public void TestValidProject()
        {
            Project project = CreateProject();

            ConfigurationMetadata metadata = new ConfigurationMetadata(project);
            Assert.Equal(project.FullPath, metadata.ProjectFullPath);
            Assert.Equal(project.ToolsVersion, metadata.ToolsVersion);
        }

        /// <summary>
        /// Verify that we get the same hash code from equivalent metadatas even if they come from different sources.
        /// </summary>
        [Fact]
        public void TestGetHashCode()
        {
            BuildRequestData data = new BuildRequestData("file", new Dictionary<string, string>(), ObjectModelHelpers.MSBuildDefaultToolsVersion, new string[0], null);
            BuildRequestConfiguration config = new BuildRequestConfiguration(1, data, ObjectModelHelpers.MSBuildDefaultToolsVersion);

            Project project = CreateProject();

            ConfigurationMetadata metadata1 = new ConfigurationMetadata(config);
            ConfigurationMetadata metadata2 = new ConfigurationMetadata(project);
            Assert.Equal(metadata1.GetHashCode(), metadata2.GetHashCode());
        }

        /// <summary>
        /// Verify that the Equals method works correctly.
        /// </summary>
        [Fact]
        public void TestEquals()
        {
            BuildRequestData data = new BuildRequestData("file", new Dictionary<string, string>(), ObjectModelHelpers.MSBuildDefaultToolsVersion, new string[0], null);
            BuildRequestConfiguration config = new BuildRequestConfiguration(1, data, ObjectModelHelpers.MSBuildDefaultToolsVersion);

            Project project = CreateProject();

            ConfigurationMetadata metadata1 = new ConfigurationMetadata(config);
            ConfigurationMetadata metadata2 = new ConfigurationMetadata(project);
            Assert.True(metadata1.Equals(metadata2));

            data = new BuildRequestData("file2", new Dictionary<string, string>(), ObjectModelHelpers.MSBuildDefaultToolsVersion, new string[0], null);
            BuildRequestConfiguration config2 = new BuildRequestConfiguration(1, data, ObjectModelHelpers.MSBuildDefaultToolsVersion);
            ConfigurationMetadata metadata3 = new ConfigurationMetadata(config2);
            Assert.False(metadata1.Equals(metadata3));

            data = new BuildRequestData("file", new Dictionary<string, string>(), "3.0", new string[0], null);
            BuildRequestConfiguration config3 = new BuildRequestConfiguration(1, data, "3.0");
            ConfigurationMetadata metadata4 = new ConfigurationMetadata(config3);
            Assert.False(metadata1.Equals(metadata4));
        }

        [Fact]
        public void TestTranslation()
        {
            var globalProperties = new PropertyDictionary<ProjectPropertyInstance>();
            globalProperties["a"] = ProjectPropertyInstance.Create("a", "b");

            var initial = new ConfigurationMetadata("path", globalProperties);

            initial.Translate(TranslationHelpers.GetWriteTranslator());
            var copy = ConfigurationMetadata.FactoryForDeserialization(TranslationHelpers.GetReadTranslator());

            copy.ProjectFullPath.ShouldBe(initial.ProjectFullPath);
            copy.ToolsVersion.ShouldBe(initial.ToolsVersion);

            Assert.Equal(copy.GlobalProperties.GetCopyOnReadEnumerable(), initial.GlobalProperties.GetCopyOnReadEnumerable(), EqualityComparer<ProjectPropertyInstance>.Default);
        }

        /// <summary>
        /// Creates a test project.
        /// </summary>
        private Project CreateProject()
        {
            string projectBody = ObjectModelHelpers.CleanupFileContents(@"
<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='msbuildnamespace'>
<Target Name='Build'>
</Target>
</Project>");

            Dictionary<string, string> globalProperties = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            Project project = new Project(XmlReader.Create(new StringReader(projectBody)), globalProperties, ObjectModelHelpers.MSBuildDefaultToolsVersion);
            project.FullPath = "file";

            return project;
        }
    }
}


<|start_filename|>src/Samples/Dependency/Alpha.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Dependency
{
    public class Alpha
    {
        public static string GetString()
        {
            return nameof(Alpha) + "." + nameof(GetString);
        }
    }
}


<|start_filename|>src/Shared/RegisteredTaskObjectCacheBase.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Concurrent;
using Microsoft.Build.Framework;

#if BUILD_ENGINE
using Microsoft.Build.Shared;

namespace Microsoft.Build.BackEnd.Components.Caching
#else
namespace Microsoft.Build.Shared
#endif
{
    /// <summary>
    /// This is a cache of objects which are registered to be disposed of at a specified time.
    /// </summary>
    internal class RegisteredTaskObjectCacheBase
    {
        /// <summary>
        /// The cache for AppDomain lifetime objects.
        /// </summary>
        private static Lazy<ConcurrentDictionary<object, object>> s_appDomainLifetimeObjects = new Lazy<ConcurrentDictionary<object, object>>();

        /// <summary>
        /// The cache for Build lifetime objects.
        /// </summary>
        private Lazy<ConcurrentDictionary<object, object>> _buildLifetimeObjects = new Lazy<ConcurrentDictionary<object, object>>();

#if FEATURE_APPDOMAIN
        /// <summary>
        /// Static constructor which registers a callback to dispose of AppDomain-lifetime cache objects.
        /// </summary>
        static RegisteredTaskObjectCacheBase()
        {
            AppDomain.CurrentDomain.DomainUnload += new EventHandler((sender, args) =>
            {
                DisposeObjects(s_appDomainLifetimeObjects);
            });
        }
#endif

        #region IRegisteredTaskObjectCache

        /// <summary> 
        /// Disposes of all of the cached objects registered with the specified lifetime.
        /// </summary>
        public void DisposeCacheObjects(RegisteredTaskObjectLifetime lifetime)
        {
            var lazyCollection = GetLazyCollectionForLifetime(lifetime);
            DisposeObjects(lazyCollection);
        }

        /// <summary>
        /// Registers a task object with the specified key and lifetime.
        /// </summary>
        public void RegisterTaskObject(object key, object obj, RegisteredTaskObjectLifetime lifetime, bool allowEarlyCollection)
        {
            ConcurrentDictionary<object, object> dict = GetCollectionForLifetime(lifetime, dontCreate: false);

            dict?.TryAdd(key, obj);
        }

        /// <summary>
        /// Gets a previously registered task object.
        /// </summary>
        public object GetRegisteredTaskObject(object key, RegisteredTaskObjectLifetime lifetime)
        {
            ConcurrentDictionary<object, object> dict = GetCollectionForLifetime(lifetime, dontCreate: true);
            object obj = null;
            dict?.TryGetValue(key, out obj);

            return obj;
        }

        /// <summary>
        /// Unregisters a previously registered task object.
        /// </summary>
        public object UnregisterTaskObject(object key, RegisteredTaskObjectLifetime lifetime)
        {
            ConcurrentDictionary<object, object> dict = GetCollectionForLifetime(lifetime, dontCreate: true);
            object obj = null;
            dict?.TryRemove(key, out obj);

            return obj;
        }

        #endregion

        /// <summary>
        /// Returns true if a collection is not yet created or if it has no content.
        /// </summary>
        protected bool IsCollectionEmptyOrUncreated(RegisteredTaskObjectLifetime lifetime)
        {
            var collection = GetCollectionForLifetime(lifetime, dontCreate: true);
            return (collection == null) || (collection.Count == 0);
        }

        /// <summary>
        /// Returns the collection associated with a particular lifetime.
        /// </summary>
        protected ConcurrentDictionary<object, object> GetCollectionForLifetime(RegisteredTaskObjectLifetime lifetime, bool dontCreate)
        {
            Lazy<ConcurrentDictionary<object, object>> dict = GetLazyCollectionForLifetime(lifetime);

            // If we aren't supposed to create it, don't force the creation.
            if (dontCreate && !dict.IsValueCreated)
            {
                return null;
            }

            return dict.Value;
        }

        /// <summary>
        /// Gets the lazy cache for the specified lifetime.
        /// </summary>
        protected Lazy<ConcurrentDictionary<object, object>> GetLazyCollectionForLifetime(RegisteredTaskObjectLifetime lifetime)
        {
            Lazy<ConcurrentDictionary<object, object>> dict = null;
            switch (lifetime)
            {
                case RegisteredTaskObjectLifetime.Build:
                    dict = _buildLifetimeObjects;
                    break;

                case RegisteredTaskObjectLifetime.AppDomain:
                    dict = RegisteredTaskObjectCacheBase.s_appDomainLifetimeObjects;
                    break;
            }

            return dict;
        }

        /// <summary>
        /// Cleans up a cache collection.
        /// </summary>
        private static void DisposeObjects(Lazy<ConcurrentDictionary<object, object>> lifetimeObjects)
        {
            if (lifetimeObjects.IsValueCreated)
            {
                foreach (var obj in lifetimeObjects.Value.Values)
                {
                    try
                    {
                        IDisposable disposable = obj as IDisposable;
                        disposable?.Dispose();
                    }
                    catch (Exception ex)
                    {
                        if (ExceptionHandling.IsCriticalException(ex))
                        {
                            throw;
                        }

                        // Eat it.  We don't have a way to log here because at a minimum the build has already completed.
                    }
                }

                lifetimeObjects.Value.Clear();
            }
        }
    }
}


<|start_filename|>src/Build/Evaluation/StringMetadataTable.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;

namespace Microsoft.Build.Evaluation
{
    /// <summary>
    /// Wraps a table of metadata values in which keys
    /// may be qualified ("itemtype.name") or unqualified ("name").
    /// </summary>
    internal class StringMetadataTable : IMetadataTable
    {
        /// <summary>
        /// Table of metadata values. 
        /// Each key may be qualified ("itemtype.name") or unqualified ("name").
        /// Unqualified are considered to apply to all item types.
        /// May be null, if empty.
        /// </summary>
        private Dictionary<string, string> _metadata;

        /// <summary>
        /// Constructor taking a table of metadata in which keys
        /// may be a mixture of qualified ("itemtype.name") and unqualified ("name").
        /// Unqualified keys are considered to apply to all item types.
        /// Metadata may be null, indicating it is empty.
        /// </summary>
        internal StringMetadataTable(Dictionary<string, string> metadata)
        {
            _metadata = metadata;
        }

        /// <summary>
        /// Retrieves any value we have in our metadata table for the metadata name specified.
        /// If no value is available, returns empty string.
        /// </summary>
        public string GetEscapedValue(string name)
        {
            return GetEscapedValue(null, name);
        }

        /// <summary>
        /// Retrieves any value we have in our metadata table for the metadata name and item type specified.
        /// If no value is available, returns empty string.
        /// </summary>
        public string GetEscapedValue(string itemType, string name)
        {
            return GetEscapedValueIfPresent(itemType, name) ?? String.Empty;
        }

        /// <summary>
        /// Retrieves any value we have in our metadata table for the metadata name and item type specified.
        /// If no value is available, returns null.
        /// </summary>
        public string GetEscapedValueIfPresent(string itemType, string name)
        {
            if (_metadata == null)
            {
                return null;
            }

            string key;
            if (itemType == null)
            {
                key = name;
            }
            else
            {
                key = itemType + "." + name;
            }

            string value;
            _metadata.TryGetValue(key, out value);

            return value;
        }
    }
}


<|start_filename|>src/Build.OM.UnitTests/Construction/ProjectRootElement_Tests.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
#if FEATURE_SECURITY_PRINCIPAL_WINDOWS
using System.Security.AccessControl;
using System.Security.Principal;
#endif
using System.Text;
using System.Threading;
using System.Xml;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Shared;

using InvalidProjectFileException = Microsoft.Build.Exceptions.InvalidProjectFileException;
using ProjectCollection = Microsoft.Build.Evaluation.ProjectCollection;
using Xunit;

namespace Microsoft.Build.UnitTests.OM.Construction
{
    /// <summary>
    /// Test the ProjectRootElement class
    /// </summary>
    public class ProjectRootElement_Tests
    {
        private const string SimpleProject =
@"<Project xmlns=`msbuildnamespace`>

  <PropertyGroup>
    <P>property value</P>
  </PropertyGroup>

  <PropertyGroup>
    <ProjectFile>$(MSBuildProjectFullPath)</ProjectFile>
    <ThisFile>$(MSBuildThisFileFullPath)</ThisFile>
  </PropertyGroup>

  <ItemGroup>
    <i Include=`a`>
      <m>metadata value</m>
    </i>
  </ItemGroup>

</Project>";

        private const string ComplexProject =
@"<?xml version=""1.0"" encoding=""utf-16""?>
<Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""msbuildnamespace"">
    <PropertyGroup Condition=""false"">
        <p>p1</p>
        <q>q1</q>
    </PropertyGroup>
    <PropertyGroup/>
    <PropertyGroup>
        <r>r1</r>
    </PropertyGroup>
    <PropertyGroup>
      <ProjectFile>$(MSBuildProjectFullPath)</ProjectFile>
      <ThisFile>$(MSBuildThisFileFullPath)</ThisFile>
    </PropertyGroup>
    <Choose>
        <When Condition=""true"">
            <Choose>
                <When Condition=""true"">
                    <PropertyGroup>
                        <s>s1</s>
                    </PropertyGroup>
                </When>
            </Choose>
        </When>
        <When Condition=""false"">
            <PropertyGroup>
                <s>s2</s> <!-- both esses -->
            </PropertyGroup>
        </When>
        <Otherwise>
            <Choose>
                <When Condition=""false""/>
                <Otherwise>
                    <PropertyGroup>
                        <t>t1</t>
                    </PropertyGroup>
                </Otherwise>
            </Choose>
        </Otherwise>
    </Choose>
    <Import Project='$(MSBuildToolsPath)\Microsoft.CSharp.targets'/>
</Project>";

        /// <summary>
        /// Empty project content
        /// </summary>
        [Fact]
        public void EmptyProject()
        {
            ProjectRootElement project = ProjectRootElement.Create();

            Assert.Equal(0, Helpers.Count(project.Children));
            Assert.Equal(string.Empty, project.DefaultTargets);
            Assert.Equal(string.Empty, project.InitialTargets);
            Assert.Equal(ObjectModelHelpers.MSBuildDefaultToolsVersion, project.ToolsVersion);
            Assert.True(project.HasUnsavedChanges); // it is indeed unsaved
        }

        /// <summary>
        /// Set default targets
        /// </summary>
        [Fact]
        public void SetDefaultTargets()
        {
            ProjectRootElement project = ProjectRootElement.Create();

            project.DefaultTargets = "dt";
            Assert.Equal("dt", project.DefaultTargets);
            Assert.True(project.HasUnsavedChanges);
        }

        /// <summary>
        /// Set initialtargets
        /// </summary>
        [Fact]
        public void SetInitialTargets()
        {
            ProjectRootElement project = ProjectRootElement.Create();

            project.InitialTargets = "it";
            Assert.Equal("it", project.InitialTargets);
            Assert.True(project.HasUnsavedChanges);
        }

        /// <summary>
        /// Set toolsversion
        /// </summary>
        [Fact]
        public void SetToolsVersion()
        {
            ProjectRootElement project = ProjectRootElement.Create();

            project.ToolsVersion = "tv";
            Assert.Equal("tv", project.ToolsVersion);
            Assert.True(project.HasUnsavedChanges);
        }

        /// <summary>
        /// Setting full path should accept and update relative path
        /// </summary>
        [Fact]
        public void SetFullPath()
        {
            ProjectRootElement project = ProjectRootElement.Create();
            project.FullPath = "X";

            Assert.Equal(project.FullPath, Path.Combine(Directory.GetCurrentDirectory(), "X"));
        }

        /// <summary>
        /// Attempting to load a second ProjectRootElement over the same file path simply
        /// returns the first one.
        /// A ProjectRootElement is notionally a "memory mapped" view of a file, and we assume there is only
        /// one per file path, so we must reject attempts to make another.
        /// </summary>
        [Fact]
        public void ConstructOverSameFileReturnsSame()
        {
            ProjectRootElement projectXml1 = ProjectRootElement.Create();
            projectXml1.Save(FileUtilities.GetTemporaryFile());

            ProjectRootElement projectXml2 = ProjectRootElement.Open(projectXml1.FullPath);

            Assert.True(object.ReferenceEquals(projectXml1, projectXml2));
        }

        /// <summary>
        /// Attempting to load a second ProjectRootElement over the same file path simply
        /// returns the first one. This should work even if one of the paths is not a full path.
        /// </summary>
        [Fact]
        public void ConstructOverSameFileReturnsSameEvenWithOneBeingRelativePath()
        {
            ProjectRootElement projectXml1 = ProjectRootElement.Create();

            projectXml1.FullPath = Path.Combine(Directory.GetCurrentDirectory(), @"xyz\abc");

            ProjectRootElement projectXml2 = ProjectRootElement.Open(@"xyz\abc");

            Assert.True(object.ReferenceEquals(projectXml1, projectXml2));
        }

        /// <summary>
        /// Attempting to load a second ProjectRootElement over the same file path simply
        /// returns the first one. This should work even if one of the paths is not a full path.
        /// </summary>
        [Fact]
        public void ConstructOverSameFileReturnsSameEvenWithOneBeingRelativePath2()
        {
            ProjectRootElement projectXml1 = ProjectRootElement.Create();

            projectXml1.FullPath = @"xyz\abc";

            ProjectRootElement projectXml2 = ProjectRootElement.Open(Path.Combine(Directory.GetCurrentDirectory(), @"xyz\abc"));

            Assert.True(object.ReferenceEquals(projectXml1, projectXml2));
        }

        /// <summary>
        /// Using TextReader
        /// </summary>
        [Fact]
        public void ConstructOverSameFileReturnsSameEvenWithOneBeingRelativePath3()
        {
            string content = "<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n</Project>";

            ProjectRootElement projectXml1 = ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));

            projectXml1.FullPath = @"xyz\abc";

            ProjectRootElement projectXml2 = ProjectRootElement.Open(Path.Combine(Directory.GetCurrentDirectory(), @"xyz\abc"));

            Assert.True(object.ReferenceEquals(projectXml1, projectXml2));
        }

        /// <summary>
        /// Using TextReader
        /// </summary>
        [Fact]
        public void ConstructOverSameFileReturnsSameEvenWithOneBeingRelativePath4()
        {
            string content = "<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n</Project>";

            ProjectRootElement projectXml1 = ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));

            projectXml1.FullPath = Path.Combine(Directory.GetCurrentDirectory(), @"xyz\abc");

            ProjectRootElement projectXml2 = ProjectRootElement.Open(@"xyz\abc");

            Assert.True(object.ReferenceEquals(projectXml1, projectXml2));
        }

        /// <summary>
        /// Two ProjectRootElement's over the same file path does not throw (although you shouldn't do it)
        /// </summary>
        [Fact]
        public void SetFullPathProjectXmlAlreadyLoaded()
        {
            ProjectRootElement projectXml1 = ProjectRootElement.Create();
            projectXml1.FullPath = Microsoft.Build.Shared.FileUtilities.GetTemporaryFile();

            ProjectRootElement projectXml2 = ProjectRootElement.Create();
            projectXml2.FullPath = projectXml1.FullPath;
        }

        /// <summary>
        /// Invalid XML
        /// </summary>
        [Fact]
        public void InvalidXml()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                ProjectRootElement.Create(XmlReader.Create(new StringReader("XXX")));
            }
           );
        }

        /// <summary>
        /// Valid Xml, invalid namespace on the root
        /// </summary>
        [Fact]
        public void InvalidNamespace()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                var content = @"<Project xmlns='XXX'/>";
                ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
            });
        }

        /// <summary>
        /// Invalid root tag
        /// </summary>
        [Fact]
        public void InvalidRootTag()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                string content = @"
                    <XXX xmlns='http://schemas.microsoft.com/developer/msbuild/2003'/>
                ";

                ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
            }
           );
        }
        /// <summary>
        /// Valid Xml, invalid syntax below the root
        /// </summary>
        [Fact]
        public void InvalidChildBelowRoot()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                string content = @"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                        <XXX/>
                    </Project>
                ";

                ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
            }
           );
        }
        /// <summary>
        /// Root indicates upgrade needed
        /// </summary>
        [Fact]
        public void NeedsUpgrade()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                string content = @"
                    <VisualStudioProject/>
                ";

                ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
            }
           );
        }
        /// <summary>
        /// Valid Xml, invalid namespace below the root
        /// </summary>
        [Fact]
        public void InvalidNamespaceBelowRoot()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                string content = @"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                        <PropertyGroup xmlns='XXX'/>
                    </Project>
                ";

                ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
            }
           );
        }
        /// <summary>
        /// Tests that the namespace error reports are correct
        /// </summary>
        [Fact]
        public void InvalidNamespaceErrorReport()
        {
            string content = @"
<msb:Project xmlns:msb=`http://schemas.microsoft.com/developer/msbuild/2003`>
    <msb:Target Name=`t`>
        <msb:Message Text=`[t]`/>
    </msb:Target>
</msb:Project>
                ";

            content = content.Replace("`", "\"");
            bool exceptionThrown = false;
            try
            {
                Project project = new Project(XmlReader.Create(new StringReader(content)));
            }
            catch (InvalidProjectFileException ex)
            {
                exceptionThrown = true;

                // MSB4068: The element <msb:Project> is unrecognized, or not supported in this context.
                Assert.NotEqual("MSB4068", ex.ErrorCode);

                // MSB4041: The default XML namespace of the project must be the MSBuild XML namespace.
                Assert.Equal("MSB4041", ex.ErrorCode);
            }

            Assert.True(exceptionThrown); // "ERROR: An invalid project file exception should have been thrown."
        }

        /// <summary>
        /// Valid Xml, invalid syntax thrown by child element parsing
        /// </summary>
        [Fact]
        public void ValidXmlInvalidSyntaxInChildElement()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                string content = @"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                        <ItemGroup>
                           <XXX YYY='ZZZ'/>
                        </ItemGroup> 
                    </Project>
                ";

                ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
            }
           );
        }
        /// <summary>
        /// Valid Xml, invalid syntax, should not get added to the Xml cache and
        /// thus returned on the second request!
        /// </summary>
        [Fact]
        public void ValidXmlInvalidSyntaxOpenFromDiskTwice()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                string content = @"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                        <ItemGroup>
                           <XXX YYY='ZZZ'/>
                        </ItemGroup> 
                    </Project>
                ";

                string path = null;

                try
                {
                    try
                    {
                        path = Microsoft.Build.Shared.FileUtilities.GetTemporaryFile();
                        File.WriteAllText(path, content);

                        ProjectRootElement.Open(path);
                    }
                    catch (InvalidProjectFileException)
                    {
                    }

                    // Should throw again, not get from cache
                    ProjectRootElement.Open(path);
                }
                finally
                {
                    File.Delete(path);
                }
            }
           );
        }
        /// <summary>
        /// Verify that opening project using XmlTextReader does not add it to the Xml cache
        /// </summary>
        [Fact]
        [Trait("Category", "netcore-osx-failing")]
        [Trait("Category", "netcore-linux-failing")]
        public void ValidXmlXmlTextReaderNotCache()
        {
            string content = @"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    </Project>
                ";

            string path = null;

            try
            {
                path = FileUtilities.GetTemporaryFile();
                File.WriteAllText(path, content);

                var reader1 = XmlReader.Create(path);
                ProjectRootElement root1 = ProjectRootElement.Create(reader1);
                root1.AddItem("type", "include");

                // If it's in the cache, then the 2nd document won't see the add.
                var reader2 = XmlReader.Create(path);
                ProjectRootElement root2 = ProjectRootElement.Create(reader2);

                Assert.Single(root1.Items);
                Assert.Empty(root2.Items);

                reader1.Dispose();
                reader2.Dispose();
            }
            finally
            {
                File.Delete(path);
            }
        }

        /// <summary>
        /// Verify that opening project using the same path adds it to the Xml cache
        /// </summary>
        [Fact]
        public void ValidXmlXmlReaderCache()
        {
            string content = @"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
                    </Project>
                ";

            string content2 = @"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' DefaultTargets='t'>
                    </Project>
                ";

            string path = null;

            try
            {
                path = FileUtilities.GetTemporaryFile();
                File.WriteAllText(path, content);

                ProjectRootElement root1 = ProjectRootElement.Create(path);

                File.WriteAllText(path, content2);

                // If it went in the cache, and this path also reads from the cache,
                // then we'll see the first version of the file.
                ProjectRootElement root2 = ProjectRootElement.Create(path);

                Assert.Equal(string.Empty, root1.DefaultTargets);
                Assert.Equal(string.Empty, root2.DefaultTargets);
            }
            finally
            {
                File.Delete(path);
            }
        }

        /// <summary>
        /// A simple "system" test: load microsoft.*.targets and verify we don't throw
        /// </summary>
        [Fact]
        public void LoadCommonTargets()
        {
            ProjectCollection projectCollection = new ProjectCollection();
            string toolsPath = projectCollection.Toolsets.Where(toolset => (string.Equals(toolset.ToolsVersion, ObjectModelHelpers.MSBuildDefaultToolsVersion, StringComparison.OrdinalIgnoreCase))).First().ToolsPath;

            string[] targets =
            {
                "Microsoft.Common.targets",
                "Microsoft.CSharp.targets",
                "Microsoft.VisualBasic.targets"
            };

            foreach (string target in targets)
            {
                string path = Path.Combine(toolsPath, target);
                ProjectRootElement project = ProjectRootElement.Open(path);
                Console.WriteLine(@"Loaded target: {0}", target);
                Console.WriteLine(@"Children: {0}", Helpers.Count(project.Children));
                Console.WriteLine(@"Targets: {0}", Helpers.MakeList(project.Targets).Count);
                Console.WriteLine(@"Root ItemGroups: {0}", Helpers.MakeList(project.ItemGroups).Count);
                Console.WriteLine(@"Root PropertyGroups: {0}", Helpers.MakeList(project.PropertyGroups).Count);
                Console.WriteLine(@"UsingTasks: {0}", Helpers.MakeList(project.UsingTasks).Count);
                Console.WriteLine(@"ItemDefinitionGroups: {0}", Helpers.MakeList(project.ItemDefinitionGroups).Count);
            }
        }

        /// <summary>
        /// Save project loaded from TextReader, without setting FullPath.
        /// </summary>
        [Fact]
        public void InvalidSaveWithoutFullPath()
        {
            Assert.Throws<InvalidOperationException>(() =>
            {
                XmlReader reader = XmlReader.Create(new StringReader("<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\"/>"));
                ProjectRootElement project = ProjectRootElement.Create(reader);

                project.Save();
            }
           );
        }
        /// <summary>
        /// Save content with transforms.
        /// The ">" should not turn into "&lt;"
        /// </summary>
        [Fact]
        public void SaveWithTransforms()
        {
            ProjectRootElement project = ProjectRootElement.Create();
            project.AddItem("i", "@(h->'%(x)')");

            StringBuilder builder = new StringBuilder();
            StringWriter writer = new StringWriter(builder);

            project.Save(writer);

            // UTF-16 because writer.Encoding is UTF-16
            string expected = ObjectModelHelpers.CleanupFileContents(
@"<?xml version=""1.0"" encoding=""utf-16""?>
<Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""msbuildnamespace"">
  <ItemGroup>
    <i Include=""@(h->'%(x)')"" />
  </ItemGroup>
</Project>");

            Helpers.VerifyAssertLineByLine(expected, builder.ToString());
        }

        /// <summary>
        /// Save content with transforms to a file.
        /// The ">" should not turn into "&lt;"
        /// </summary>
        [Fact]
        public void SaveWithTransformsToFile()
        {
            ProjectRootElement project = ProjectRootElement.Create();
            project.AddItem("i", "@(h->'%(x)')");

            string file = null;

            try
            {
                file = FileUtilities.GetTemporaryFile();

                project.Save(file);

                string expected = ObjectModelHelpers.CleanupFileContents(
    @"<?xml version=""1.0"" encoding=""utf-8""?>
<Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""msbuildnamespace"">
  <ItemGroup>
    <i Include=""@(h->'%(x)')"" />
  </ItemGroup>
</Project>");

                string actual = File.ReadAllText(file);
                Helpers.VerifyAssertLineByLine(expected, actual);
            }
            finally
            {
                File.Delete(file);
            }
        }

        /// <summary>
        /// Save should create a directory if it is missing
        /// </summary>
        [Fact]
        public void SaveToNonexistentDirectory()
        {
            ProjectRootElement project = ProjectRootElement.Create();
            string directory = null;

            try
            {
                directory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
                string file = "foo.proj";
                string path = Path.Combine(directory, file);

                project.Save(path);

                Assert.True(File.Exists(path));
                Assert.Equal(path, project.FullPath);
                Assert.Equal(directory, project.DirectoryPath);
            }
            finally
            {
                FileUtilities.DeleteWithoutTrailingBackslash(directory, true);
            }
        }

        /// <summary>
        /// Save should create a directory if it is missing
        /// </summary>
        [Fact]
        public void SaveToNonexistentDirectoryRelativePath()
        {
            ProjectRootElement project = ProjectRootElement.Create();
            string directory = null;

            string savedCurrentDirectory = Directory.GetCurrentDirectory();
            try
            {
                Directory.SetCurrentDirectory(Path.GetTempPath()); // should be used for project.DirectoryPath; it must exist
                // Use the *real* current directory for constructing the path
                var curDir = Directory.GetCurrentDirectory();

                string file = "bar" + Path.DirectorySeparatorChar + "foo.proj";
                string path = Path.Combine(curDir, file);
                directory = Path.Combine(curDir, "bar");

                project.Save(file); // relative path: file and a single directory only; should create the "bar" part

                Assert.True(File.Exists(file));
                Assert.Equal(path, project.FullPath);
                Assert.Equal(directory, project.DirectoryPath);
            }
            finally
            {
                FileUtilities.DeleteWithoutTrailingBackslash(directory, true);

                Directory.SetCurrentDirectory(savedCurrentDirectory);
            }
        }

        /// <summary>
        /// Saving an unnamed project without a path specified should give a nice exception
        /// </summary>
        [Fact]
        public void SaveUnnamedProject()
        {
            Assert.Throws<InvalidOperationException>(() =>
            {
                ProjectRootElement project = ProjectRootElement.Create();
                project.Save();
            }
           );
        }
        /// <summary>
        /// Verifies that the ProjectRootElement.Encoding property getter returns values
        /// that are based on the XML declaration in the file.
        /// </summary>
        [Fact]
        public void EncodingGetterBasedOnXmlDeclaration()
        {
            ProjectRootElement project = ProjectRootElement.Create(XmlReader.Create(new StringReader(ObjectModelHelpers.CleanupFileContents(@"<?xml version=""1.0"" encoding=""utf-16""?>
<Project DefaultTargets=""Build"" ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""msbuildnamespace"">
</Project>"))));
            Assert.Equal(Encoding.Unicode, project.Encoding);

            project = ProjectRootElement.Create(XmlReader.Create(new StringReader(ObjectModelHelpers.CleanupFileContents(@"<?xml version=""1.0"" encoding=""utf-8""?>
<Project DefaultTargets=""Build"" ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""msbuildnamespace"">
</Project>"))));
            Assert.Equal(Encoding.UTF8, project.Encoding);

            project = ProjectRootElement.Create(XmlReader.Create(new StringReader(ObjectModelHelpers.CleanupFileContents(@"<?xml version=""1.0"" encoding=""us-ascii""?>
<Project DefaultTargets=""Build"" ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""msbuildnamespace"">
</Project>"))));
            Assert.Equal(Encoding.ASCII, project.Encoding);
        }

        /// <summary>
        /// Verifies that ProjectRootElement.Encoding returns the correct value
        /// after reading a file off disk, even if no xml declaration is present.
        /// </summary>
        [Fact]
        public void EncodingGetterBasedOnActualEncodingWhenXmlDeclarationIsAbsent()
        {
            string projectFullPath = FileUtilities.GetTemporaryFile();
            try
            {
                VerifyLoadedProjectHasEncoding(projectFullPath, Encoding.UTF8);
                VerifyLoadedProjectHasEncoding(projectFullPath, Encoding.Unicode);

                // We don't test ASCII, since there is no byte order mark for it,
                // and the XmlReader will legitimately decide to interpret it as UTF8,
                // which would fail the test although it's a reasonable assumption
                // when no xml declaration is present.
                ////VerifyLoadedProjectHasEncoding(projectFullPath, Encoding.ASCII);
            }
            finally
            {
                File.Delete(projectFullPath);
            }
        }

        /// <summary>
        /// Verifies that the Save method saves an otherwise unmodified project
        /// with a specified file encoding.
        /// </summary>
        [Fact]
        public void SaveUnmodifiedWithNewEncoding()
        {
            ProjectRootElement project = ProjectRootElement.Create(XmlReader.Create(new StringReader(ObjectModelHelpers.CleanupFileContents(@"
<Project DefaultTargets=""Build"" ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""msbuildnamespace"">
</Project>"))));
            project.FullPath = FileUtilities.GetTemporaryFile();
            string projectFullPath = project.FullPath;
            try
            {
                project.Save();
                project = null;

                // We haven't made any changes to the project, but we want to save it using various encodings.
                SaveProjectWithEncoding(projectFullPath, Encoding.Unicode);
                SaveProjectWithEncoding(projectFullPath, Encoding.ASCII);
                SaveProjectWithEncoding(projectFullPath, Encoding.UTF8);
            }
            finally
            {
                File.Delete(projectFullPath);
            }
        }

        /// <summary>
        /// Enumerate over all properties from the project directly.
        /// It should traverse into Choose's.
        /// </summary>
        [Fact]
        public void PropertiesEnumerator()
        {
            string content = ObjectModelHelpers.CleanupFileContents(
                  @"<?xml version=""1.0"" encoding=""utf-16""?>
                    <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""msbuildnamespace"">
                        <PropertyGroup Condition=""false"">
                            <p>p1</p>
                            <q>q1</q>
                        </PropertyGroup>
                        <PropertyGroup/>
                        <PropertyGroup>
                            <r>r1</r>
                        </PropertyGroup>
                        <Choose>
                            <When Condition=""true"">
                                <Choose>
                                    <When Condition=""true"">
                                        <PropertyGroup>
                                            <s>s1</s>
                                        </PropertyGroup>
                                    </When>
                                </Choose>
                            </When>
                            <When Condition=""false"">
                                <PropertyGroup>
                                    <s>s2</s> <!-- both esses -->
                                </PropertyGroup>
                            </When>
                            <Otherwise>
                                <Choose>
                                    <When Condition=""false""/>
                                    <Otherwise>
                                        <PropertyGroup>
                                            <t>t1</t>
                                        </PropertyGroup>
                                    </Otherwise>
                                </Choose>
                            </Otherwise>
                        </Choose>
                    </Project>");

            ProjectRootElement project = ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));

            List<ProjectPropertyElement> properties = Helpers.MakeList(project.Properties);

            Assert.Equal(6, properties.Count);

            Assert.Equal("q", properties[1].Name);
            Assert.Equal("r1", properties[2].Value);
            Assert.Equal("t1", properties[5].Value);
        }

        /// <summary>
        /// Enumerate over all items from the project directly.
        /// It should traverse into Choose's.
        /// </summary>
        [Fact]
        public void ItemsEnumerator()
        {
            string content = ObjectModelHelpers.CleanupFileContents(
                  @"<?xml version=""1.0"" encoding=""utf-16""?>
                    <Project ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""msbuildnamespace"">
                        <ItemGroup Condition=""false"">
                            <i Include=""i1""/>
                            <j Include=""j1""/>
                        </ItemGroup>
                        <ItemGroup/>
                        <ItemGroup>
                            <k Include=""k1""/>
                        </ItemGroup>
                        <Choose>
                            <When Condition=""true"">
                                <Choose>
                                    <When Condition=""true"">
                                        <ItemGroup>
                                            <k Include=""k2""/>
                                        </ItemGroup>
                                    </When>
                                </Choose>
                            </When>
                            <When Condition=""false"">
                                <ItemGroup>
                                    <k Include=""k3""/>
                                </ItemGroup>
                            </When>
                            <Otherwise>
                                <Choose>
                                    <When Condition=""false""/>
                                    <Otherwise>
                                        <ItemGroup>
                                            <k Include=""k4""/>
                                        </ItemGroup>
                                    </Otherwise>
                                </Choose>
                            </Otherwise>
                        </Choose>
                    </Project>");

            ProjectRootElement project = ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));

            List<ProjectItemElement> items = Helpers.MakeList(project.Items);

            Assert.Equal(6, items.Count);

            Assert.Equal("j", items[1].ItemType);
            Assert.Equal("k1", items[2].Include);
            Assert.Equal("k4", items[5].Include);
        }

#if FEATURE_SECURITY_PRINCIPAL_WINDOWS
        /// <summary>
        /// Build a solution file that can't be accessed
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]  // Security classes are not supported on Unix

        public void SolutionCanNotBeOpened()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                string solutionFile = null;
                string tempFileSentinel = null;

                IdentityReference identity = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
                FileSystemAccessRule rule = new FileSystemAccessRule(identity, FileSystemRights.Read, AccessControlType.Deny);

                FileSecurity security = null;

                try
                {
                    tempFileSentinel = Microsoft.Build.Shared.FileUtilities.GetTemporaryFile();
                    solutionFile = Path.ChangeExtension(tempFileSentinel, ".sln");
                    File.Copy(tempFileSentinel, solutionFile);

                    security = new FileSecurity(solutionFile, System.Security.AccessControl.AccessControlSections.All);

                    security.AddAccessRule(rule);

                    File.SetAccessControl(solutionFile, security);

                    ProjectRootElement.Open(solutionFile);
                }
                catch (PrivilegeNotHeldException)
                {
                    throw new InvalidProjectFileException("Running unelevated so skipping this scenario.");
                }
                finally
                {
                    security?.RemoveAccessRule(rule);

                    File.Delete(solutionFile);
                    File.Delete(tempFileSentinel);
                    Assert.False(File.Exists(solutionFile));
                }
            }
           );
        }

        /// <summary>
        /// Build a project file that can't be accessed
        /// </summary>
        [Fact]
        [PlatformSpecific (TestPlatforms.Windows)]
        // FileSecurity class is not supported on Unix
        public void ProjectCanNotBeOpened()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                string projectFile = null;

                IdentityReference identity = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
                FileSystemAccessRule rule = new FileSystemAccessRule(identity, FileSystemRights.Read, AccessControlType.Deny);

                FileSecurity security = null;

                try
                {
                    // Does not have .sln or .vcproj extension so loads as project
                    projectFile = Microsoft.Build.Shared.FileUtilities.GetTemporaryFile();

                    security = new FileSecurity(projectFile, System.Security.AccessControl.AccessControlSections.All);
                    security.AddAccessRule(rule);

                    File.SetAccessControl(projectFile, security);

                    ProjectRootElement.Open(projectFile);
                }
                catch (PrivilegeNotHeldException)
                {
                    throw new InvalidProjectFileException("Running unelevated so skipping the scenario.");
                }
                finally
                {
                    security?.RemoveAccessRule(rule);

                    File.Delete(projectFile);
                    Assert.False(File.Exists(projectFile));
                }
            }
           );
        }
#endif

        /// <summary>
        /// Build a corrupt solution
        /// </summary>
        [Fact]
        public void SolutionCorrupt()
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                string solutionFile = null;

                try
                {
                    solutionFile = Microsoft.Build.Shared.FileUtilities.GetTemporaryFile();

                    // Arbitrary corrupt content
                    string content = @"Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio Codename Orcas
Project(""{";

                    File.WriteAllText(solutionFile, content);

                    ProjectRootElement.Open(solutionFile);
                }
                finally
                {
                    File.Delete(solutionFile);
                }
            }
           );
        }
        /// <summary>
        /// Open lots of projects concurrently to try to trigger problems
        /// </summary>
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]  //This test is platform specific for Windows
        public void ConcurrentProjectOpenAndCloseThroughProject()
        {
            int iterations = 500;
            string[] paths = ObjectModelHelpers.GetTempFiles(iterations);

            try
            {
                Project[] projects = new Project[iterations];

                for (int i = 0; i < iterations; i++)
                {
                    CreatePREWithSubstantialContent().Save(paths[i]);
                }

                var collection = new ProjectCollection();
                int counter = 0;
                int remaining = iterations;
                var done = new ManualResetEvent(false);

                for (int i = 0; i < iterations; i++)
                {
                    ThreadPool.QueueUserWorkItem(delegate
                    {
                        var current = Interlocked.Increment(ref counter) - 1;

                        projects[current] = collection.LoadProject(paths[current]);

                        if (Interlocked.Decrement(ref remaining) == 0)
                        {
                            done.Set();
                        }
                    });
                }

                done.WaitOne();

                Assert.Equal(iterations, collection.LoadedProjects.Count);

                counter = 0;
                remaining = iterations;
                done.Reset();

                for (int i = 0; i < iterations; i++)
                {
                    ThreadPool.QueueUserWorkItem(delegate
                    {
                        var current = Interlocked.Increment(ref counter) - 1;

                        var pre = projects[current].Xml;
                        collection.UnloadProject(projects[current]);
                        collection.UnloadProject(pre);

                        if (Interlocked.Decrement(ref remaining) == 0)
                        {
                            done.Set();
                        }
                    });
                }

                done.WaitOne();

                Assert.Empty(collection.LoadedProjects);
            }
            finally
            {
                for (int i = 0; i < iterations; i++)
                {
                    File.Delete(paths[i]);
                }
            }
        }

        /// <summary>
        /// Open lots of projects concurrently to try to trigger problems
        /// </summary>
        [Fact]
        public void ConcurrentProjectOpenAndCloseThroughProjectRootElement()
        {
            int iterations = 500;
            string[] paths = ObjectModelHelpers.GetTempFiles(iterations);

            try
            {
                var projects = new ProjectRootElement[iterations];

                var collection = new ProjectCollection();
                int counter = 0;
                int remaining = iterations;
                var done = new ManualResetEvent(false);

                for (int i = 0; i < iterations; i++)
                {
                    ThreadPool.QueueUserWorkItem(delegate
                    {
                        var current = Interlocked.Increment(ref counter) - 1;

                        CreatePREWithSubstantialContent().Save(paths[current]);
                        projects[current] = ProjectRootElement.Open(paths[current], collection);

                        if (Interlocked.Decrement(ref remaining) == 0)
                        {
                            done.Set();
                        }
                    });
                }

                done.WaitOne();

                counter = 0;
                remaining = iterations;
                done.Reset();

                for (int i = 0; i < iterations; i++)
                {
                    ThreadPool.QueueUserWorkItem(delegate
                    {
                        var current = Interlocked.Increment(ref counter) - 1;

                        collection.UnloadProject(projects[current]);

                        if (Interlocked.Decrement(ref remaining) == 0)
                        {
                            done.Set();
                        }
                    });
                }

                done.WaitOne();
            }
            finally
            {
                for (int i = 0; i < iterations; i++)
                {
                    File.Delete(paths[i]);
                }
            }
        }

        /// <summary>
        /// Tests DeepClone and CopyFrom for ProjectRootElements.
        /// </summary>
        [Fact]
        public void DeepClone()
        {
            var pre = ProjectRootElement.Create();
            var pg = pre.AddPropertyGroup();
            pg.AddProperty("a", "$(b)");
            pg.AddProperty("c", string.Empty);

            var ig = pre.AddItemGroup();
            var item = ig.AddItem("Foo", "boo$(hoo)");
            item.AddMetadata("Some", "Value");

            var target = pre.AddTarget("SomeTarget");
            target.Condition = "Some Condition";
            var task = target.AddTask("SomeTask");
            task.AddOutputItem("p1", "it");
            task.AddOutputProperty("prop", "it2");
            target.AppendChild(pre.CreateOnErrorElement("someTarget"));

            var idg = pre.AddItemDefinitionGroup();
            var id = idg.AddItemDefinition("SomeType");
            id.AddMetadata("sm", "sv");

            pre.AddUsingTask("name", "assembly", null);

            var inlineUt = pre.AddUsingTask("anotherName", "somefile", null);
            inlineUt.TaskFactory = "SomeFactory";
            inlineUt.AddUsingTaskBody("someEvaluate", "someTaskBody");

            var choose = pre.CreateChooseElement();
            pre.AppendChild(choose);
            var when1 = pre.CreateWhenElement("some condition");
            choose.AppendChild(when1);
            when1.AppendChild(pre.CreatePropertyGroupElement());
            var otherwise = pre.CreateOtherwiseElement();
            choose.AppendChild(otherwise);
            otherwise.AppendChild(pre.CreateItemGroupElement());

            var importGroup = pre.AddImportGroup();
            importGroup.AddImport("Some imported project");
            pre.AddImport("direct import");

            ValidateDeepCloneAndCopyFrom(pre);
        }

        /// <summary>
        /// Tests DeepClone and CopyFrom for ProjectRootElement that contain ProjectExtensions with text inside.
        /// </summary>
        [Fact]
        public void DeepCloneWithProjectExtensionsElementOfText()
        {
            var pre = ProjectRootElement.Create();

            var extensions = pre.CreateProjectExtensionsElement();
            extensions.Content = "Some foo content";
            pre.AppendChild(extensions);

            ValidateDeepCloneAndCopyFrom(pre);
        }

        /// <summary>
        /// Tests DeepClone and CopyFrom for ProjectRootElement that contain ProjectExtensions with xml inside.
        /// </summary>
        [Fact]
        public void DeepCloneWithProjectExtensionsElementOfXml()
        {
            var pre = ProjectRootElement.Create();

            var extensions = pre.CreateProjectExtensionsElement();
            extensions.Content = "<a><b/></a>";
            pre.AppendChild(extensions);

            ValidateDeepCloneAndCopyFrom(pre);
        }

        /// <summary>
        /// Tests DeepClone and CopyFrom when there is metadata expressed as attributes
        /// </summary>
        [Fact]
        public void DeepCloneWithMetadataAsAttributes()
        {
            var project =
@"<?xml version=`1.0` encoding=`utf-8`?>
  <Project xmlns = 'msbuildnamespace'>

    <ItemDefinitionGroup>
      <Compile A=`a`/>
      <B M1=`dv1`>
        <M2>dv2</M2>
      </B>
      <C/>
    </ItemDefinitionGroup>

    <ItemGroup>
      <Compile Include=`Class1.cs` A=`a` />
      <Compile Include=`Class2.cs` />
    </ItemGroup>

    <PropertyGroup>
      <P>val</P>
    </PropertyGroup>

    <Target Name=`Build`>
      <ItemGroup>
        <A Include=`a` />
        <B Include=`b` M1=`v1`>
          <M2>v2</M2>
        </B>
        <C Include=`c`/>
      </ItemGroup>
    </Target>

  </Project>";

            var pre = ProjectRootElement.Create(XmlReader.Create(new StringReader(ObjectModelHelpers.CleanupFileContents(project))));

            ValidateDeepCloneAndCopyFrom(pre);
        }

        /// <summary>
        /// Tests TryOpen when preserveFormatting is the same and different than the cached project.
        /// </summary>
        [Fact]
        public void TryOpenWithPreserveFormatting()
        {
            string project =
@"<?xml version=`1.0` encoding=`utf-8`?>
<Project xmlns = 'msbuildnamespace'>
</Project>";

            using (var env = TestEnvironment.Create())
            using (var projectCollection = new ProjectCollection())
            {
                var projectFiles = env.CreateTestProjectWithFiles("", new[] { "build.proj" });
                var projectFile = projectFiles.CreatedFiles.First();

                var projectXml = ProjectRootElement.Create(
                    XmlReader.Create(new StringReader(ObjectModelHelpers.CleanupFileContents(project))),
                    projectCollection,
                    preserveFormatting: true);

                projectXml.Save(projectFile);

                var xml0 = ProjectRootElement.TryOpen(projectXml.FullPath, projectCollection, preserveFormatting: true);
                Assert.True(xml0.PreserveFormatting);

                var xml1 = ProjectRootElement.TryOpen(projectXml.FullPath, projectCollection, preserveFormatting: false);
                Assert.False(xml1.PreserveFormatting);

                var xml2 = ProjectRootElement.TryOpen(projectXml.FullPath, projectCollection, preserveFormatting: null);
                // reuses existing setting
                Assert.False(xml2.PreserveFormatting);

                Assert.NotNull(xml0);

                Assert.Same(xml0, xml1);
                Assert.Same(xml0, xml2);
            }
        }

        [Theory]
        [InlineData(true, false, false)]
        [InlineData(true, true, true)]
        [InlineData(false, false, false)]
        [InlineData(false, true, true)]
        [InlineData(true, null, true)]
        [InlineData(false, null, false)]
        public void ReloadCanSpecifyPreserveFormatting(bool initialPreserveFormatting, bool? reloadShouldPreserveFormatting, bool expectedFormattingAfterReload)
        {
            using (var env = TestEnvironment.Create())
            {
                var testFiles = env.CreateTestProjectWithFiles("", new[] { "build.proj" });
                var projectFile = testFiles.CreatedFiles.First();

                var projectElement = ObjectModelHelpers.CreateInMemoryProjectRootElement(SimpleProject, null, initialPreserveFormatting);
                projectElement.Save(projectFile);
                Assert.Equal(initialPreserveFormatting, projectElement.PreserveFormatting);

                projectElement.Reload(false, reloadShouldPreserveFormatting);
                Assert.Equal(expectedFormattingAfterReload, projectElement.PreserveFormatting);

                // reset project to original preserve formatting
                projectElement.Reload(false, initialPreserveFormatting);
                Assert.Equal(initialPreserveFormatting, projectElement.PreserveFormatting);

                projectElement.ReloadFrom(XmlReader.Create(new StringReader(ObjectModelHelpers.CleanupFileContents(SimpleProject))), false, reloadShouldPreserveFormatting);
                Assert.Equal(expectedFormattingAfterReload, projectElement.PreserveFormatting);

                // reset project to original preserve formatting
                projectElement.Reload(false, initialPreserveFormatting);
                Assert.Equal(initialPreserveFormatting, projectElement.PreserveFormatting);

                projectElement.ReloadFrom(projectFile, false, reloadShouldPreserveFormatting);
                Assert.Equal(expectedFormattingAfterReload, projectElement.PreserveFormatting);
            }
        }

        [Theory]

        // same content should still dirty the project
        [InlineData(
SimpleProject,
SimpleProject,
true, false, false)]

        // new comment
        [InlineData(
@"<Project xmlns=`msbuildnamespace`>

  <PropertyGroup>
    <P>property value</P>
  </PropertyGroup>

  <ItemGroup>
    <i Include=`a`>
      <m>metadata value</m>
    </i>
  </ItemGroup>

</Project>",
@"
<!-- new comment -->
<Project xmlns=`msbuildnamespace`>
  <PropertyGroup>
    <P><!-- new comment -->property value<!-- new comment --></P>
  </PropertyGroup>
  
  <!-- new comment -->
  <ItemGroup>
    <i Include=`a`>
      <!-- new comment -->
      <m>metadata value</m>
    </i>
  </ItemGroup>

</Project>",
true, false, true)]

        // changed comment
        [InlineData(
@"
<!-- new comment -->
<Project xmlns=`msbuildnamespace`>
  <PropertyGroup>
    <P><!-- new comment -->property value<!-- new comment --></P>
  </PropertyGroup>
  
  <!-- new comment -->
  <ItemGroup>
    <i Include=`a`>
      <!-- new comment -->
      <m>metadata value</m>
    </i>
  </ItemGroup>

</Project>",
@"
<!-- changed comment -->
<Project xmlns=`msbuildnamespace`>
  <PropertyGroup>
    <P><!-- changed comment -->property value<!-- changed comment --></P>
  </PropertyGroup>
  
  <!-- changed comment -->
  <ItemGroup>
    <i Include=`a`>
      <!-- changed comment -->
      <m>metadata value</m>
    </i>
  </ItemGroup>

</Project>",
true, false, true)]

        // deleted comment
        [InlineData(
@"
<!-- new comment -->
<Project xmlns=`msbuildnamespace`>
  <PropertyGroup>
    <P><!-- new comment -->property value<!-- new comment --></P>
  </PropertyGroup>
  
  <!-- new comment -->
  <ItemGroup>
    <i Include=`a`>
      <!-- new comment -->
      <m>metadata value</m>
    </i>
  </ItemGroup>

</Project>",
@"
<Project xmlns=`msbuildnamespace`>
  <PropertyGroup>
    <P>property value</P>
  </PropertyGroup>
  
  <ItemGroup>
    <i Include=`a`>
      <m>metadata value</m>
    </i>
  </ItemGroup>

</Project>",
true, false, true)]

        // new comments and changed code
        [InlineData(
@"<Project xmlns=`msbuildnamespace`>

  <PropertyGroup>
    <P>property value</P>
  </PropertyGroup>

  <ItemGroup>
    <i Include=`a`>
      <m>metadata value</m>
    </i>
  </ItemGroup>

</Project>",
@"
<!-- new comment -->
<Project xmlns=`msbuildnamespace`>
  <PropertyGroup>
    <P>property value</P>
    <P2><!-- new comment -->property value<!-- new comment --></P2>
  </PropertyGroup>

</Project>",
true, true, true)]

        // commented out code
        [InlineData(
@"<Project xmlns=`msbuildnamespace`>

  <PropertyGroup>
    <P>property value</P>
  </PropertyGroup>

  <ItemGroup>
    <i Include=`a`>
      <m>metadata value</m>
    </i>
  </ItemGroup>

</Project>",
@"<Project xmlns=`msbuildnamespace`>
  <PropertyGroup>
    <P>property value</P>
  </PropertyGroup>

<!--
  <ItemGroup>
    <i Include=`a`>
      <m>metadata value</m>
    </i>
  </ItemGroup>
-->
</Project>",
true, true, true)]
        public void ReloadRespectsNewContents(string initialProjectContents, string changedProjectContents, bool versionChanged, bool msbuildChildrenChanged, bool xmlChanged)
        {
            Action<ProjectRootElement, string> act = (p, c) =>
            {
                p.ReloadFrom(
                    XmlReader.Create(new StringReader(c)),
                    throwIfUnsavedChanges: false);
            };

            AssertReload(initialProjectContents, changedProjectContents, versionChanged, msbuildChildrenChanged, xmlChanged, act);
        }

        [Fact]
        public void ReloadedStateIsResilientToChangesAndDiskRoundtrip()
        {
            var initialProjectContents = ObjectModelHelpers.CleanupFileContents(
@"
<!-- new comment -->
<Project xmlns=`msbuildnamespace`>

  <!-- new comment -->
  <ItemGroup>
    <i Include=`a`>
      <!-- new comment -->
      <m>metadata value</m>
    </i>
  </ItemGroup>

</Project>");

            var changedProjectContents1 = ObjectModelHelpers.CleanupFileContents(
@"
<!-- changed comment -->
<Project xmlns=`msbuildnamespace`>
  
  <!-- changed comment -->
  <ItemGroup>

    <i Include=`a`>
         <!-- changed comment -->
           <m>metadata value</m>
    </i>

  </ItemGroup>

</Project>");

            var changedProjectContents2 = ObjectModelHelpers.CleanupFileContents(
// spurious comment placement issue: https://github.com/Microsoft/msbuild/issues/1503
@"
<!-- changed comment -->
<Project xmlns=`msbuildnamespace`>
  
  <!-- changed comment -->
  <PropertyGroup>
    <P>v</P>
  </PropertyGroup>
  <ItemGroup>

    <i Include=`a`>
         <!-- changed comment -->
           <m>metadata value</m>
    </i>

  </ItemGroup>

</Project>");

            using (var env = TestEnvironment.Create())
            {
                var projectCollection1 = env.CreateProjectCollection().Collection;
                var projectCollection2 = env.CreateProjectCollection().Collection;

                var testFiles = env.CreateTestProjectWithFiles("", new[] { "build.proj" });
                var projectPath = testFiles.CreatedFiles.First();

                var projectElement = ObjectModelHelpers.CreateInMemoryProjectRootElement(initialProjectContents, projectCollection1, preserveFormatting: true);
                projectElement.Save(projectPath);

                projectElement.ReloadFrom(XmlReader.Create(new StringReader(changedProjectContents1)));

                VerifyAssertLineByLine(changedProjectContents1, projectElement.RawXml);

                projectElement.AddProperty("P", "v");

                VerifyAssertLineByLine(changedProjectContents2, projectElement.RawXml);

                projectElement.Save();

                var projectElement2 = ProjectRootElement.Open(projectPath, projectCollection2, preserveFormatting: true);

                VerifyAssertLineByLine(changedProjectContents2, projectElement2.RawXml);
            }
        }

        [Fact]
        public void ReloadThrowsOnInvalidXmlSyntax()
        {
            var missingClosingTag =
@"<Project xmlns=`msbuildnamespace`>

  <PropertyGroup>
    <P>property value</P>
  </PropertyGroup>

  <ItemGroup>
    <i Include=`a`>
      <m>metadata value<m>
    </i>
  </ItemGroup>

</Project>";

            Action<ProjectRootElement, string> act = (p, c) =>
            {
                var exception =
                    Assert.Throws<InvalidProjectFileException>(
                        () =>
                            p.ReloadFrom(
                                XmlReader.Create(
                                    new StringReader(c)),
                                throwIfUnsavedChanges: false));

                Assert.Contains(@"The project file could not be loaded. The 'm' start tag on line", exception.Message);
            };

            // reload does not mutate the project element
            AssertReload(SimpleProject, missingClosingTag, false, false, false, act);
        }

        [Fact]
        public void ReloadThrowsForInMemoryProjectsWithoutAPath()
        {
            Action<ProjectRootElement, string> act = (p, c) =>
            {
                var exception =
                    Assert.Throws<InvalidOperationException>(
                        () =>
                            p.Reload(throwIfUnsavedChanges: false));

                Assert.Contains(@"Value not set:", exception.Message);
            };

            // reload does not mutate the project element
            AssertReload(SimpleProject, ComplexProject, false, false, false, act);
        }

        [Fact]
        public void ReloadFromAPathThrowsOnMissingPath()
        {
            Action<ProjectRootElement, string> act = (p, c) =>
            {
                var fullPath = Path.GetFullPath("foo");

                var exception =
                    Assert.Throws<InvalidOperationException>(
                        () =>
                            p.ReloadFrom(fullPath, throwIfUnsavedChanges: false));

                Assert.Contains(@"File to reload from does not exist:", exception.Message);
            };

            // reload does not mutate the project element
            AssertReload(SimpleProject, ComplexProject, false, false, false, act);
        }

        [Fact]
        public void ReloadFromMemoryWhenProjectIsInMemoryKeepsProjectFileEmpty()
        {
            AssertProjectFileAfterReload(
                true,
                true,
                (initial, reload, actualFile) => { Assert.Equal(String.Empty, actualFile); });
        }

        [Fact]
        public void ReloadFromMemoryWhenProjectIsInFileKeepsProjectFile()
        {
            AssertProjectFileAfterReload(
                false,
                true,
                (initial, reload, actualFile) => { Assert.Equal(initial, actualFile); });
        }

        [Fact]
        public void ReloadFromFileWhenProjectIsInMemorySetsProjectFile()
        {
            AssertProjectFileAfterReload(
                true,
                false,
                (initial, reload, actualFile) => { Assert.Equal(reload, actualFile);});
        }

        [Fact]
        public void ReloadFromFileWhenProjectIsInFileUpdatesProjectFile()
        {
            AssertProjectFileAfterReload(
                false,
                false,
                (initial, reload, actualFile) => { Assert.Equal(reload, actualFile); });
        }

        private void AssertProjectFileAfterReload(
            bool initialProjectFromMemory,
            bool reloadProjectFromMemory,
            Action<string, string, string> projectFileAssert)
        {
            using (var env = TestEnvironment.Create())
            {
                var projectCollection = env.CreateProjectCollection().Collection;

                string initialLocation = null;
                ProjectRootElement rootElement = null;

                if (initialProjectFromMemory)
                {
                    rootElement = ObjectModelHelpers.CreateInMemoryProjectRootElement(SimpleProject, projectCollection);
                }
                else
                {
                    initialLocation = env.CreateFile().Path;
                    File.WriteAllText(initialLocation, ObjectModelHelpers.CleanupFileContents(SimpleProject));
                    rootElement = ProjectRootElement.Open(initialLocation, projectCollection);
                }

                var project = new Project(rootElement, null, null, projectCollection);

                string reloadLocation = null;

                if (reloadProjectFromMemory)
                {
                    rootElement.ReloadFrom(XmlReader.Create(new StringReader(ObjectModelHelpers.CleanupFileContents(ComplexProject))), false);
                }
                else
                {
                    reloadLocation = env.CreateFile().Path;
                    File.WriteAllText(reloadLocation, ObjectModelHelpers.CleanupFileContents(ComplexProject));
                    rootElement.ReloadFrom(reloadLocation, false);
                }

                project.ReevaluateIfNecessary();

                projectFileAssert.Invoke(initialLocation, reloadLocation, EmptyIfNull(rootElement.FullPath));
                projectFileAssert.Invoke(initialLocation, reloadLocation, rootElement.ProjectFileLocation.File);
                projectFileAssert.Invoke(initialLocation, reloadLocation, rootElement.AllChildren.Last().Location.File);
                projectFileAssert.Invoke(initialLocation, reloadLocation, project.GetPropertyValue("ProjectFile"));
                projectFileAssert.Invoke(initialLocation, reloadLocation, project.GetPropertyValue("ThisFile"));

                if (initialProjectFromMemory && reloadProjectFromMemory)
                {
                    Assert.Equal(NativeMethodsShared.GetCurrentDirectory(), rootElement.DirectoryPath);
                }
                else
                {
                    projectFileAssert.Invoke(Path.GetDirectoryName(initialLocation), Path.GetDirectoryName(reloadLocation), rootElement.DirectoryPath);
                }
            }
        }

        private static string EmptyIfNull(string aString) => aString ?? string.Empty;

        [Fact]
        public void ReloadThrowsOnInvalidMsBuildSyntax()
        {
            var unknownAttribute =
@"<Project xmlns=`msbuildnamespace`>

  <PropertyGroup Foo=`bar`>
    <P>property value</P>
  </PropertyGroup>

  <ItemGroup>
    <i Include=`a`>
      <m>metadata value</m>
    </i>
  </ItemGroup>

</Project>";

            Action<ProjectRootElement, string> act = (p, c) =>
            {
                var exception =
                    Assert.Throws<InvalidProjectFileException>(
                        () =>
                            p.ReloadFrom(
                                XmlReader.Create(
                                    new StringReader(c)),
                                throwIfUnsavedChanges: false));

                Assert.Contains(@"The attribute ""Foo"" in element <PropertyGroup> is unrecognized", exception.Message);
            };

            // reload does not mutate the project element
            AssertReload(SimpleProject, unknownAttribute, false, false, false, act);
        }

        [Fact]
        public void ReloadThrowsByDefaultIfThereAreUnsavedChanges()
        {
            Action<ProjectRootElement, string> act = (p, c) =>
            {
                var exception =
                    Assert.Throws<InvalidOperationException>(
                        () =>
                            p.ReloadFrom(
                                XmlReader.Create(
                                    new StringReader(c))));

                Assert.Contains(@"ProjectRootElement can't reload if it contains unsaved changes.", exception.Message);
            };

            // reload does not mutate the project element
            AssertReload(SimpleProject, ComplexProject, false, false, false, act);
        }

        [Fact]
        public void ReloadCanOverwriteUnsavedChanges()
        {
            Action<ProjectRootElement, string> act = (p, c) =>
            {
                p.ReloadFrom(
                    XmlReader.Create(new StringReader(ObjectModelHelpers.CleanupFileContents(c))),
                    throwIfUnsavedChanges: false);
            };

            AssertReload(SimpleProject, ComplexProject, true, true, true, act);
        }

        private void AssertReload(
            string initialContents,
            string changedContents,
            bool versionChanged,
            bool msbuildChildrenChanged,
            bool xmlChanged,
            Action<ProjectRootElement, string> act)
        {
            var projectElement = ObjectModelHelpers.CreateInMemoryProjectRootElement(initialContents);

            var version = projectElement.Version;
            var childrenCount = projectElement.AllChildren.Count();
            var xml = projectElement.RawXml;

            Assert.True(projectElement.HasUnsavedChanges);
            act(projectElement, ObjectModelHelpers.CleanupFileContents(changedContents));

            if (versionChanged)
            {
                Assert.NotEqual(version, projectElement.Version);
            }
            else
            {
                Assert.Equal(version, projectElement.Version);
            }

            if (msbuildChildrenChanged)
            {
                Assert.NotEqual(childrenCount, projectElement.AllChildren.Count());
            }
            else
            {
                Assert.Equal(childrenCount, projectElement.AllChildren.Count());
            }

            if (xmlChanged)
            {
                Assert.NotEqual(xml, projectElement.RawXml);
            }
            else
            {
                Assert.Equal(xml, projectElement.RawXml);
            }
        }

        /// <summary>
        /// Test helper for validating that DeepClone and CopyFrom work as advertised.
        /// </summary>
        private static void ValidateDeepCloneAndCopyFrom(ProjectRootElement pre)
        {
            var pre2 = pre.DeepClone();
            Assert.NotSame(pre2, pre);
            Assert.Equal(pre.RawXml, pre2.RawXml);

            var pre3 = ProjectRootElement.Create();
            pre3.AddPropertyGroup(); // this should get wiped out in the DeepCopyFrom
            pre3.DeepCopyFrom(pre);
            Assert.Equal(pre.RawXml, pre3.RawXml);
        }

        /// <summary>
        /// Re-saves a project with a new encoding and thoroughly verifies that the right things happen.
        /// </summary>
        private void SaveProjectWithEncoding(string projectFullPath, Encoding encoding)
        {
            // Always use a new project collection to guarantee we're reading off disk.
            ProjectRootElement project = ProjectRootElement.Open(projectFullPath, new ProjectCollection());
            project.Save(encoding);
            Assert.Equal(encoding, project.Encoding); // "Changing an unmodified project's encoding failed to update ProjectRootElement.Encoding."

            // Try to verify that the xml declaration was emitted, and that the correct byte order marks
            // are also present.

            using (var reader = FileUtilities.OpenRead(projectFullPath, encoding, true))
            {
                Assert.Equal(encoding, reader.CurrentEncoding);
                string actual = reader.ReadLine();
                string expected = string.Format(@"<?xml version=""1.0"" encoding=""{0}""?>", encoding.WebName);
                Assert.Equal(expected, actual); // "The encoding was not emitted as an XML declaration."
            }

            project = ProjectRootElement.Open(projectFullPath, new ProjectCollection());

            // It's ok for the read Encoding to differ in fields like DecoderFallback,
            // so a pure equality check here is too much.
            Assert.Equal(encoding.CodePage, project.Encoding.CodePage);
            Assert.Equal(encoding.EncodingName, project.Encoding.EncodingName);
        }

        /// <summary>
        /// Creates a project at a given path with a given encoding but without the Xml declaration,
        /// and then verifies that when loaded by MSBuild, the encoding is correctly reported.
        /// </summary>
        private void VerifyLoadedProjectHasEncoding(string projectFullPath, Encoding encoding)
        {
            CreateProjectWithEncodingWithoutDeclaration(projectFullPath, encoding);

            // Let's just be certain the project has been read off disk...
            ProjectRootElement project = ProjectRootElement.Open(projectFullPath, new ProjectCollection());
            Assert.Equal(encoding.WebName, project.Encoding.WebName);
        }

        /// <summary>
        /// Creates a project file with a specific encoding, but without an XML declaration.
        /// </summary>
        private void CreateProjectWithEncodingWithoutDeclaration(string projectFullPath, Encoding encoding)
        {
            const string EmptyProject = @"<Project DefaultTargets=""Build"" ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""msbuildnamespace"">
</Project>";

            using (StreamWriter writer = FileUtilities.OpenWrite(projectFullPath, false, encoding))
            {
                writer.Write(ObjectModelHelpers.CleanupFileContents(EmptyProject));
            }
        }

        /// <summary>
        /// Create a nice big PRE
        /// </summary>
        private ProjectRootElement CreatePREWithSubstantialContent()
        {
            string content = ObjectModelHelpers.CleanupFileContents(ComplexProject);

            ProjectRootElement project = ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));

            return project;
        }

        private void VerifyAssertLineByLine(string expected, string actual)
        {
            Helpers.VerifyAssertLineByLine(expected, actual, false);
        }
    }
}


<|start_filename|>src/Shared/UnitTests/ImmutableDictionary_Tests.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

// We don't automatically run these tests against the BCL implementation of ImmutableDictionary as it would require dual-compiling
// this file. When making changes to this test, though, it is recommended to run them manually by uncommenting the following line.
// This helps ensure that the real thing has the same behavior that we expect in our implementation.
//#define _TEST_BCL_IMMUTABLE_DICTIONARY

extern alias MSBuildTaskHost;

using System;
using System.Collections;
using System.Collections.Generic;

using Shouldly;
using Xunit;

#if _TEST_BCL_IMMUTABLE_DICTIONARY
using ImmutableDictionary = System.Collections.Immutable.ImmutableDictionary<string, string>;
#else
using ImmutableDictionary = MSBuildTaskHost::System.Collections.Immutable.ImmutableDictionary<string, string>;
#endif

namespace Microsoft.Build.UnitTests
{
    public class ImmutableDictionary_Tests
    {
        private readonly ImmutableDictionary _emptyDict = ImmutableDictionary.Empty;

        [Fact]
        public void SimplesBoolPropertiesReturnExpectedValues()
        {
            ((IDictionary)_emptyDict).IsFixedSize.ShouldBeTrue();
            ((IDictionary)_emptyDict).IsReadOnly.ShouldBeTrue();
            ((IDictionary)_emptyDict).IsSynchronized.ShouldBeTrue();
        }

        [Fact]
        public void CountReturnsExpectedValue()
        {
            _emptyDict.Count.ShouldBe(0);
            ImmutableDictionary dict = _emptyDict.SetItem("Key1", "Value1");
            dict.Count.ShouldBe(1);
            dict = dict.SetItem("Key2", "Value2");
            dict.Count.ShouldBe(2);
            dict = dict.Clear();
            dict.Count.ShouldBe(0);
        }

        [Fact]
        public void IndexerReturnsPreviouslySetItem()
        {
            ImmutableDictionary dict = _emptyDict.SetItem("Key1", "Value1");
            dict["Key1"].ShouldBe("Value1");
            ((IDictionary)dict)["Key1"].ShouldBe("Value1");
            ((IDictionary<string, string>)dict)["Key1"].ShouldBe("Value1");
        }

        [Fact]
        public void IndexerThrowsForItemNotPreviouslySet()
        {
            ImmutableDictionary dict = _emptyDict.SetItem("Key1", "Value1");
            Should.Throw<KeyNotFoundException>(() => _ = dict["Key2"]);
            Should.Throw<KeyNotFoundException>(() => _ = ((IDictionary)dict)["Key2"]);
            Should.Throw<KeyNotFoundException>(() => _ = ((IDictionary<string, string>)dict)["Key2"]);
        }

        [Fact]
        public void ContainsReturnsTrueForPeviouslySetItem()
        {
            ImmutableDictionary dict = _emptyDict.SetItem("Key1", "Value1");
            dict.Contains(new KeyValuePair<string, string>("Key1", "Value1")).ShouldBeTrue();
            dict.ContainsKey("Key1").ShouldBeTrue();
            ((IDictionary)dict).Contains("Key1").ShouldBeTrue();
        }

        [Fact]
        public void ContainsReturnsFalseForItemNotPeviouslySet()
        {
            ImmutableDictionary dict = _emptyDict.SetItem("Key1", "Value1");
            dict.Contains(new KeyValuePair<string, string>("Key2", "Value2")).ShouldBeFalse();
            dict.ContainsKey("Key2").ShouldBeFalse();
            ((IDictionary)dict).Contains("Key2").ShouldBeFalse();
        }

        [Fact]
        public void EnumeratorEnumeratesItems()
        {
            ImmutableDictionary dict = _emptyDict.SetItem("Key1", "Value1");

            IEnumerator<KeyValuePair<string, string>> enumerator1 = dict.GetEnumerator();
            int i = 0;
            while (enumerator1.MoveNext())
            {
                i++;
                enumerator1.Current.Key.ShouldBe("Key1");
                enumerator1.Current.Value.ShouldBe("Value1");
            }
            i.ShouldBe(dict.Count);

            IDictionaryEnumerator enumerator2 = ((IDictionary)dict).GetEnumerator();
            i = 0;
            while (enumerator2.MoveNext())
            {
                i++;
                enumerator2.Key.ShouldBe("Key1");
                enumerator2.Value.ShouldBe("Value1");
            }
            i.ShouldBe(dict.Count);

            IEnumerator enumerator3 = ((IEnumerable)dict).GetEnumerator();
            i = 0;
            while (enumerator3.MoveNext())
            {
                i++;
                KeyValuePair<string, string> entry = (KeyValuePair<string, string>)enumerator3.Current;
                entry.Key.ShouldBe("Key1");
                entry.Value.ShouldBe("Value1");
            }
            i.ShouldBe(dict.Count);
        }

        [Fact]
        public void CopyToCopiesItemsToArray()
        {
            ImmutableDictionary dict = _emptyDict.SetItem("Key1", "Value1");

            KeyValuePair<string, string>[] array1 = new KeyValuePair<string, string>[1];
            ((ICollection<KeyValuePair<string, string>>)dict).CopyTo(array1, 0);
            array1[0].Key.ShouldBe("Key1");
            array1[0].Value.ShouldBe("Value1");

            array1 = new KeyValuePair<string, string>[2];
            ((ICollection<KeyValuePair<string, string>>)dict).CopyTo(array1, 1);
            array1[1].Key.ShouldBe("Key1");
            array1[1].Value.ShouldBe("Value1");

            DictionaryEntry[] array2 = new DictionaryEntry[1];
            ((ICollection)dict).CopyTo(array2, 0);
            array2[0].Key.ShouldBe("Key1");
            array2[0].Value.ShouldBe("Value1");

            array2 = new DictionaryEntry[2];
            ((ICollection)dict).CopyTo(array2, 1);
            array2[1].Key.ShouldBe("Key1");
            array2[1].Value.ShouldBe("Value1");
        }

        [Fact]
        public void CopyToThrowsOnInvalidInput()
        {
            ImmutableDictionary dict = _emptyDict.SetItem("Key1", "Value1");

            Should.Throw<ArgumentNullException>(() => ((ICollection<KeyValuePair<string, string>>)dict).CopyTo(null, 0));
            Should.Throw<ArgumentNullException>(() => ((ICollection)dict).CopyTo(null, 0));

            KeyValuePair<string, string>[] array1 = new KeyValuePair<string, string>[1];
            DictionaryEntry[] array2 = new DictionaryEntry[1];
            Should.Throw<ArgumentOutOfRangeException>(() => ((ICollection<KeyValuePair<string, string>>)dict).CopyTo(array1, -1));
            Should.Throw<ArgumentOutOfRangeException>(() => ((ICollection)dict).CopyTo(array1, -1));

            Should.Throw<ArgumentException>(() => ((ICollection<KeyValuePair<string, string>>)dict).CopyTo(array1, 1));
            Should.Throw<ArgumentException>(() => ((ICollection)dict).CopyTo(array1, 1));
        }

        [Fact]
        public void KeysReturnsKeys()
        {
            ImmutableDictionary dict = _emptyDict.SetItem("Key1", "Value1");

            ICollection<string> keys1 = ((IDictionary<string, string>)dict).Keys;
            keys1.ShouldBe(new string[] { "Key1" });

            ICollection keys2 = ((IDictionary)dict).Keys;
            keys2.ShouldBe(new string[] { "Key1" });
        }

        [Fact]
        public void ValuesReturnsValues()
        {
            ImmutableDictionary dict = _emptyDict.SetItem("Key1", "Value1");

            ICollection<string> values1 = ((IDictionary<string, string>)dict).Values;
            values1.ShouldBe(new string[] { "Value1" });

            ICollection values2 = ((IDictionary)dict).Values;
            values2.ShouldBe(new string[] { "Value1" });
        }

        [Fact]
        public void SetItemReturnsNewInstanceAfterAdding()
        {
            ImmutableDictionary dict = _emptyDict.SetItem("Key1", "Value1");
            dict.ShouldNotBeSameAs(_emptyDict);
        }

        [Fact]
        public void SetItemReturnsNewInstanceAfterUpdating()
        {
            ImmutableDictionary dict1 = _emptyDict.SetItem("Key1", "Value1");
            ImmutableDictionary dict2 = dict1.SetItem("Key1", "Value2");
            dict2.ShouldNotBeSameAs(dict1);
        }

        [Fact]
        public void SetItemReturnsSameInstanceWhenItemAlreadyExists()
        {
            ImmutableDictionary dict1 = _emptyDict.SetItem("Key1", "Value1");
            ImmutableDictionary dict2 = dict1.SetItem("Key1", "Value1");
            dict2.ShouldBeSameAs(dict1);
        }

        [Fact]
        public void RemoveReturnsNewInstanceAfterDeleting()
        {
            ImmutableDictionary dict1 = _emptyDict.SetItem("Key1", "Value1");
            ImmutableDictionary dict2 = dict1.Remove("Key1");
            dict2.ShouldNotBeSameAs(dict1);
        }

        [Fact]
        public void RemoveReturnsSameInstanceWhenItemDoesNotExist()
        {
            ImmutableDictionary dict1 = _emptyDict.SetItem("Key1", "Value1");
            ImmutableDictionary dict2 = dict1.Remove("Key2");
            dict2.ShouldBeSameAs(dict1);
        }

        [Fact]
        public void ClearReturnsNewInstance()
        {
            ImmutableDictionary dict1 = _emptyDict.SetItem("Key1", "Value1");
            ImmutableDictionary dict2 = dict1.Clear();
            dict2.ShouldNotBeSameAs(dict1);
        }

        [Fact]
        public void WithComparersCreatesNewInstanceWithSpecifiedKeyComparer()
        {
            ImmutableDictionary dict1 = _emptyDict.SetItem("Key1", "Value1");
            ImmutableDictionary dict2 = dict1.WithComparers(StringComparer.OrdinalIgnoreCase);
            dict2["KEY1"].ShouldBe("Value1");
        }

        [Fact]
        public void AddRangeAddsAllItems()
        {
            ImmutableDictionary dict = _emptyDict.AddRange(new KeyValuePair<string, string>[]
            {
                new KeyValuePair<string, string>("Key1", "Value1"),
                new KeyValuePair<string, string>("Key2", "Value2")
            });
            dict.Count.ShouldBe(2);
            dict["Key1"].ShouldBe("Value1");
            dict["Key2"].ShouldBe("Value2");
        }
    }
}


<|start_filename|>src/Framework/XamlTypes/Rule.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Windows.Markup;

namespace Microsoft.Build.Framework.XamlTypes
{
    // DEV11DESIGNISSUE (pavana): Once the de-serialization is complete, seal the type so
    // that the object becomes immutable (e.g. we can set a flag in EndInit() and throw
    // in all property setter if this flag is set.

    /// <summary>
    /// Methods for overriding one rule with another.
    /// </summary>
    public enum RuleOverrideMode
    {
        /// <summary>
        /// A subsequent definition for a rule (with the same name) entirely overrides a previous definition.
        /// </summary>
        Replace,

        /// <summary>
        /// A subsequent definition for a rule (with the same name) adds properties to a previous definition.
        /// </summary>
        Extend,
    }

    /// <summary>
    /// Used to represent the schema information for a Tool, a Custom Build Rule, a PropertyPage, etc. 
    /// </summary> 
    /// <remarks> 
    /// <para>
    /// Normally represented on disk as XAML, only one instance of this class is maintained per XAML
    /// file per project engine (solution).
    /// </para>
    /// <para> Those who manually instantiate this class should remember to call <see cref="BeginInit"/> before
    /// setting the first property and <see cref="EndInit"/> after setting the last property of the object.
    /// </para>
    /// </remarks>
    /// <comment>
    /// This partial class contains all properties which are public and hence settable in XAML. Those properties that
    /// are internal are defined in another partial class below.
    /// </comment>
    [ContentProperty("Properties")]
    [DebuggerDisplay("Rule: {Name}")]
    public sealed partial class Rule : RuleSchema, ISupportInitialize, IProjectSchemaNode
    {
        #region Fields

        /// <summary>
        /// See DisplayName property.
        /// </summary>
        private string _displayName;

        #endregion // Fields

        #region Constructor

        /// <summary>
        /// Default constructor. Needed for deserialization from a persisted format.
        /// </summary>
        public Rule()
        {
            // Initialize collection properties in this class. This is required for
            // proper deserialization.
            Properties = new List<BaseProperty>();
            Categories = new List<Category>();
            Metadata = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);

            // Set defaults.
            SupportsFileBatching = false;
            ShowOnlyRuleProperties = true;
            SwitchPrefix = String.Empty;
            Separator = String.Empty;
            OverrideMode = RuleOverrideMode.Replace;
            PropertyPagesHidden = false;
        }

        #endregion // Constructor

        #region Properties

        /// <summary>
        /// The name of this <see cref="Rule"/>. 
        /// </summary>
        /// <remarks>
        /// This field is mandatory and culture invariant. The value of this field cannot be set to the empty string. 
        /// </remarks>
        public string Name
        {
            get;
            set;
        }

        /// <summary>
        /// The name that could be used by a prospective UI client to display this <see cref="BaseProperty"/>. 
        /// </summary>
        /// <remarks>
        /// This field is optional and is culture sensitive. When this property is not set, it is assigned the same 
        /// value as the <see cref="Name"/> property (and hence, would not be localized).
        /// </remarks>
        [Localizable(true)]
        public string DisplayName
        {
            get
            {
                return _displayName ?? Name;
            }

            set
            {
                _displayName = value;
            }
        }

        /// <summary>
        /// The name of the tool executable when this rule represents a tool.
        /// </summary>
        public string ToolName
        {
            get;
            set;
        }

        /// <summary>
        /// Description of this <see cref="Rule"/> for use by a prospective UI client. 
        /// </summary>
        /// <remarks> 
        /// This field is optional and is culture sensitive.
        /// </remarks>
        [Localizable(true)]
        public string Description
        {
            get;
            set;
        }

        /// <summary>
        /// Help information for this <see cref="Rule"/>. 
        /// </summary>
        /// <remarks>
        /// Maybe used to specify a help URL. This field
        /// is optional and is culture sensitive.
        /// </remarks>
        [Localizable(true)]
        public string HelpString
        {
            get;
            set;
        }

        /// <summary>
        /// The prefix to use for all property switches in this <see cref="Rule"/> for the case when this property <see cref="Rule"/> represent a tool.
        /// </summary>
        /// <remarks>
        /// The value specified can be overridden by the value specified by a child <see cref="BaseProperty"/>'s <see cref="BaseProperty.SwitchPrefix"/>.
        /// This field is optional and culture invariant.
        /// </remarks>
        /// <example>
        /// For the VC++ CL task, <c>WholeProgramOptimization</c> is a boolean parameter. It's switch is <c>GL</c> and its
        /// switch prefix (inherited from the parent <see cref="Rule.SwitchPrefix"/> since it is not overridden by <c>WholeProgramOptimization</c>)
        /// is <c>/</c>. Thus the complete switch in the command line for this property would be <c>/GL</c>
        /// </example>
        public string SwitchPrefix
        {
            get;
            set;
        }

        /// <summary>
        /// The token used to separate a property switch from its value.
        /// </summary>
        /// <remarks>
        /// The value specified here is overridden by the value specified by the child <see cref="BaseProperty"/>'s <see cref="BaseProperty.Separator"/>.
        /// This field is optional and culture invariant.
        /// </remarks>
        /// <example>
        /// Example: Consider <c>/D:WIN32</c>. In this switch and value representation, ":" is the separator since its separates the switch <c>D</c> 
        /// from its value <c>WIN32</c>.
        /// </example>
        public string Separator
        {
            get;
            set;
        }

        /// <summary>
        /// The UI renderer template used to display this Rule. 
        /// </summary>
        /// <remarks>
        /// The value used to set
        /// this field can be anything as long as it is recognized by the intended renderer.
        /// This field is required only if this Rule is meant to be displayed as a property page.
        /// </remarks>
        public string PageTemplate
        {
            get;
            set;
        }

        /// <summary>
        /// The <see cref="DataSource"/> for all the properties in this <see cref="Rule"/>. This is overriden by any
        /// data source defined locally for a property. 
        /// </summary>
        /// <remarks>
        /// This field need not be specified only if all individual properties have data source defined locally.
        /// </remarks>
        public DataSource DataSource
        {
            get;
            set;
        }

        /// <summary>
        /// This is a suggestion to a prospective UI client on the relative location of this <see cref="Rule"/> compared to all other Rules in the system.
        /// </summary>
        public int Order
        {
            get;
            set;
        }

        /// <summary>
        /// This is used to specify whether multiple files need to be batched on one command line invocation. 
        /// </summary>
        /// <remarks>
        /// This field is optional.
        /// </remarks>
        public bool SupportsFileBatching
        {
            get;
            set;
        }

        /// <summary>
        /// Indicates whether to hide the command line category or not. Default value is true.
        /// </summary>
        /// <remarks>
        /// This field is optional.
        /// </remarks>
        public bool ShowOnlyRuleProperties
        {
            get;
            set;
        }

        /// <summary>
        /// When this <see cref="Rule"/> represents a Build Customization, this field represents the file extension to associate.
        /// </summary>
        /// <remarks>
        /// This field is optional.
        /// </remarks>
        public string FileExtension
        {
            get;
            set;
        }

        /// <summary>
        /// When this <see cref="Rule"/> represents a Build Customization, this field represents the message to be displayed before executing a Build Customization during the build.
        /// </summary>
        /// <remarks>
        /// This field is optional.
        /// </remarks>
        public string ExecutionDescription
        {
            get;
            set;
        }

        /// <summary>
        /// When this <see cref="Rule"/> represents a Build Customization, this field represents the command line template that is going to be used by a Build Customization task to invoke the tool.
        /// </summary>
        /// <remarks>
        /// This field is optional.
        /// </remarks>
        public string CommandLine
        {
            get;
            set;
        }

        /// <summary>
        /// When this <see cref="Rule"/> represents a Build Customization, this field defines the semicolon separated list of additional inputs that are going to be evaluated
        /// for the Build Customization target.
        /// </summary>
        /// <remarks>
        /// This field is optional.
        /// </remarks>
        public string AdditionalInputs
        {
            get;
            set;
        }

        /// <summary>
        /// When this <see cref="Rule"/> represents a Build Customization, this field defines the semicolon separated list of outputs that are going to be evaluated
        /// for the Build Customization target.
        /// </summary>
        /// <remarks>
        /// This field is optional.
        /// </remarks>
        public string Outputs
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the method to use when multiple rules with the same name appear in the project
        /// to reconcile the rules into one instance.
        /// </summary>
        public RuleOverrideMode OverrideMode
        {
            get;
            set;
        }

        /// <summary>
        /// This list of properties in this <see cref="Rule"/>. Atleast one property should be specified.
        /// </summary>
        /// <remarks> The list returned by this property should not be modified. </remarks>
        [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "This has shipped in Framework, which is especially important to keep binary compatible, so we can't change it now")]
        public List<BaseProperty> Properties
        {
            get;
            set;
        }

        /// <summary>
        /// The list of <see cref="Category"/>s that properties in this <see cref="Rule"/> belong to. 
        /// </summary>
        /// <remarks>
        /// This field is optional. Note that this field returns only the categories that were explicitly defined and do
        /// not contain any auto-generated categories. When a <see cref="BaseProperty"/> contained in this <see cref="Rule"/>
        /// declares its category to be something that is not present in this list, then we auto-generate a <see cref="Category"/>
        /// with that name and add it to the internal list of categories. That auto-generated category will not be returned
        /// by this field.
        /// </remarks>
        [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "This has shipped in Framework, which is especially important to keep binary compatible, so we can't change it now")]
        public List<Category> Categories
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets arbitrary metadata that may be set on a rule.
        /// </summary>
        [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "Shipped this way in Dev11 Beta, which is go-live")]
        public Dictionary<string, object> Metadata { get; set; }

        /// <summary>
        /// Gets or sets a value indicating if property pages for this rule should be hidden or not.
        /// </summary>
        public bool PropertyPagesHidden { get; set; }

        #endregion
    }

    /// <summary>
    /// Used to represent the schema information for a Tool, a Custom Build Rule, a PropertyPage, etc. 
    /// </summary> 
    /// <remarks> 
    /// <para>
    /// Normally represented on disk as XAML, only one instance of this class is maintained per XAML
    /// file per project engine (solution).
    /// </para>
    /// <para> Those who manually instantiate this class should remember to call <see cref="BeginInit"/> before
    /// setting the first property and <see cref="EndInit"/> after setting the last property of the object.
    /// </para>
    /// </remarks>
    /// <comment>
    /// This partial class contains members that are auto-generated, internal, etc. Whereas the
    /// other partial class contains public properties that can be set in XAML.
    /// </comment>
    public sealed partial class Rule : RuleSchema, ISupportInitialize, IProjectSchemaNode
    {
        #region Fields

        /// <summary>
        /// Thread synchronization.
        /// </summary>
        private object _syncObject = new object();

        /// <summary>
        /// See the <see cref="EvaluatedCategories"/> property.
        /// </summary>
        private List<Category> _evaluatedCategories;

        /// <summary>
        /// Ordered dictionary of category names and the properties contained in them.
        /// The order of the categories is exactly the same as that specified in the XAML file.
        /// </summary>
        private OrderedDictionary _categoryNamePropertyListMap;

        /// <summary>
        /// A lookup cache of property names to properties.
        /// </summary>
        private ReadOnlyDictionary<string, BaseProperty> _propertiesByNameMap;

        #endregion

        #region Properties

        /// <summary>
        /// This property returns the union of XAML specified <see cref="Category"/>s and auto-generated 
        /// <see cref="Category"/>s. The latter are created from the missing categories that are being referred to by the 
        /// properties in this Rule. The auto-generated <see cref="Category"/>s only have their name set.
        /// </summary>
        public List<Category> EvaluatedCategories
        {
            get
            {
                // check-lock-check pattern DOESN'T work here because two fields get initialized within this lazy initialization method.
                lock (_syncObject)
                {
                    if (_evaluatedCategories == null)
                    {
                        CreateCategoryNamePropertyListMap();
                    }

                    return _evaluatedCategories;
                }
            }
        }

        #endregion // Properties

        #region Public Methods

        /// <summary>
        /// Returns all properties partitioned into categories. The return value is never
        /// null. 
        /// The returned list may contain auto-generated categories. Note that if a <see cref="BaseProperty"/>
        /// (or its derived classes) refer to a property that is not specified, then an new
        /// Category is generated for the same. If not category is specified for the property, then
        /// the property is placed in the "General" category.
        /// The list of categories is exactly as specified in the Xaml file. The auto-generated
        /// categories come (in no strict order) after the specified categories.
        /// </summary>
        /// <returns> A dictionary whose keys are the <see cref="Category"/> names and 
        /// the value is the list of properties in that category. </returns>
        public OrderedDictionary GetPropertiesByCategory()
        {
            // check-lock-check pattern DOESN'T work here because two fields get initialized within this lazy initialization method.
            lock (_syncObject)
            {
                if (_categoryNamePropertyListMap == null)
                {
                    CreateCategoryNamePropertyListMap();
                }

                return _categoryNamePropertyListMap;
            }
        }

        /// <summary>
        /// Returns the list of properties in a <see cref="Category"/>. Returns null if this <see cref="Rule"/>
        /// doesn't contain this category.
        /// </summary>
        public IList<BaseProperty> GetPropertiesInCategory(string categoryName)
        {
            // check-lock-check pattern DOESN'T work here because two fields get initialized within this lazy initialization method.
            lock (_syncObject)
            {
                if (_categoryNamePropertyListMap == null)
                {
                    CreateCategoryNamePropertyListMap();
                }

                return _categoryNamePropertyListMap[categoryName] as IList<BaseProperty>;
            }
        }

        /// <summary>
        /// Returns a property with a given name.
        /// </summary>
        /// <returns>The property, or <c>null</c> if one with a matching name could not be found.</returns>
        public BaseProperty GetProperty(string propertyName)
        {
            if (_propertiesByNameMap == null)
            {
                lock (_syncObject)
                {
                    if (_propertiesByNameMap == null)
                    {
                        var map = new Dictionary<string, BaseProperty>(this.Properties.Count, StringComparer.OrdinalIgnoreCase);
                        foreach (var property in this.Properties)
                        {
                            map[property.Name] = property;
                        }

                        _propertiesByNameMap = new ReadOnlyDictionary<string, BaseProperty>(map);
                    }
                }
            }

            BaseProperty result;
            _propertiesByNameMap.TryGetValue(propertyName, out result);
            return result;
        }

        #endregion // Public Methods

        #region ISupportInitialize Members

        /// <summary>
        /// See ISupportInitialize.
        /// </summary>
        public void BeginInit()
        {
        }

        /// <summary>
        /// See ISupportInitialize.
        /// </summary>
        public void EndInit()
        {
            Initialize();
        }

        #endregion

        #region IProjectSchemaNode Members
        /// <summary>
        /// see IProjectSchemaNode
        /// </summary>
        public IEnumerable<Type> GetSchemaObjectTypes()
        {
            yield return typeof(Rule);
        }

        /// <summary>
        /// see IProjectSchemaNode
        /// </summary>
        public IEnumerable<object> GetSchemaObjects(Type type)
        {
            if (type == typeof(Rule))
            {
                yield return this;
            }
        }
        #endregion

        #region Private Methods

        /// <summary>
        /// Initializes this class after Xaml loading is done.
        /// </summary>
        private void Initialize()
        {
            if (Properties != null)
            {
                // Set parent pointers on all containing properties.
                foreach (BaseProperty property in Properties)
                {
                    property.ContainingRule = this;
                }
            }
        }

        /// <summary>
        /// Creates a map containing all the evaluated category names and the list of
        /// properties belonging to that category.
        /// </summary>
        private void CreateCategoryNamePropertyListMap()
        {
            lock (_syncObject)
            {
                _evaluatedCategories = new List<Category>();

                if (Categories != null)
                {
                    _evaluatedCategories.AddRange(Categories);
                }

                _categoryNamePropertyListMap = new OrderedDictionary();

                foreach (Category category in Categories)
                {
                    _categoryNamePropertyListMap.Add(category.Name, new List<BaseProperty>());
                }

                foreach (BaseProperty property in Properties)
                {
                    // If a property refers to a category which does not have an entry in the Xaml file,
                    // create a category object ourselves.
                    if (!_categoryNamePropertyListMap.Contains(property.Category))
                    {
                        Category category = new Category();
                        category.Name = property.Category;

                        _evaluatedCategories.Add(category);
                        _categoryNamePropertyListMap.Add(category.Name, new List<BaseProperty>());
                    }

                    List<BaseProperty> propertiesInTheSameCategory = _categoryNamePropertyListMap[property.Category] as List<BaseProperty>;
                    propertiesInTheSameCategory.Add(property);
                }
            }
        }

        #endregion
    }
}


<|start_filename|>src/Build/ElementLocation/XmlElementWithLocation.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Xml;
using System.Diagnostics;
using Microsoft.Build.ObjectModelRemoting;

namespace Microsoft.Build.Construction
{
    /// <summary>
    /// Derivation of XmlElement to implement IXmlLineInfo
    /// </summary>
    /// <remarks>
    /// It would be nice to add some helper overloads of base class members that
    /// downcast their return values to XmlElement/AttributeWithLocation. However
    /// C# doesn't currently allow covariance in method overloading, only on delegates.
    /// The caller must bravely downcast.
    /// </remarks>
    internal class XmlElementWithLocation : XmlElement, IXmlLineInfo, ILinkedXml
    {
        /// <summary>
        /// Line, column, file information
        /// </summary>
        private ElementLocation _elementLocation;

        /// <summary>
        /// Constructor without location information
        /// </summary>
        public XmlElementWithLocation(string prefix, string localName, string namespaceURI, XmlDocumentWithLocation document)
            : this(prefix, localName, namespaceURI, document, 0, 0)
        {
        }

        /// <summary>
        /// Constructor with location information
        /// </summary>
        public XmlElementWithLocation(string prefix, string localName, string namespaceURI, XmlDocumentWithLocation document, int lineNumber, int columnNumber)
            : base(prefix, localName, namespaceURI, document)
        {
            // Subtract one, just to give the same value as the old code did.
            // In the past we pointed to the column of the open angle bracket whereas the XmlTextReader points to the first character of the element name.
            // In well formed XML these are always adjacent on the same line, so it's safe to subtract one.
            // If we're loading from a stream it's zero, so don't subtract one.
            XmlDocumentWithLocation documentWithLocation = (XmlDocumentWithLocation)document;

            int adjustedColumn = (columnNumber == 0) ? columnNumber : columnNumber - 1;
            _elementLocation = ElementLocation.Create(documentWithLocation.FullPath, lineNumber, adjustedColumn);
        }

        ProjectElementLink ILinkedXml.Link => null;

        XmlElementWithLocation ILinkedXml.Xml => this;


        /// <summary>
        /// Returns the line number if available, else 0.
        /// IXmlLineInfo member.
        /// </summary>
        public int LineNumber
        {
            [DebuggerStepThrough]
            get
            { return Location.Line; }
        }

        /// <summary>
        /// Returns the column number if available, else 0.
        /// IXmlLineInfo member.
        /// </summary>
        public int LinePosition
        {
            [DebuggerStepThrough]
            get
            { return Location.Column; }
        }

        /// <summary>
        /// Provides an ElementLocation for this element, using the path to the file containing
        /// this element as the project file entry.
        /// Element location may be incorrect, if it was not loaded from disk.
        /// Does not return null.
        /// </summary>
        /// <remarks>
        /// Should have at least the file name if the containing project has been given a file name,
        /// even if it wasn't loaded from disk, or has been edited since. That's because we set that
        /// path on our XmlDocumentWithLocation wrapper class.
        /// </remarks>
        internal ElementLocation Location
        {
            get
            {
                // Caching the element location object saves significant memory
                XmlDocumentWithLocation ownerDocumentWithLocation = (XmlDocumentWithLocation)OwnerDocument;
                if (!String.Equals(_elementLocation.File, ownerDocumentWithLocation.FullPath, StringComparison.OrdinalIgnoreCase))
                {
                    _elementLocation = ElementLocation.Create(ownerDocumentWithLocation.FullPath, _elementLocation.Line, _elementLocation.Column);
                }

                return _elementLocation;
            }
        }

        /// <summary>
        /// Whether location is available.
        /// IXmlLineInfo member.
        /// </summary>
        public bool HasLineInfo()
        {
            return Location.Line != 0;
        }

        /// <summary>
        /// Returns the XmlAttribute with the specified name or null if a matching attribute was not found.
        /// </summary>
        public XmlAttributeWithLocation GetAttributeWithLocation(string name)
        {
            XmlAttribute attribute = GetAttributeNode(name);

            if (attribute == null)
            {
                return null;
            }

            return (XmlAttributeWithLocation)attribute;
        }

        /// <summary>
        /// Overridden to convert the display of the element from open form (separate open and closed tags) to closed form 
        /// (single closed tag) if the last child is being removed. This is simply for tidiness of the project file.
        /// For example, removing the only piece of metadata from an item will leave behind one tag instead of two.
        /// </summary>
        public override XmlNode RemoveChild(XmlNode oldChild)
        {
            XmlNode result = base.RemoveChild(oldChild);

            if (!HasChildNodes)
            {
                IsEmpty = true;
            }

            return result;
        }

        /// <summary>
        /// Gets the location of any attribute on this element with the specified name.
        /// If there is no such attribute, returns null.
        /// </summary>
        internal ElementLocation GetAttributeLocation(string name)
        {
            XmlAttributeWithLocation attributeWithLocation = GetAttributeWithLocation(name);

            return attributeWithLocation?.Location;
        }
    }
}


<|start_filename|>src/Tasks/ManifestUtil/LauncherBuilder.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.IO;
using Microsoft.Build.Shared;
using Microsoft.Build.Shared.FileSystem;
using Microsoft.Build.Tasks.Deployment.Bootstrapper;

namespace Microsoft.Build.Tasks.Deployment.ManifestUtilities
{
    /// <summary>
    /// Adds Launcher and updates its resource
    /// </summary>
    public class LauncherBuilder
    {
        private const string LAUNCHER_RESOURCENAME = "FILENAME";
        private const int LAUNCHER_RESOURCE_TABLE = 50;

        private BuildResults _results;

        public LauncherBuilder(string launcherPath)
        {
            LauncherPath = launcherPath;
        }

        /// <summary>
        /// Specifies the location of the required Launcher files.
        /// </summary>
        /// <value>Path to Launcher files.</value>
        public string LauncherPath { get; set; }

        public BuildResults Build(string filename, string outputPath)
        {
            string launcherFilename = Path.GetFileName(LauncherPath);

            _results = new BuildResults();

            try
            {
                if (filename == null)
                {
                    _results.AddMessage(BuildMessage.CreateMessage(BuildMessageSeverity.Error, "GenerateLauncher.InvalidInput"));
                    return _results;
                }

                if (String.IsNullOrEmpty(outputPath))
                {
                    _results.AddMessage(BuildMessage.CreateMessage(BuildMessageSeverity.Error, "GenerateLauncher.NoOutputPath"));
                    return _results;
                }

                // Copy setup.bin to the output directory
                string strOutputExe = System.IO.Path.Combine(outputPath, launcherFilename);
                if (!CopyLauncherToOutputDirectory(strOutputExe))
                {
                    // Appropriate messages should have been stuffed into the results already
                    return _results;
                }

                var resourceUpdater = new ResourceUpdater();
                resourceUpdater.AddStringResource(LAUNCHER_RESOURCE_TABLE, LAUNCHER_RESOURCENAME, filename);
                if (!resourceUpdater.UpdateResources(strOutputExe, _results))
                {
                    return _results;
                }

                _results.SetKeyFile(launcherFilename);
                _results.BuildSucceeded();
            }
            catch (Exception ex)
            {
                _results.AddMessage(BuildMessage.CreateMessage(BuildMessageSeverity.Error, "GenerateLauncher.General", ex.Message));
            }

            return _results;
        }

        private bool CopyLauncherToOutputDirectory(string strOutputExe)
        {
            if (!FileSystems.Default.FileExists(LauncherPath))
            {
                _results.AddMessage(BuildMessage.CreateMessage(BuildMessageSeverity.Error, "GenerateLauncher.MissingLauncherExe", LauncherPath));
                return false;
            }

            try
            {
                EnsureFolderExists(Path.GetDirectoryName(strOutputExe));
                File.Copy(LauncherPath, strOutputExe, true);
                ClearReadOnlyAttribute(strOutputExe);
            }
            catch (Exception ex) when (ExceptionHandling.IsIoRelatedException(ex))
            {
                _results.AddMessage(BuildMessage.CreateMessage(BuildMessageSeverity.Error, "GenerateLauncher.CopyError", LauncherPath, strOutputExe, ex.Message));
                return false;
            }

            return true;
        }

        private static void EnsureFolderExists(string strFolderPath)
        {
            if (!FileSystems.Default.DirectoryExists(strFolderPath))
            {
                Directory.CreateDirectory(strFolderPath);
            }
        }

        private static void ClearReadOnlyAttribute(string strFileName)
        {
            FileAttributes attribs = File.GetAttributes(strFileName);
            if ((attribs & FileAttributes.ReadOnly) != 0)
            {
                attribs &= (~FileAttributes.ReadOnly);
                File.SetAttributes(strFileName, attribs);
            }
        }
    }
}


<|start_filename|>src/Build.UnitTests/BackEnd/SdkResolverLoader_Tests.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using Shouldly;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.Build.BackEnd.Logging;
using Microsoft.Build.BackEnd.SdkResolution;
using Microsoft.Build.Construction;
using Microsoft.Build.Exceptions;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using Microsoft.Build.UnitTests;
using Xunit;
using Xunit.Abstractions;
using Exception = System.Exception;
using SdkResolverBase = Microsoft.Build.Framework.SdkResolver;
using SdkResolverContextBase = Microsoft.Build.Framework.SdkResolverContext;
using SdkResultBase = Microsoft.Build.Framework.SdkResult;
using SdkResultFactoryBase = Microsoft.Build.Framework.SdkResultFactory;

namespace Microsoft.Build.Engine.UnitTests.BackEnd
{
    public class SdkResolverLoader_Tests
    {
        private readonly ITestOutputHelper _output;
        private readonly MockLogger _logger;
        private readonly LoggingContext _loggingContext;

        public SdkResolverLoader_Tests(ITestOutputHelper output)
        {
            _output = output;
            _logger = new MockLogger(output);
            ILoggingService loggingService = LoggingService.CreateLoggingService(LoggerMode.Synchronous, 1);
            loggingService.RegisterLogger(_logger);

            _loggingContext = new MockLoggingContext(
                loggingService,
                new BuildEventContext(0, 0, BuildEventContext.InvalidProjectContextId, 0, 0));
        }

        [Fact]
        public void AssertDefaultLoaderReturnsDefaultResolvers()
        {
            var loader = new SdkResolverLoader();

            var resolvers = loader.LoadResolvers(_loggingContext, new MockElementLocation("file"));

            resolvers.Select(i => i.GetType().FullName).ShouldBe(new [] { typeof(DefaultSdkResolver).FullName });
            
            _logger.ErrorCount.ShouldBe(0);
            _logger.WarningCount.ShouldBe(0);
        }

        [Fact]
        public void VerifySdkResolverLoaderFileDiscoveryPattern()
        {
            var root = FileUtilities.GetTemporaryDirectory();
            try
            {
                // Valid pattern is root\(Name)\(Name).dll. No other files should be considered.
                var d1 = Directory.CreateDirectory(Path.Combine(root, "Resolver1"));

                // Valid.
                var f1 = Path.Combine(d1.FullName, "Resolver1.dll");

                // Invalid, won't be considered.
                var f2 = Path.Combine(d1.FullName, "Dependency.dll");
                var f3 = Path.Combine(d1.FullName, "InvalidName.dll");
                var f4 = Path.Combine(d1.FullName, "NoResolver.txt");

                File.WriteAllText(f1, string.Empty);
                File.WriteAllText(f2, string.Empty);
                File.WriteAllText(f3, string.Empty);
                File.WriteAllText(f4, string.Empty);

                var strategy = new SdkResolverLoader();
                var files = strategy.FindPotentialSdkResolvers(root, new MockElementLocation("file"));

                files.Count.ShouldBe(1);
                files[0].ShouldBe(f1);
            }
            finally
            {
                FileUtilities.DeleteDirectoryNoThrow(root, true);
            }
        }

        /// <summary>
        /// Verifies that if an SDK resolver throws while creating an instance that a warning is logged.
        /// </summary>
        [Fact]
        public void VerifyThrowsWhenResolverFailsToLoad()
        {
            SdkResolverLoader sdkResolverLoader = new MockSdkResolverLoader
            {
                LoadResolverAssemblyFunc = (resolverPath, loggingContext, location) => typeof(SdkResolverLoader_Tests).GetTypeInfo().Assembly,
                FindPotentialSdkResolversFunc = (rootFolder, loc) => new List<string>
                {
                    "myresolver.dll"
                },
                GetResolverTypesFunc = assembly => new[] { typeof(MockSdkResolverThatDoesNotLoad) }
            };

            InvalidProjectFileException exception = Should.Throw<InvalidProjectFileException>(() =>
            {
                sdkResolverLoader.LoadResolvers(_loggingContext, ElementLocation.EmptyLocation);
            });

            exception.Message.ShouldBe($"The SDK resolver type \"{nameof(MockSdkResolverThatDoesNotLoad)}\" failed to load. A8BB8B3131D3475D881ACD3AF8D75BD6");

            Exception innerException = exception.InnerException.ShouldBeOfType<Exception>();

            innerException.Message.ShouldBe(MockSdkResolverThatDoesNotLoad.ExpectedMessage);

            _logger.WarningCount.ShouldBe(0);
            _logger.ErrorCount.ShouldBe(0);
        }

        /// <summary>
        /// Verifies that when we attempt to create an instance of a resolver with no public constructor that a warning
        /// is logged with the appropriate message.
        /// </summary>
        [Fact]
        public void VerifyThrowsWhenResolverHasNoPublicConstructor()
        {
            SdkResolverLoader sdkResolverLoader = new MockSdkResolverLoader
            {
                LoadResolverAssemblyFunc = (resolverPath, loggingContext, location) => typeof(SdkResolverLoader_Tests).GetTypeInfo().Assembly,
                FindPotentialSdkResolversFunc = (rootFolder, loc) => new List<string>
                {
                    "myresolver.dll"
                },
                GetResolverTypesFunc = assembly => new[] { typeof(MockSdkResolverNoPublicConstructor) }
            };

            InvalidProjectFileException exception = Should.Throw<InvalidProjectFileException>(() =>
            {
                sdkResolverLoader.LoadResolvers(_loggingContext, ElementLocation.EmptyLocation);
            });

            exception.Message.ShouldStartWith($"The SDK resolver type \"{nameof(MockSdkResolverNoPublicConstructor)}\" failed to load.");

            exception.InnerException.ShouldBeOfType<MissingMethodException>();

            _logger.WarningCount.ShouldBe(0);
            _logger.ErrorCount.ShouldBe(0);
        }

        /// <summary>
        /// Verifies that when a resolver assembly cannot be loaded, that a warning is logged and other resolvers are still loaded.
        /// </summary>
        [Fact]
        public void VerifyWarningLoggedWhenResolverAssemblyCannotBeLoaded()
        {
            const string assemblyPath = @"C:\foo\bar\myresolver.dll";
            const string expectedMessage = "91BF077D4E9646819DE7AB2CBA2637B6";

            SdkResolverLoader sdkResolverLoader = new MockSdkResolverLoader
            {
                LoadResolverAssemblyFunc = (resolverPath, loggingContext, location) => throw new Exception(expectedMessage),
                FindPotentialSdkResolversFunc = (rootFolder, loc) => new List<string>
                {
                    assemblyPath,
                }
            };

            InvalidProjectFileException exception = Should.Throw<InvalidProjectFileException>(() =>
            {
                sdkResolverLoader.LoadResolvers(_loggingContext, ElementLocation.EmptyLocation);
            });

            exception.Message.ShouldBe($"The SDK resolver assembly \"{assemblyPath}\" could not be loaded. {expectedMessage}");

            Exception innerException = exception.InnerException.ShouldBeOfType<Exception>();

            innerException.Message.ShouldBe(expectedMessage);

            _logger.WarningCount.ShouldBe(0);
            _logger.ErrorCount.ShouldBe(0);
        }

        [Fact]
        public void SdkResolverLoaderReadsManifestFile()
        {
            using (var env = TestEnvironment.Create(_output))
            {
                var root = env.CreateFolder().Path;
                var resolverPath = Path.Combine(root, "MyTestResolver");
                var resolverManifest = Path.Combine(resolverPath, "MyTestResolver.xml");

                var assemblyToLoad = env.CreateFile(".dll").Path;

                Directory.CreateDirectory(resolverPath);
                File.WriteAllText(resolverManifest, $@"
                    <SdkResolver>
                      <Path>{assemblyToLoad}</Path>
                    </SdkResolver>");

                SdkResolverLoader loader = new SdkResolverLoader();
                var resolversFound = loader.FindPotentialSdkResolvers(root, new MockElementLocation("file"));

                resolversFound.Count.ShouldBe(1);
                resolversFound.First().ShouldBe(assemblyToLoad);
            }
        }

        [Fact]
        public void SdkResolverLoaderErrorsWithInvalidManifestFile()
        {
            using (var env = TestEnvironment.Create(_output))
            {
                var root = env.CreateFolder().Path;
                var resolverPath = Path.Combine(root, "MyTestResolver");
                var resolverManifest = Path.Combine(resolverPath, "MyTestResolver.xml");

                var assemblyToLoad = env.CreateFile(".dll").Path;

                Directory.CreateDirectory(resolverPath);
                File.WriteAllText(resolverManifest, $@"
                    <SdkResolver2>
                      <Path>{assemblyToLoad}</Path>
                    </SdkResolver2>");

                SdkResolverLoader loader = new SdkResolverLoader();

                var ex = Should.Throw<InvalidProjectFileException>(() => loader.FindPotentialSdkResolvers(root, new MockElementLocation("file")));
                ex.ErrorCode.ShouldBe("MSB4245");
            }
        }

        [Fact]
        public void SdkResolverLoaderErrorsWhenNoDllOrAssemblyFound()
        {
            using (var env = TestEnvironment.Create(_output))
            {
                var root = env.CreateFolder().Path;
                var resolverPath = Path.Combine(root, "MyTestResolver");

                Directory.CreateDirectory(resolverPath);
                SdkResolverLoader loader = new SdkResolverLoader();

                var ex = Should.Throw<InvalidProjectFileException>(() => loader.FindPotentialSdkResolvers(root, new MockElementLocation("file")));
                ex.ErrorCode.ShouldBe("MSB4246");
            }
        }

        [Fact]
        public void SdkResolverLoaderErrorsWhenManifestTargetMissing()
        {
            using (var env = TestEnvironment.Create(_output))
            {
                var root = env.CreateFolder().Path;
                var resolverPath = Path.Combine(root, "MyTestResolver");
                var resolverManifest = Path.Combine(resolverPath, "MyTestResolver.xml");

                // Note this does NOT create the file just gets a valid name
                var assemblyToLoad = env.GetTempFile(".dll").Path;

                Directory.CreateDirectory(resolverPath);
                File.WriteAllText(resolverManifest, $@"
                    <SdkResolver>
                      <Path>{assemblyToLoad}</Path>
                    </SdkResolver>");

                SdkResolverLoader loader = new SdkResolverLoader();
                var ex = Should.Throw<InvalidProjectFileException>(() => loader.FindPotentialSdkResolvers(root, new MockElementLocation("file")));
                ex.ErrorCode.ShouldBe("MSB4247");
            }
        }

        [Fact]
        public void SdkResolverLoaderHonorsIncludeDefaultEnvVar()
        {
            using (var env = TestEnvironment.Create(_output))
            {
                var origIncludeDefault = Environment.GetEnvironmentVariable("MSBUILDINCLUDEDEFAULTSDKRESOLVER");
                try
                {
                    var testRoot = env.CreateFolder().Path;
                    Environment.SetEnvironmentVariable("MSBUILDINCLUDEDEFAULTSDKRESOLVER", "false");
                    SdkResolverLoader loader = new MockSdkResolverLoader()
                    {
                        LoadResolversAction = (resolverPath, loggingContext, location, resolvers) => {
                            resolvers.Add(new MockSdkResolverWithAssemblyPath(resolverPath));
                        }
                    };
                    IList<SdkResolverBase> resolvers = loader.LoadResolvers(_loggingContext, new MockElementLocation("file"));

                    resolvers.Count.ShouldBe(0);
                }
                finally
                {
                    Environment.SetEnvironmentVariable("MSBUILDINCLUDEDEFAULTSDKRESOLVER", origIncludeDefault);
                }
            }
        }

        [Fact]
        public void SdkResolverLoaderHonorsAdditionalResolversFolder()
        {
            using (var env = TestEnvironment.Create(_output))
            {
                var origResolversFolder = Environment.GetEnvironmentVariable("MSBUILDADDITIONALSDKRESOLVERSFOLDER");
                try
                {
                    var testRoot = env.CreateFolder().Path;
                    var additionalRoot = env.CreateFolder().Path;

                    var resolver1 = "Resolver1";
                    var resolver1Path = Path.Combine(additionalRoot, resolver1, $"{resolver1}.dll");
                    Directory.CreateDirectory(Path.Combine(testRoot, resolver1));
                    File.WriteAllText(Path.Combine(testRoot, resolver1, $"{resolver1}.dll"), string.Empty);
                    Directory.CreateDirectory(Path.Combine(additionalRoot, resolver1));
                    File.WriteAllText(resolver1Path, string.Empty);
                    var resolver2 = "Resolver2";
                    var resolver2Path = Path.Combine(testRoot, resolver2, $"{resolver2}.dll");
                    Directory.CreateDirectory(Path.Combine(testRoot, resolver2));
                    File.WriteAllText(resolver2Path, string.Empty);
                    var resolver3 = "Resolver3";
                    var resolver3Path = Path.Combine(additionalRoot, resolver3, $"{resolver3}.dll");
                    Directory.CreateDirectory(Path.Combine(additionalRoot, resolver3));
                    File.WriteAllText(resolver3Path, string.Empty);

                    Environment.SetEnvironmentVariable("MSBUILDADDITIONALSDKRESOLVERSFOLDER", additionalRoot);

                    SdkResolverLoader loader = new SdkResolverLoader();
                    IList<string> resolvers = loader.FindPotentialSdkResolvers(testRoot, new MockElementLocation("file"));

                    resolvers.ShouldBeSameIgnoringOrder(new[] { resolver1Path, resolver2Path, resolver3Path });
                }
                finally
                {
                    Environment.SetEnvironmentVariable("MSBUILDADDITIONALSDKRESOLVERSFOLDER", origResolversFolder);
                }
            }
        }

        private class MockSdkResolverThatDoesNotLoad : SdkResolverBase
        {
            public const string ExpectedMessage = "A8BB8B3131D3475D881ACD3AF8D75BD6";

            public MockSdkResolverThatDoesNotLoad()
            {
                throw new Exception(ExpectedMessage);
            }

            public override string Name => nameof(MockSdkResolverThatDoesNotLoad);

            public override int Priority => 0;

            public override SdkResultBase Resolve(SdkReference sdkReference, SdkResolverContextBase resolverContext, SdkResultFactoryBase factory)
            {
                throw new NotImplementedException();
            }
        }

        private class MockSdkResolverNoPublicConstructor : SdkResolverBase
        {
            private MockSdkResolverNoPublicConstructor()
            {
            }

            public override string Name => nameof(MockSdkResolverNoPublicConstructor);

            public override int Priority => 0;

            public override SdkResultBase Resolve(SdkReference sdkReference, SdkResolverContextBase resolverContext, SdkResultFactoryBase factory)
            {
                throw new NotImplementedException();
            }
        }

        private class MockSdkResolverWithAssemblyPath : SdkResolverBase
        {
            public string AssemblyPath;

            public MockSdkResolverWithAssemblyPath(string assemblyPath = "")
            {
                AssemblyPath = assemblyPath;
            }

            public override string Name => nameof(MockSdkResolverWithAssemblyPath);

            public override int Priority => 0;

            public override SdkResultBase Resolve(SdkReference sdkReference, SdkResolverContextBase resolverContext, SdkResultFactoryBase factory)
            {
                throw new NotImplementedException();
            }
        }

        private class MockSdkResolverLoader : SdkResolverLoader
        {
            public Func<string, LoggingContext, ElementLocation, Assembly> LoadResolverAssemblyFunc { get; set; }

            public Func<string, ElementLocation, IList<string>> FindPotentialSdkResolversFunc { get; set; }

            public Func<Assembly, IEnumerable<Type>> GetResolverTypesFunc { get; set; }

            public Action<string, LoggingContext, ElementLocation, List<SdkResolver>> LoadResolversAction { get; set; }

            protected override Assembly LoadResolverAssembly(string resolverPath, LoggingContext loggingContext, ElementLocation location)
            {
                if (LoadResolverAssemblyFunc != null)
                {
                    return LoadResolverAssemblyFunc(resolverPath, loggingContext, location);
                }

                return base.LoadResolverAssembly(resolverPath, loggingContext, location);
            }

            protected override IEnumerable<Type> GetResolverTypes(Assembly assembly)
            {
                if (GetResolverTypesFunc != null)
                {
                    return GetResolverTypesFunc(assembly);
                }

                return base.GetResolverTypes(assembly);
            }

            internal override IList<string> FindPotentialSdkResolvers(string rootFolder, ElementLocation location)
            {
                if (FindPotentialSdkResolversFunc != null)
                {
                    return FindPotentialSdkResolversFunc(rootFolder, location);
                }

                return base.FindPotentialSdkResolvers(rootFolder, location);
            }

            protected override void LoadResolvers(string resolverPath, LoggingContext loggingContext, ElementLocation location, List<SdkResolver> resolvers)
            {
                if (LoadResolversAction != null)
                {
                    LoadResolversAction(resolverPath, loggingContext, location, resolvers);
                    return;
                }
                base.LoadResolvers(resolverPath, loggingContext, location, resolvers);
            }
        }
    }
}


<|start_filename|>src/Build.OM.UnitTests/Construction/ProjectItemElement_Tests.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.IO;
using System.Linq;
using System.Xml;

using Microsoft.Build.Evaluation;
using Microsoft.Build.Construction;

using InvalidProjectFileException = Microsoft.Build.Exceptions.InvalidProjectFileException;
using Xunit;

namespace Microsoft.Build.UnitTests.OM.Construction
{
    /// <summary>
    /// Test the ProjectItemElement class
    /// </summary>
    public class ProjectItemElement_Tests
    {
        private const string RemoveInTarget = @"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i Remove='i'/>
                            </ItemGroup>
                        </Target>
                    </Project>
                ";

        private const string RemoveOutsideTarget = @"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                            <ItemGroup>
                                <i Remove='i'/>
                            </ItemGroup>
                    </Project>
                ";
        private const string IncludeOutsideTarget = @"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <i Include='i'/>
                        </ItemGroup>
                    </Project>
                ";
        private const string IncludeInsideTarget = @"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i Include='i'/>
                            </ItemGroup>
                        </Target>
                    </Project>
                ";
        private const string UpdateOutsideTarget = @"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                            <ItemGroup>
                                <i Update='i'/>
                            </ItemGroup>
                    </Project>
                ";
        private const string UpdateInTarget = @"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i Update='i'/>
                            </ItemGroup>
                        </Target>
                    </Project>
                ";

        /// <summary>
        /// Read item with no children
        /// </summary>
        [Theory]
        [InlineData(IncludeInsideTarget)]
        [InlineData(IncludeOutsideTarget)]
        public void ReadNoChildren(string project)
        {
            ProjectItemElement item = GetItemFromContent(project);

            Assert.Equal(0, Helpers.Count(item.Metadata));
        }

        /// <summary>
        /// Read item with no include
        /// </summary>
        [Theory]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <i/>
                        </ItemGroup>
                    </Project>
                ")]
        // https://github.com/Microsoft/msbuild/issues/900
        //[InlineData(@"
        //            <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
        //                <Target Name='t'>
        //                    <ItemGroup>
        //                        <i/>
        //                    </ItemGroup>
        //                </Target>
        //            </Project>
        //        ")]
        public void ReadInvalidNoInclude(string project)
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                ProjectRootElement.Create(XmlReader.Create(new StringReader(project)));
            }
           );
        }

        /// <summary>
        /// Read item which contains text
        /// </summary>
        [Theory]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <i Include='a'>error text</i>
                        </ItemGroup>
                    </Project>
                ")]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i Include='a'>error text</i>
                            </ItemGroup>
                        </Target>
                    </Project>
                ")]
        public void ReadInvalidContainsText(string project)
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                ProjectRootElement.Create(XmlReader.Create(new StringReader(project)));
            }
           );
        }

        /// <summary>
        /// Read item with empty include
        /// </summary>
        [Theory]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <i Include=''/>
                        </ItemGroup>
                    </Project>
                ")]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i Include=''/>
                            </ItemGroup>
                        </Target>
                    </Project>
                ")]
        public void ReadInvalidEmptyInclude(string project)
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                ProjectRootElement.Create(XmlReader.Create(new StringReader(project)));
            }
           );
        }

        /// <summary>
        /// Read item with reserved element name
        /// </summary>
        [Theory]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <PropertyGroup Include='i1'/>
                        </ItemGroup>
                    </Project>
                ")]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <PropertyGroup Include='i1'/>
                            </ItemGroup>
                        </Target>
                    </Project>
                ")]
        public void ReadInvalidReservedElementName(string project)
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                ProjectRootElement.Create(XmlReader.Create(new StringReader(project)));
            }
           );
        }

        /// <summary>
        /// Read item with Exclude without Include
        /// </summary>
        [Fact]
        public void ReadInvalidExcludeWithoutInclude()
        {
            var project = @"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <i Exclude='i1'/>
                        </ItemGroup>
                    </Project>
                ";

            var exception =
                Assert.Throws<InvalidProjectFileException>(
                    () => { ProjectRootElement.Create(XmlReader.Create(new StringReader(project))); }
                    );
            
            Assert.Contains("Items that are outside Target elements must have one of the following operations: Include, Update, or Remove.", exception.Message);
        }
        
        /// <summary>
        /// Read item with Exclude without Include under a target
        /// </summary>
        [Fact]
        public void ReadInvalidExcludeWithoutIncludeUnderTarget()
        {
            var project = @"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i Exclude='i1'/>
                            </ItemGroup>
                        </Target>
                    </Project>
                ";

            var exception =
                Assert.Throws<InvalidProjectFileException>(
                    () => { ProjectRootElement.Create(XmlReader.Create(new StringReader(project))); }
                    );
            
            Assert.Contains("The attribute \"Exclude\" in element <i> is unrecognized.", exception.Message);
        }

        [Theory]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <i include='i1'/>
                        </ItemGroup>
                    </Project>
                ")]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i include='i1'/>
                            </ItemGroup>
                        </Target>
                    </Project>
                ")]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <i Include='i1' exclude='i2' />
                        </ItemGroup>
                    </Project>
                ")]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i Include='i1' exclude='i2' />
                            </ItemGroup>
                        </Target>
                    </Project>
                ")]
        public void ReadInvalidItemAttributeCasing(string project)
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                ProjectRootElement.Create(XmlReader.Create(new StringReader(project)));
            }
           );
        }

        /// <summary>
        /// Basic reading of items
        /// </summary>
        [Theory]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <i1 Include='i'>
                                <m1>v1</m1>
                            </i1>
                            <i2 Include='i' Exclude='j'>
                                <m2>v2</m2>
                            </i2>
                        </ItemGroup>
                    </Project>
                ")]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i1 Include='i'>
                                    <m1>v1</m1>
                                </i1>
                                <i2 Include='i' Exclude='j'>
                                    <m2>v2</m2>
                                </i2>
                            </ItemGroup>
                        </Target>
                    </Project>
                ")]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <i1 Include='i' m1='v1' />
                            <i2 Include='i' Exclude='j' m2='v2' />
                        </ItemGroup>
                    </Project>
                ")]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i1 Include='i' m1='v1' />
                                <i2 Include='i' Exclude='j' m2='v2' />
                            </ItemGroup>
                        </Target>
                    </Project>
                ")]
        public void ReadBasic(string project)
        {
            ProjectRootElement projectElement = ProjectRootElement.Create(XmlReader.Create(new StringReader(project)));
            ProjectItemGroupElement itemGroup = (ProjectItemGroupElement) projectElement.AllChildren.FirstOrDefault(c => c is ProjectItemGroupElement);

            var items = Helpers.MakeList(itemGroup.Items);

            Assert.Equal("i1", items[0].ItemType);
            Assert.Equal("i", items[0].Include);

            var metadata1 = Helpers.MakeList(items[0].Metadata);
            Assert.Single(metadata1);
            Assert.Equal("m1", metadata1[0].Name);
            Assert.Equal("v1", metadata1[0].Value);

            var metadata2 = Helpers.MakeList(items[1].Metadata);
            Assert.Equal("i2", items[1].ItemType);
            Assert.Equal("i", items[1].Include);
            Assert.Equal("j", items[1].Exclude);
            Assert.Single(metadata2);
            Assert.Equal("m2", metadata2[0].Name);
            Assert.Equal("v2", metadata2[0].Value);
        }

        /// <summary>
        /// Read metadata on item
        /// </summary>
        [Theory]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <i1 Include='i'>
                                <m1>v1</m1>
                                <m2 Condition='c'>v2</m2>
                                <m1>v3</m1>
                            </i1>
                        </ItemGroup>
                    </Project>
                ")]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i1 Include='i'>
                                    <m1>v1</m1>
                                    <m2 Condition='c'>v2</m2>
                                    <m1>v3</m1>
                                </i1>
                            </ItemGroup>
                        </Target>
                    </Project>
                ")]
        public void ReadMetadata(string project)
        {
            ProjectRootElement projectElement = ProjectRootElement.Create(XmlReader.Create(new StringReader(project)));
            ProjectItemGroupElement itemGroup = (ProjectItemGroupElement)projectElement.AllChildren.FirstOrDefault(c => c is ProjectItemGroupElement);
            ProjectItemElement item = Helpers.GetFirst(itemGroup.Items);

            var metadata = Helpers.MakeList(item.Metadata);
            Assert.Equal(3, metadata.Count);
            Assert.Equal("m1", metadata[0].Name);
            Assert.Equal("v1", metadata[0].Value);
            Assert.Equal("m2", metadata[1].Name);
            Assert.Equal("v2", metadata[1].Value);
            Assert.Equal("c", metadata[1].Condition);
            Assert.Equal("m1", metadata[2].Name);
            Assert.Equal("v3", metadata[2].Value);
        }

        [Theory]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <i Include='i1' Update='i2'/>
                        </ItemGroup>
                    </Project>
                ")]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i Include='i1' Update='i2'/>
                            </ItemGroup>
                        </Target>
                    </Project>
                ")]
        public void ReadInvalidUpdateWithInclude(string project)
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                ProjectRootElement.Create(XmlReader.Create(new StringReader(project)));
            }
           );
        }

        [Theory]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <i Include='i1' Exclude='i1' Update='i2'/>
                        </ItemGroup>
                    </Project>
                ")]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i Include='i1' Exclude='i1' Update='i2'/>
                            </ItemGroup>
                        </Target>
                    </Project>
                ")]
        public void ReadInvalidUpdateWithIncludeAndExclude(string project)
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                ProjectRootElement.Create(XmlReader.Create(new StringReader(project)));
            }
           );
        }

        [Theory]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <i Exclude='i1' Update='i2'/>
                        </ItemGroup>
                    </Project>
                ")]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i Exclude='i1' Update='i2'/>
                            </ItemGroup>
                        </Target>
                    </Project>
                ")]
        public void ReadInvalidUpdateWithExclude(string project)
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                ProjectRootElement.Create(XmlReader.Create(new StringReader(project)));
            }
           );
        }

        /// <summary>
        /// Read item with Remove inside of Target, but with metadata
        /// </summary>
        [Theory]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <i Remove='i1'>
                                    <m> </m>
                            </i>
                        </ItemGroup>
                    </Project>
                ")]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i Remove='i1'>
                                    <m> </m>
                                </i>
                            </ItemGroup>
                        </Target>
                    </Project>
                ")]
        public void ReadInvalidRemoveWithMetadata(string project)
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                ProjectRootElement.Create(XmlReader.Create(new StringReader(project)));
            }
           );
        }

        /// <summary>
        /// Read item with Remove inside of Target, but with Exclude: not currently supported
        /// </summary>
        [Theory]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <i Exclude='i1' Remove='i1'/>
                        </ItemGroup>
                    </Project>
                ")]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i Exclude='i1' Remove='i1'/>
                            </ItemGroup>
                        </Target>
                    </Project>
                ")]
        public void ReadInvalidExcludeAndRemove(string project)
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                ProjectRootElement.Create(XmlReader.Create(new StringReader(project)));
            }
           );
        }

        /// <summary>
        /// Read item with Remove inside of Target, but with Include: not currently supported
        /// </summary>
        [Theory]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <i Include='i1' Remove='i1'/>
                        </ItemGroup>
                    </Project>
                ")]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i Include='i1' Remove='i1'/>
                            </ItemGroup>
                        </Target>
                    </Project>
                ")]
        public void ReadInvalidIncludeAndRemove(string project)
        {
            Assert.Throws<InvalidProjectFileException>(() =>
            {
                ProjectRootElement.Create(XmlReader.Create(new StringReader(project)));
            }
           );
        }

        /// <summary>
        /// Read item with Remove inside of Target
        /// </summary>
        [Theory]
        [InlineData(RemoveInTarget)]
        [InlineData(RemoveOutsideTarget)]
        public void ReadValidRemove(string project)
        {
            var item = GetItemFromContent(project);

            Assert.Equal("i", item.Remove);
        }

        /// <summary>
        /// Read item with Remove inside of Target
        /// </summary>
        [Theory]
        [InlineData(UpdateInTarget)]
        [InlineData(UpdateOutsideTarget)]
        public void ReadValidUpdate(string project)
        {
            var item = GetItemFromContent(project);

            Assert.Equal("i", item.Update);
        }

        /// <summary>
        /// Read item with Exclude without Include, inside of Target
        /// </summary>
        [Theory]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <ItemGroup>
                            <i Include='i1' Exclude='i2'/>
                        </ItemGroup>
                    </Project>
                ")]
        [InlineData(@"
                    <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' >
                        <Target Name='t'>
                            <ItemGroup>
                                <i Include='i1' Exclude='i2'/>
                            </ItemGroup>
                        </Target>
                    </Project>
                ")]
        public void ReadValidIncludeExclude(string project)
        {
            var item = GetItemFromContent(project);

            Assert.Equal("i1", item.Include);
            Assert.Equal("i2", item.Exclude);
        }

        /// <summary>
        /// Set the include on an item
        /// </summary>
        [Theory]
        [InlineData(IncludeInsideTarget)]
        [InlineData(IncludeOutsideTarget)]
        public void SetInclude(string project)
        {
            ProjectItemElement item = GetItemFromContent(project);

            item.Include = "ib";

            Assert.Equal("ib", item.Include);
        }

        /// <summary>
        /// Set empty include: this removes it
        /// </summary>
        [Theory]
        [InlineData(IncludeInsideTarget)]
        [InlineData(IncludeOutsideTarget)]
        public void SetEmptyInclude(string project)
        {
            ProjectItemElement item = GetItemFromContent(project);

            item.Include = String.Empty;

            Assert.Equal(String.Empty, item.Include);
        }

        /// <summary>
        /// Set null empty : this removes it
        /// </summary>
        [Theory]
        [InlineData(IncludeInsideTarget)]
        [InlineData(IncludeOutsideTarget)]
        public void SetNullInclude(string project)
        {
            ProjectItemElement item = GetItemFromContent(project);

            item.Include = null;

            Assert.Equal(String.Empty, item.Include);
        }

        /// <summary>
        /// Set the Exclude on an item
        /// </summary>
        [Theory]
        [InlineData(IncludeInsideTarget)]
        [InlineData(IncludeOutsideTarget)]
        public void SetExclude(string project)
        {
            ProjectItemElement item = GetItemFromContent(project);

            item.Exclude = "ib";

            Assert.Equal("ib", item.Exclude);
        }

        /// <summary>
        /// Set empty Exclude: this removes it
        /// </summary>
        [Theory]
        [InlineData(IncludeInsideTarget)]
        [InlineData(IncludeOutsideTarget)]
        public void SetEmptyExclude(string project)
        {
            ProjectItemElement item = GetItemFromContent(project);

            item.Exclude = String.Empty;

            Assert.Equal(String.Empty, item.Exclude);
        }

        /// <summary>
        /// Set null Exclude: this removes it
        /// </summary>
        [Theory]
        [InlineData(IncludeInsideTarget)]
        [InlineData(IncludeOutsideTarget)]
        public void SetNullExclude(string project)
        {
            ProjectItemElement item = GetItemFromContent(project);

            item.Exclude = null;

            Assert.Equal(String.Empty, item.Exclude);
        }

        /// <summary>
        /// Set Remove when Include is present, inside a target
        /// </summary>
        [Theory]
        [InlineData(IncludeInsideTarget)]
        [InlineData(IncludeOutsideTarget)]
        public void SetInvalidRemoveWithInclude(string project)
        {
            Assert.Throws<InvalidOperationException>(() =>
            {
                ProjectItemElement item = GetItemFromContent(project);

                item.Remove = "i1";
            }
           );
        }

        /// <summary>
        /// Set Update when Include is present
        /// </summary>
        [Theory]
        [InlineData(IncludeInsideTarget)]
        [InlineData(IncludeOutsideTarget)]
        public void SetInvalidUpdateWithInclude(string project)
        {
            Assert.Throws<InvalidOperationException>(() =>
            {
                ProjectItemElement item = GetItemFromContent(project);

                item.Update = "i1";
            }
           );
        }

        /// <summary>
        /// Set the Remove on an item
        /// </summary>
        [Theory]
        [InlineData(RemoveInTarget)]
        [InlineData(RemoveOutsideTarget)]
        public void SetRemove(string project)
        {
            ProjectItemElement item = GetItemFromContent(project);

            item.Remove = "ib";

            Assert.Equal("ib", item.Remove);
        }

        /// <summary>
        /// Set empty Remove: this removes it
        /// </summary>
        [Theory]
        [InlineData(RemoveInTarget)]
        [InlineData(RemoveOutsideTarget)]
        public void SetEmptyRemove(string project)
        {
            ProjectItemElement item = GetItemFromContent(project);

            item.Remove = String.Empty;

            Assert.Equal(String.Empty, item.Remove);
        }

        /// <summary>
        /// Set null Remove: this removes it
        /// </summary>
        [Theory]
        [InlineData(RemoveInTarget)]
        [InlineData(RemoveOutsideTarget)]
        public void SetNullRemove(string project)
        {
            ProjectItemElement item = GetItemFromContent(project);

            item.Remove = null;

            Assert.Equal(String.Empty, item.Remove);
        }

        /// <summary>
        /// Set Include when Remove is present
        /// </summary>
        [Theory]
        [InlineData(RemoveInTarget)]
        [InlineData(RemoveOutsideTarget)]
        public void SetInvalidIncludeWithRemove(string project)
        {
            Assert.Throws<InvalidOperationException>(() =>
            {
                ProjectItemElement item = GetItemFromContent(project);

                item.Include = "i1";
            }
           );
        }

        /// <summary>
        /// Set Exclude when Remove is present
        /// </summary>
        [Theory]
        [InlineData(RemoveInTarget)]
        [InlineData(RemoveOutsideTarget)]
        public void SetInvalidExcludeWithRemove(string project)
        {
            Assert.Throws<InvalidOperationException>(() =>
            {
                ProjectItemElement item = GetItemFromContent(project);

                item.Exclude = "i1";
            }
           );
        }
        
        /// <summary>
        /// Set Update when Remove is present
        /// </summary>
        [Theory]
        [InlineData(RemoveInTarget)]
        [InlineData(RemoveOutsideTarget)]
        public void SetInvalidUpdateWithRemove(string project)
        {
            Assert.Throws<InvalidOperationException>(() =>
            {
                ProjectItemElement item = GetItemFromContent(project);

                item.Update = "i1";
            }
           );
        }

        /// 
        /// <summary>
        /// Set the Update on an item
        /// </summary>
        [Theory]
        [InlineData(UpdateInTarget)]
        [InlineData(UpdateOutsideTarget)]
        public void SetUpdate(string project)
        {
            ProjectItemElement item = GetItemFromContent(project);

            item.Update = "ib";

            Assert.Equal("ib", item.Update);
        }

        /// <summary>
        /// Set empty Update: this removes it
        /// </summary>
        [Theory]
        [InlineData(UpdateInTarget)]
        [InlineData(UpdateOutsideTarget)]
        public void SetEmptyUpdate(string project)
        {
            ProjectItemElement item = GetItemFromContent(project);

            item.Update = String.Empty;

            Assert.Equal(String.Empty, item.Update);
        }

        /// <summary>
        /// Set null Update: this removes it
        /// </summary>
        [Theory]
        [InlineData(UpdateInTarget)]
        [InlineData(UpdateOutsideTarget)]
        public void SetNullUpdate(string project)
        {
            ProjectItemElement item = GetItemFromContent(project);

            item.Update = null;

            Assert.Equal(String.Empty, item.Update);
        }

        /// <summary>
        /// Set Include when Update is present
        /// </summary>
        [Theory]
        [InlineData(UpdateInTarget)]
        [InlineData(UpdateOutsideTarget)]
        public void SetInvalidIncludeWithUpdate(string project)
        {
            Assert.Throws<InvalidOperationException>(() =>
            {
                ProjectItemElement item = GetItemFromContent(project);

                item.Include = "i1";
            }
           );
        }

        /// <summary>
        /// Set Exclude when Update is present
        /// </summary>
        [Theory]
        [InlineData(UpdateInTarget)]
        [InlineData(UpdateOutsideTarget)]
        public void SetInvalidExcludeWithUpdate(string project)
        {
            Assert.Throws<InvalidOperationException>(() =>
            {
                ProjectItemElement item = GetItemFromContent(project);

                item.Exclude = "i1";
            }
           );
        }

        /// <summary>
        /// Set the condition on an item
        /// </summary>
        [Theory]
        [InlineData(UpdateInTarget)]
        [InlineData(UpdateOutsideTarget)]
        public void SetCondition(string project)
        {
            ProjectItemElement item = GetItemFromContent(project);

            item.Condition = "c";

            Assert.Equal("c", item.Condition);
        }

        /// <summary>
        /// Setting condition should dirty the project
        /// </summary>
        [Fact]
        public void SettingItemConditionDirties()
        {
            Project project = new Project();
            ProjectItem item = project.AddItem("i", "i1")[0];
            project.ReevaluateIfNecessary();

            item.Xml.Condition = "false";
            project.ReevaluateIfNecessary();

            Assert.Empty(Helpers.MakeList(project.Items));
        }

        /// <summary>
        /// Setting include should dirty the project
        /// </summary>
        [Fact]
        public void SettingItemIncludeDirties()
        {
            Project project = new Project();
            ProjectItem item = project.AddItem("i", "i1")[0];
            project.ReevaluateIfNecessary();

            item.Xml.Include = "i2";
            project.ReevaluateIfNecessary();

            Assert.Equal("i2", Helpers.GetFirst(project.Items).EvaluatedInclude);
        }

        /// <summary>
        /// Setting exclude should dirty the project
        /// </summary>
        [Fact]
        public void SettingItemExcludeDirties()
        {
            Project project = new Project();
            ProjectItem item = project.AddItem("i", "i1")[0];
            project.ReevaluateIfNecessary();

            item.Xml.Exclude = "i1";
            project.ReevaluateIfNecessary();

            Assert.Empty(Helpers.MakeList(project.Items));
        }

        /// <summary>
        /// Setting exclude should dirty the project
        /// </summary>
        [Fact]
        public void SettingItemRemoveDirties()
        {
            ProjectRootElement project = ProjectRootElement.Create();

            ProjectItemElement item = project.AddTarget("t").AddItemGroup().AddItem("i", "i1");
            item.Include = null;
            Helpers.ClearDirtyFlag(project);

            Assert.False(project.HasUnsavedChanges);

            item.Remove = "i2";

            Assert.Equal("i2", item.Remove);
            Assert.True(project.HasUnsavedChanges);
        }

        /// <summary>
        /// Setting update should dirty the project
        /// </summary>
        [Fact]
        public void SettingItemUpdateDirties()
        {
            ProjectRootElement project = ProjectRootElement.Create();

            ProjectItemElement item = project.AddItemGroup().AddItem("i", "i1");
            item.Include = null;
            Helpers.ClearDirtyFlag(project);

            Assert.False(project.HasUnsavedChanges);

            item.Update = "i2";

            Assert.Equal("i2", item.Update);
            Assert.True(project.HasUnsavedChanges);
        }

        private static ProjectItemElement GetItemFromContent(string content)
        {
            var project = ProjectRootElement.Create(XmlReader.Create(new StringReader(content)));
            return Helpers.GetFirst(project.Items);
        }
    }
}

<|start_filename|>src/Tasks/ManifestUtil/CngLightup.cs<|end_filename|>
﻿// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==

// Supported preprocessor declarations:
//
// CNG_LIGHTUP_NO_SYSTEM_CORE
//   Indicates that this file is being processed from a context that cannot access System.Core.
//     * The assembly must be built with <GenerateAssemblyRefs>true</GenerateAssemblyRefs>
//     * The ECDSA methods are not available

// There are cases where we have multiple assemblies that are going to import this file and 
// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning
// that the type is found both in the source and in a referenced assembly. The compiler will prefer 
// the version of the type defined in the source
//
// In order to disable the warning for this type we are disabling this warning for this entire file.
#pragma warning disable 436

using System.Diagnostics;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;

namespace System.Security.Cryptography
{
    internal static partial class CngLightup
    {
        private const string DsaOid = "1.2.840.10040.4.1";
        private const string RsaOid = "1.2.840.113549.1.1.1";

        private const string HashAlgorithmNameTypeName = "System.Security.Cryptography.HashAlgorithmName";
        private const string RSASignaturePaddingTypeName = "System.Security.Cryptography.RSASignaturePadding";
        private const string RSAEncryptionPaddingTypeName = "System.Security.Cryptography.RSAEncryptionPadding";
        private const string RSACngTypeName = "System.Security.Cryptography.RSACng";
        private const string DSACngTypeName = "System.Security.Cryptography.DSACng";

        // If 4.6 is guaranteed as a baseline, then these field references should become typeof()
        // expressions, and the methods that consume them can get significantly easier.
        private static readonly Type s_hashAlgorithmNameType =
            typeof(object).Assembly.GetType(HashAlgorithmNameTypeName, false);

        private static readonly Type s_rsaSignaturePaddingType =
            typeof(object).Assembly.GetType(RSASignaturePaddingTypeName, false);

        private static readonly Type s_rsaEncryptionPaddingType =
            typeof(object).Assembly.GetType(RSAEncryptionPaddingTypeName, false);

        private static readonly object s_pkcs1SignaturePadding =
            s_rsaSignaturePaddingType?.GetProperty("Pkcs1", BindingFlags.Static | BindingFlags.Public).GetValue(null);

        private static readonly object s_pkcs1EncryptionPadding =
            s_rsaEncryptionPaddingType?.GetProperty("Pkcs1", BindingFlags.Static | BindingFlags.Public).GetValue(null);

        private static readonly object s_oaepSha1EncryptionPadding =
            s_rsaEncryptionPaddingType?.GetProperty("OaepSHA1", BindingFlags.Static | BindingFlags.Public).GetValue(null);

        private static readonly Lazy<bool> s_preferRsaCng = new Lazy<bool>(DetectRsaCngSupport);

        private static volatile Func<X509Certificate2, DSA> s_getDsaPublicKey;
        private static volatile Func<X509Certificate2, DSA> s_getDsaPrivateKey;

        private static volatile Func<X509Certificate2, RSA> s_getRsaPublicKey;
        private static volatile Func<X509Certificate2, RSA> s_getRsaPrivateKey;
        private static volatile Func<RSA, byte[], string, byte[]> s_rsaPkcs1SignMethod;
        private static volatile Func<RSA, byte[], byte[], string, bool> s_rsaPkcs1VerifyMethod;
        private static volatile Func<RSA, byte[], byte[]> s_rsaPkcs1EncryptMethod;
        private static volatile Func<RSA, byte[], byte[]> s_rsaPkcs1DecryptMethod;
        private static volatile Func<RSA, byte[], byte[]> s_rsaOaepSha1EncryptMethod;
        private static volatile Func<RSA, byte[], byte[]> s_rsaOaepSha1DecryptMethod;

#if !CNG_LIGHTUP_NO_SYSTEM_CORE
        private static volatile Func<X509Certificate2, ECDsa> s_getECDsaPublicKey;
        private static volatile Func<X509Certificate2, ECDsa> s_getECDsaPrivateKey;
#endif

        internal static RSA GetRSAPublicKey(X509Certificate2 cert)
        {
            if (s_getRsaPublicKey == null)
            {
                if (s_preferRsaCng.Value)
                {
                    s_getRsaPublicKey =
                        BindCoreDelegate<RSA>("RSA", isPublic: true) ??
                        BindGetCapiPublicKey<RSA, RSACryptoServiceProvider>(RsaOid);
                }
                else
                {
                    s_getRsaPublicKey = BindGetCapiPublicKey<RSA, RSACryptoServiceProvider>(RsaOid);
                }
            }

            return s_getRsaPublicKey(cert);
        }

        internal static RSA GetRSAPrivateKey(X509Certificate2 cert)
        {
            if (s_getRsaPrivateKey == null)
            {
                if (s_preferRsaCng.Value)
                {
                    s_getRsaPrivateKey =
                        BindCoreDelegate<RSA>("RSA", isPublic: false) ??
                        BindGetCapiPrivateKey<RSA>(RsaOid, csp => new RSACryptoServiceProvider(csp));
                }
                else
                {
                    s_getRsaPrivateKey = BindGetCapiPrivateKey<RSA>(RsaOid, csp => new RSACryptoServiceProvider(csp));
                }
            }

            return s_getRsaPrivateKey(cert);
        }

        internal static DSA GetDSAPublicKey(X509Certificate2 cert)
        {
            if (s_getDsaPublicKey == null)
            {
                s_getDsaPublicKey =
                    BindCoreDelegate<DSA>("DSA", isPublic: true) ??
                    BindGetCapiPublicKey<DSA, DSACryptoServiceProvider>(DsaOid);
            }

            return s_getDsaPublicKey(cert);
        }

        internal static DSA GetDSAPrivateKey(X509Certificate2 cert)
        {
            if (s_getDsaPrivateKey == null)
            {
                s_getDsaPrivateKey =
                    BindCoreDelegate<DSA>("DSA", isPublic: false) ??
                    BindGetCapiPrivateKey<DSA>(DsaOid, csp => new DSACryptoServiceProvider(csp));
            }

            return s_getDsaPrivateKey(cert);
        }

#if !CNG_LIGHTUP_NO_SYSTEM_CORE
        internal static ECDsa GetECDsaPublicKey(X509Certificate2 cert)
        {
            // ECDsa has no fallback mode, it was only available via the System.Core extension method.
            // With this lightup path, GetECDsaPublicKey can return null for an ECDSA certificate, just because
            // System.Core is too old.
            if (s_getECDsaPublicKey == null)
            {
                s_getECDsaPublicKey = BindCoreDelegate<ECDsa>("ECDsa", isPublic: true) ?? (c => null);
            }

            return s_getECDsaPublicKey(cert);
        }

        internal static ECDsa GetECDsaPrivateKey(X509Certificate2 cert)
        {
            // ECDsa has no fallback mode, it was only available via the System.Core extension method.
            // With this lightup path, GetECDsaPrivateKey can return null for an ECDSA certificate, just because
            // System.Core is too old.
            if (s_getECDsaPrivateKey == null)
            {
                s_getECDsaPrivateKey = BindCoreDelegate<ECDsa>("ECDsa", isPublic: false) ?? (c => null);
            }

            return s_getECDsaPrivateKey(cert);
        }
#endif

        // When 4.6 is guaranteed as the minimum patch baseline, this method should be moved to a direct
        // call to RSA.SignData.  Or, even better, removed and just used inline.
        internal static byte[] Pkcs1SignData(RSA rsa, byte[] data, string hashAlgorithmName)
        {
            // Because RSACryptoServiceProvider existed in 4.5, but RSACng didn't, and RSA's SignData
            // method requires types that aren't in 4.5, try RSACryptoServiceProvider's way first.
            if (rsa is RSACryptoServiceProvider rsaCsp)
            {
                return rsaCsp.SignData(data, hashAlgorithmName);
            }

            if (s_rsaPkcs1SignMethod == null)
            {
                // [X] SignData(byte[] data, HashAlgorithmName hashAlgorithmName, RSASignaturePadding padding)
                // [ ] SignData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithmName, RSASignaturePadding padding)
                // [ ] SignData(Stream data, HashAlgorithmName hashAlgorithmName, RSASignaturePadding padding)

                Debug.Assert(s_hashAlgorithmNameType != null);
                Debug.Assert(s_rsaSignaturePaddingType != null);
                Debug.Assert(s_pkcs1SignaturePadding != null);
                Type[] signatureTypes = { typeof(byte[]), s_hashAlgorithmNameType, s_rsaSignaturePaddingType };

                MethodInfo signDataMethod = typeof(RSA).GetMethod(
                    "SignData",
                    BindingFlags.Public | BindingFlags.Instance,
                    null,
                    signatureTypes,
                    null);

                Debug.Assert(signDataMethod != null, "Cannot find RSA.SignData(byte[], HashAlgorithmName, RSASignaturePadding)");

                // Because the HashAlgorithmName and RSASignaturePadding types aren't guaranteed available at
                // assembly time (though they really need to be if the runtime makes it here...) the delegate binding
                // is a bit harder than normal.
                Type delegateType = typeof(Func<,,,,>).MakeGenericType(
                    typeof(RSA),
                    typeof(byte[]),
                    s_hashAlgorithmNameType,
                    s_rsaSignaturePaddingType,
                    typeof(byte[]));

                Delegate openDelegate = Delegate.CreateDelegate(delegateType, signDataMethod);

                s_rsaPkcs1SignMethod =
                    (delegateRsa, delegateData, delegateAlgorithm) =>
                    {
                        object hashAlgorithmNameObject = Activator.CreateInstance(s_hashAlgorithmNameType, delegateAlgorithm);

                        object[] args = { delegateRsa, delegateData, hashAlgorithmNameObject, s_pkcs1SignaturePadding };
                        return (byte[])openDelegate.DynamicInvoke(args);
                    };
            }

            Debug.Assert(s_rsaPkcs1SignMethod != null);
            return s_rsaPkcs1SignMethod(rsa, data, hashAlgorithmName);
        }

        internal static bool Pkcs1VerifyData(RSA rsa, byte[] data, byte[] signature, string hashAlgorithmName)
        {
            // Because RSACryptoServiceProvider existed in 4.5, but RSACng didn't, and RSA's SignData
            // method requires types that aren't in 4.5, try RSACryptoServiceProvider's way first.
            if (rsa is RSACryptoServiceProvider rsaCsp)
            {
                return rsaCsp.VerifyData(data, hashAlgorithmName, signature);
            }

            if (s_rsaPkcs1VerifyMethod == null)
            {
                // [X] VerifyData(byte[] data, byte[] signature, HashAlgorithmName hashAlgorithmName, RSASignaturePadding padding)
                // [ ] VerifyData(byte[] data, int offset, int count, byte[] signature, HashAlgorithmName hashAlgorithmName, RSASignaturePadding padding)
                // [ ] VerifyData(Stream data, byte[] signature, HashAlgorithmName hashAlgorithmName, RSASignaturePadding padding)

                Debug.Assert(s_hashAlgorithmNameType != null);
                Debug.Assert(s_rsaSignaturePaddingType != null);
                Debug.Assert(s_pkcs1SignaturePadding != null);
                Type[] signatureTypes = { typeof(byte[]), typeof(byte[]), s_hashAlgorithmNameType, s_rsaSignaturePaddingType };

                MethodInfo verifyDataMethod = typeof(RSA).GetMethod(
                    "VerifyData",
                    BindingFlags.Public | BindingFlags.Instance,
                    null,
                    signatureTypes,
                    null);

                Debug.Assert(
                    verifyDataMethod != null,
                    "Cannot find RSA.VerifyData(byte[], byte[], HashAlgorithmName, RSASignaturePadding)");

                // Because the HashAlgorithmName and RSASignaturePadding types aren't guaranteed available at
                // assembly time (though they really need to be if the runtime makes it here...) the delegate binding
                // is a bit harder than normal.
                Type delegateType = typeof(Func<,,,,,>).MakeGenericType(
                    typeof(RSA),
                    typeof(byte[]),
                    typeof(byte[]),
                    s_hashAlgorithmNameType,
                    s_rsaSignaturePaddingType,
                    typeof(bool));

                Delegate openDelegate = Delegate.CreateDelegate(delegateType, verifyDataMethod);

                s_rsaPkcs1VerifyMethod =
                    (delegateRsa, delegateData, delegateSignature, delegateAlgorithm) =>
                    {
                        object hashAlgorithmNameObject = Activator.CreateInstance(s_hashAlgorithmNameType, delegateAlgorithm);

                        object[] args =
                        {
                            delegateRsa,
                            delegateData,
                            delegateSignature,
                            hashAlgorithmNameObject,
                            s_pkcs1SignaturePadding
                        };

                        return (bool)openDelegate.DynamicInvoke(args);
                    };
            }

            Debug.Assert(s_rsaPkcs1VerifyMethod != null);
            return s_rsaPkcs1VerifyMethod(rsa, data, signature, hashAlgorithmName);
        }

        internal static byte[] Pkcs1Encrypt(RSA rsa, byte[] data)
        {
            // Because RSACryptoServiceProvider existed in 4.5, but RSACng didn't, and RSA's Encrypt
            // method requires types that aren't in 4.5, try RSACryptoServiceProvider's way first.
            if (rsa is RSACryptoServiceProvider rsaCsp)
            {
                return rsaCsp.Encrypt(data, false);
            }

            if (s_rsaPkcs1EncryptMethod == null)
            {
                Debug.Assert(s_pkcs1EncryptionPadding != null);

                Delegate openDelegate = BindRsaCryptMethod("Encrypt");

                s_rsaPkcs1EncryptMethod =
                    (delegateRsa, delegateData) => (byte[])openDelegate.DynamicInvoke(delegateRsa, delegateData, s_pkcs1EncryptionPadding);
            }

            Debug.Assert(s_rsaPkcs1EncryptMethod != null);
            return s_rsaPkcs1EncryptMethod(rsa, data);
        }

        internal static byte[] Pkcs1Decrypt(RSA rsa, byte[] data)
        {
            // Because RSACryptoServiceProvider existed in 4.5, but RSACng didn't, and RSA's Decrypt
            // method requires types that aren't in 4.5, try RSACryptoServiceProvider's way first.
            if (rsa is RSACryptoServiceProvider rsaCsp)
            {
                return rsaCsp.Decrypt(data, false);
            }

            if (s_rsaPkcs1DecryptMethod == null)
            {
                Debug.Assert(s_pkcs1EncryptionPadding != null);

                Delegate openDelegate = BindRsaCryptMethod("Decrypt");

                s_rsaPkcs1DecryptMethod =
                    (delegateRsa, delegateData) => (byte[])openDelegate.DynamicInvoke(delegateRsa, delegateData, s_pkcs1EncryptionPadding);
            }

            Debug.Assert(s_rsaPkcs1DecryptMethod != null);
            return s_rsaPkcs1DecryptMethod(rsa, data);
        }

        internal static byte[] OaepSha1Encrypt(RSA rsa, byte[] data)
        {
            // Because RSACryptoServiceProvider existed in 4.5, but RSACng didn't, and RSA's Encrypt
            // method requires types that aren't in 4.5, try RSACryptoServiceProvider's way first.

            if (rsa is RSACryptoServiceProvider rsaCsp)
            {
                return rsaCsp.Encrypt(data, true);
            }

            if (s_rsaOaepSha1EncryptMethod == null)
            {
                Debug.Assert(s_oaepSha1EncryptionPadding != null);

                Delegate openDelegate = BindRsaCryptMethod("Encrypt");

                s_rsaOaepSha1EncryptMethod =
                    (delegateRsa, delegateData) => (byte[])openDelegate.DynamicInvoke(delegateRsa, delegateData, s_oaepSha1EncryptionPadding);
            }

            Debug.Assert(s_rsaOaepSha1EncryptMethod != null);
            return s_rsaOaepSha1EncryptMethod(rsa, data);
        }

        internal static byte[] OaepSha1Decrypt(RSA rsa, byte[] data)
        {
            // Because RSACryptoServiceProvider existed in 4.5, but RSACng didn't, and RSA's Decrypt
            // method requires types that aren't in 4.5, try RSACryptoServiceProvider's way first.
            if (rsa is RSACryptoServiceProvider rsaCsp)
            {
                return rsaCsp.Decrypt(data, true);
            }

            if (s_rsaOaepSha1DecryptMethod == null)
            {
                Debug.Assert(s_oaepSha1EncryptionPadding != null);

                Delegate openDelegate = BindRsaCryptMethod("Decrypt");

                s_rsaOaepSha1DecryptMethod =
                    (delegateRsa, delegateData) => (byte[])openDelegate.DynamicInvoke(delegateRsa, delegateData, s_oaepSha1EncryptionPadding);
            }

            Debug.Assert(s_rsaOaepSha1DecryptMethod != null);
            return s_rsaOaepSha1DecryptMethod(rsa, data);
        }

        private static Delegate BindRsaCryptMethod(string methodName)
        {
            Debug.Assert(s_rsaEncryptionPaddingType != null);
            Type[] signatureTypes = { typeof(byte[]), s_rsaEncryptionPaddingType };

            MethodInfo cryptMethod = typeof(RSA).GetMethod(
                methodName,
                BindingFlags.Public | BindingFlags.Instance,
                null,
                signatureTypes,
                null);

            Debug.Assert(cryptMethod != null, "Cannot find RSA." + methodName + "(byte[], RSAEncryptionPadding)");

            // Because the RSAEncryptionPadding type isn't guaranteed available at assembly time
            // (though they really need to be if the runtime makes it here...) the delegate binding
            // is a bit harder than normal.
            Type delegateType = typeof(Func<,,,>).MakeGenericType(
                typeof(RSA),
                typeof(byte[]),
                s_rsaEncryptionPaddingType,
                typeof(byte[]));

            return Delegate.CreateDelegate(delegateType, cryptMethod);
        }

        private static bool DetectRsaCngSupport()
        {
            Type rsaCng = GetSystemCoreType(RSACngTypeName, throwOnError: false);

            // If the type doesn't exist, there can't be good support for it.
            // (System.Core < 4.6)
            if (rsaCng == null)
            {
                return false;
            }

            Type dsaCng = GetSystemCoreType(DSACngTypeName, throwOnError: false);

            // The original implementation of RSACng returned shared objects in the CAPI fallback
            // pathway. That behavior is hard to test for, since CNG can load all CAPI software keys.
            // But, since DSACng was added in 4.6.2, and RSACng better guarantees uniqueness in 4.6.2
            // use that coincidence as a compatibility test.
            //
            // If DSACng is missing, RSACng usage might lead to attempting to use Disposed objects
            // (System.Core < 4.6.2)
            if (dsaCng == null)
            {
                return false;
            }

            // RSAPKCS1KeyExchangeFormatter, and other BCL types, were better compatible with RSACng
            // in .NET 4.6.2 and beyond.
            //
            // DSACng has a 4.6.2 patch-family dependency on mscorlib 4.6.2, so the existence of
            // DSACng should mean that we can expect the BCL to use the new (4.6) RSA base class
            // overloads, instead of just casting as RSACryptoServiceProvider.
            //
            // But, do one last check: DSA.SignData(byte[], HashAlgorithmName) was added to mscorlib in
            // .NET 4.6.2.  If that's present, RSACng should have sufficient support.
            //
            // A live functionality test would be best, but instantiating an RSACng to generate a new
            // key may fail in no-profile execution contexts; and custom extending RSA in the lightup
            // path would cause the lightup path to fail to load if a library with this change got
            // patched next to mscorlib 4.5.x.
            Type[] signatureTypes = { typeof(byte[]), s_hashAlgorithmNameType };
            MethodInfo signDataMethod = typeof(DSA).GetMethod(
                "SignData",
                BindingFlags.Public | BindingFlags.Instance,
                null,
                signatureTypes,
                null);

            if (signDataMethod == null)
            {
                return false;
            }

            return true;
        }

        private static Func<X509Certificate2, T> BindGetCapiPublicKey<T, TCryptoServiceProvider>(string algorithmOid)
            where T : AsymmetricAlgorithm
            where TCryptoServiceProvider : T, ICspAsymmetricAlgorithm, new()
        {
            return cert =>
            {
                PublicKey publicKeyInfo = cert.PublicKey;

                if (publicKeyInfo.Oid.Value != algorithmOid)
                {
                    return null;
                }

                AsymmetricAlgorithm publicKey = publicKeyInfo.Key;
                Debug.Assert(publicKey != null);
                Debug.Assert(publicKey is T);
                Debug.Assert(publicKey is ICspAsymmetricAlgorithm);

                ICspAsymmetricAlgorithm sharedCspKey = (ICspAsymmetricAlgorithm)publicKey;
                byte[] publicKeyBlob = sharedCspKey.ExportCspBlob(false);

                TCryptoServiceProvider uniqueCspKey = new TCryptoServiceProvider();
                uniqueCspKey.ImportCspBlob(publicKeyBlob);

                return uniqueCspKey;
            };
        }

        private static Func<X509Certificate2, T> BindGetCapiPrivateKey<T>(
            string algorithmOid,
            Func<CspParameters, T> instanceFactory)
            where T : AsymmetricAlgorithm
        {
            return cert =>
            {
                if (!cert.HasPrivateKey)
                {
                    return null;
                }

                PublicKey publicKeyInfo = cert.PublicKey;

                if (publicKeyInfo.Oid.Value != algorithmOid)
                {
                    return null;
                }

                AsymmetricAlgorithm privateKey = cert.PrivateKey;
                Debug.Assert(privateKey != null);
                Debug.Assert(privateKey is T);
                Debug.Assert(privateKey is ICspAsymmetricAlgorithm);

                ICspAsymmetricAlgorithm cspKey = (ICspAsymmetricAlgorithm)privateKey;
                CspParameters cspParameters = CopyCspParameters(cspKey);
                return instanceFactory(cspParameters);
            };
        }

        private static Func<X509Certificate2, T> BindCoreDelegate<T>(string algorithmName, bool isPublic)
        {
            Debug.Assert(typeof(T).Name == algorithmName);

            // Load System.Core.dll and load the appropriate extension class 
            // (one of
            //    System.Security.Cryptography.X509Certificates.RSACertificateExtensions
            //    System.Security.Cryptography.X509Certificates.DSACertificateExtensions
            //    System.Security.Cryptography.X509Certificates.ECDsaCertificateExtensions
            // )
            string typeName = "System.Security.Cryptography.X509Certificates." + algorithmName + "CertificateExtensions";

            Type type = GetSystemCoreType(typeName, throwOnError: false);

            // If the type exists, it will have the GetPublic/GetPrivate methods available.
            // But it can end up not existing in scenarios where this assembly has been patched onto
            // a machine which doesn't have the equivalent baseline.

            if (type == null)
            {
                return null;
            }

            // Now, find the api we want to call:
            //   
            // (one of
            //     GetRSAPublicKey(this X509Certificate2 c)
            //     GetRSAPrivateKey(this X509Certificate2 c)
            //     GetDSAPublicKey(this X509Certificate2 c)
            //     GetDSAPrivateKey(this X509Certificate2 c)
            //     GetECDsaPublicKey(this X509Certificate2 c)
            //     GetECDsaPrivateKey(this X509Certificate2 c)
            // )
            string methodName = "Get" + algorithmName + (isPublic ? "Public" : "Private") + "Key";

            MethodInfo api = type.GetMethod(
                methodName,
                BindingFlags.Public | BindingFlags.Static,
                null,
                new[] { typeof(X509Certificate2) },
                null);

            Debug.Assert(api != null, "Method '" + methodName + "(X509Certificate2 c)' not found on type '" + type + "'");
            return (Func<X509Certificate2, T>)api.CreateDelegate(typeof(Func<X509Certificate2, T>));
        }

        private static CspParameters CopyCspParameters(ICspAsymmetricAlgorithm cspAlgorithm)
        {
            CspKeyContainerInfo cspInfo = cspAlgorithm.CspKeyContainerInfo;

            CspParameters cspParameters = new CspParameters(cspInfo.ProviderType, cspInfo.ProviderName, cspInfo.KeyContainerName)
            {
                Flags = CspProviderFlags.UseExistingKey,
                KeyNumber = (int)cspInfo.KeyNumber,
            };

            if (cspInfo.MachineKeyStore)
            {
                cspParameters.Flags |= CspProviderFlags.UseMachineKeyStore;
            }

            return cspParameters;
        }

        private static Type GetSystemCoreType(string namespaceQualifiedTypeName, bool throwOnError=true)
        {
#if CNG_LIGHTUP_NO_SYSTEM_CORE
            string assemblyQualifiedTypeName = namespaceQualifiedTypeName + ", " + AssemblyRef.SystemCore;
            return Type.GetType(assemblyQualifiedTypeName, throwOnError: false, ignoreCase: false);
#else
            Assembly systemCore = typeof(CngKey).Assembly;
            Debug.Assert(systemCore.GetName().Name == "System.Core");
            return systemCore.GetType(namespaceQualifiedTypeName, throwOnError);
#endif
        }
    }
}

#pragma warning restore 436


<|start_filename|>src/Build/Evaluation/MetadataReference.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Microsoft.Build.Evaluation
{
    /// <summary>
    /// This struct represents a reference to a piece of item metadata.  For example,
    /// %(EmbeddedResource.Culture) or %(Culture) in the project file.  In this case,
    /// "EmbeddedResource" is the item name, and "Culture" is the metadata name.
    /// The item name is optional.
    /// </summary>
    internal struct MetadataReference
    {
        /// <summary>
        /// The item name
        /// </summary>
        internal string ItemName;       // Could be null if the %(...) is not qualified with an item name.

        /// <summary>
        /// The metadata name
        /// </summary>
        internal string MetadataName;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="itemName">Name of the item</param>
        /// <param name="metadataName">Name of the metadata</param>
        internal MetadataReference
        (
            string itemName,
            string metadataName
        )
        {
            this.ItemName = itemName;
            this.MetadataName = metadataName;
        }
    }
}


<|start_filename|>src/Tasks.UnitTests/XmlPeek_Tests.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Build.Tasks;
using Microsoft.Build.Utilities;
using System;
using System.IO;
using Xunit;

namespace Microsoft.Build.UnitTests
{
    sealed public class XmlPeek_Tests
    {
        private string _xmlFileWithNs = @"<?xml version='1.0' encoding='utf-8'?>

<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">
<class AccessModifier='public' Name='test' xmlns:s='http://nsurl'>
  <s:variable Type='String' Name='a'></s:variable>
  <s:variable Type='String' Name='b'></s:variable>
  <s:variable Type='String' Name='c'></s:variable>
  <method AccessModifier='public static' Name='GetVal' />
</class>
";

        private string _xmlFileWithNsWithText = @"<?xml version='1.0' encoding='utf-8'?>

<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">
<class AccessModifier='public' Name='test' xmlns:s='http://nsurl'>
  <s:variable Type='String' Name='a'>This</s:variable>
  <s:variable Type='String' Name='b'>is</s:variable>
  <s:variable Type='String' Name='c'>Sparta!</s:variable>
  <method AccessModifier='public static' Name='GetVal' />
</class>
";

        private string _xmlFileNoNsNoDtd = @"<?xml version='1.0' encoding='utf-8'?>
        
<class AccessModifier='public' Name='test'>
  <variable Type='String' Name='a'></variable>
  <variable Type='String' Name='b'></variable>
  <variable Type='String' Name='c'></variable>
  <method AccessModifier='public static' Name='GetVal' />
</class>
";

        [Fact]
        public void PeekWithNamespaceAttribute()
        {
            MockEngine engine = new MockEngine(true);
            string xmlInputPath;
            Prepare(_xmlFileWithNs, out xmlInputPath);

            XmlPeek p = new XmlPeek();
            p.BuildEngine = engine;

            p.XmlInputPath = new TaskItem(xmlInputPath);
            p.Query = "//s:variable/@Name";
            p.Namespaces = "<Namespace Prefix=\"s\" Uri=\"http://nsurl\" />";

            Assert.True(p.Execute()); // "Test should've passed"
            Assert.Equal(3, p.Result.Length); // "result Length should be 3"
            string[] results = new string[] { "a", "b", "c" };
            for (int i = 0; i < p.Result.Length; i++)
            {
                Assert.Equal(p.Result[i].ItemSpec, results[i]);
            }
        }

        [Fact]
        public void PeekWithNamespaceNode()
        {
            MockEngine engine = new MockEngine(true);
            string xmlInputPath;
            Prepare(_xmlFileWithNs, out xmlInputPath);

            XmlPeek p = new XmlPeek();
            p.BuildEngine = engine;

            p.XmlInputPath = new TaskItem(xmlInputPath);
            p.Query = "//s:variable/.";
            p.Namespaces = "<Namespace Prefix=\"s\" Uri=\"http://nsurl\" />";

            Assert.True(p.Execute()); // "Test should've passed"
            Assert.Equal(3, p.Result.Length); // "result Length should be 3"

            string[] results = new string[] {
                "<s:variable Type=\"String\" Name=\"a\" xmlns:s=\"http://nsurl\"></s:variable>",
                "<s:variable Type=\"String\" Name=\"b\" xmlns:s=\"http://nsurl\"></s:variable>",
                "<s:variable Type=\"String\" Name=\"c\" xmlns:s=\"http://nsurl\"></s:variable>"
            };

            for (int i = 0; i < p.Result.Length; i++)
            {
                Assert.Equal(p.Result[i].ItemSpec, results[i]);
            }
        }

        [Fact]
        public void PeekWithNamespaceText()
        {
            MockEngine engine = new MockEngine(true);
            string xmlInputPath;
            Prepare(_xmlFileWithNsWithText, out xmlInputPath);

            XmlPeek p = new XmlPeek();
            p.BuildEngine = engine;

            p.XmlInputPath = new TaskItem(xmlInputPath);
            p.Query = "//s:variable/text()";
            p.Namespaces = "<Namespace Prefix=\"s\" Uri=\"http://nsurl\" />";
            Assert.Equal("<Namespace Prefix=\"s\" Uri=\"http://nsurl\" />", p.Namespaces);
            Assert.True(p.Execute()); // "Test should've passed"
            Assert.Equal(3, p.Result.Length); // "result Length should be 3"

            string[] results = new string[] {
                "This",
                "is",
                "Sparta!"
            };

            for (int i = 0; i < p.Result.Length; i++)
            {
                Assert.Equal(p.Result[i].ItemSpec, results[i]);
            }
        }

        [Fact]
        public void PeekNoNamespace()
        {
            MockEngine engine = new MockEngine(true);
            string xmlInputPath;
            Prepare(_xmlFileNoNsNoDtd, out xmlInputPath);

            XmlPeek p = new XmlPeek();
            p.BuildEngine = engine;

            p.XmlInputPath = new TaskItem(xmlInputPath);
            p.Query = "//variable/@Name";

            Assert.True(p.Execute()); // "Test should've passed"
            Assert.Equal(3, p.Result.Length); // "result Length should be 3"
            string[] results = new string[] { "a", "b", "c" };
            for (int i = 0; i < p.Result.Length; i++)
            {
                Assert.Equal(p.Result[i].ItemSpec, results[i]);
            }
        }

        [Fact]
        public void PeekNoNSXmlContent()
        {
            MockEngine engine = new MockEngine(true);

            XmlPeek p = new XmlPeek();
            p.BuildEngine = engine;

            p.XmlContent = _xmlFileNoNsNoDtd;
            p.Query = "//variable/@Name";

            Assert.True(p.Execute()); // "Test should've passed"
            Assert.Equal(3, p.Result.Length); // "result Length should be 3"
            string[] results = new string[] { "a", "b", "c" };
            for (int i = 0; i < p.Result.Length; i++)
            {
                Assert.Equal(p.Result[i].ItemSpec, results[i]);
            }
        }

        [Fact]
        public void PeekNoNSXmlContentAndXmlInputError1()
        {
            MockEngine engine = new MockEngine(true);

            string xmlInputPath;
            Prepare(_xmlFileNoNsNoDtd, out xmlInputPath);

            XmlPeek p = new XmlPeek();
            p.BuildEngine = engine;

            p.XmlInputPath = new TaskItem(xmlInputPath);
            p.XmlContent = _xmlFileNoNsNoDtd;
            Assert.Equal(xmlInputPath, p.XmlInputPath.ItemSpec);
            Assert.Equal(_xmlFileNoNsNoDtd, p.XmlContent);

            p.Query = "//variable/@Name";
            Assert.Equal("//variable/@Name", p.Query);

            Assert.False(p.Execute()); // "Test should've failed"
            Assert.Contains("MSB3741", engine.Log); // "Error message MSB3741 should fire"
        }

        [Fact]
        public void PeekNoNSXmlContentAndXmlInputError2()
        {
            MockEngine engine = new MockEngine(true);

            string xmlInputPath;
            Prepare(_xmlFileNoNsNoDtd, out xmlInputPath);

            XmlPeek p = new XmlPeek();
            p.BuildEngine = engine;

            p.Query = "//variable/@Name";

            Assert.False(p.Execute()); // "Test should've failed"
            Assert.Contains("MSB3741", engine.Log); // "Error message MSB3741 should fire"
        }

        [Fact]
        public void PeekNoNSWPrefixedQueryError()
        {
            MockEngine engine = new MockEngine(true);
            string xmlInputPath;
            Prepare(_xmlFileNoNsNoDtd, out xmlInputPath);

            XmlPeek p = new XmlPeek();
            p.BuildEngine = engine;

            p.XmlInputPath = new TaskItem(xmlInputPath);
            p.Query = "//s:variable/@Name";

            Assert.False(p.Execute()); // "Test should've failed"
            Assert.Contains("MSB3743", engine.Log); // "Engine log should contain error code MSB3743"
        }

        [Fact]
        public void PeekDtdWhenDtdProhibitedError()
        {
            MockEngine engine = new MockEngine(true);
            string xmlInputPath;
            Prepare(_xmlFileWithNs, out xmlInputPath);

            XmlPeek p = new XmlPeek();
            p.BuildEngine = engine;

            p.ProhibitDtd = true;
            p.XmlInputPath = new TaskItem(xmlInputPath);
            p.Query = "//s:variable/@Name";

            Assert.False(p.Execute()); // "Test should've failed"
            Assert.Contains("MSB3733", engine.Log); // "Engine log should contain error code MSB3733"
        }

        [Fact]
        public void ErrorInNamespaceDecl()
        {
            MockEngine engine = new MockEngine(true);
            string xmlInputPath;
            Prepare(_xmlFileWithNs, out xmlInputPath);

            XmlPeek p = new XmlPeek();
            p.BuildEngine = engine;
            p.XmlInputPath = new TaskItem(xmlInputPath);
            p.Query = "//s:variable/@Name";
            p.Namespaces = "<!THIS IS ERROR Namespace Prefix=\"s\" Uri=\"http://nsurl\" />";

            bool executeResult = p.Execute();
            Assert.True(engine.Log.Contains("MSB3742"), "Engine Log: " + engine.Log);
            Assert.False(executeResult); // "Execution should've failed"
        }

        [Fact]
        public void MissingNamespaceParameters()
        {
            MockEngine engine = new MockEngine(true);
            string xmlInputPath;
            Prepare(_xmlFileWithNs, out xmlInputPath);

            string[] attrs = new string[] { "Prefix=\"s\"", "Uri=\"http://nsurl\"" };
            for (int i = 0; i < Math.Pow(2, attrs.Length); i++)
            {
                string res = "";
                for (int k = 0; k < attrs.Length; k++)
                {
                    if ((i & (int)Math.Pow(2, k)) != 0)
                    {
                        res += attrs[k] + " ";
                    }
                }
                XmlPeek p = new XmlPeek();
                p.BuildEngine = engine;
                p.XmlInputPath = new TaskItem(xmlInputPath);
                p.Query = "//s:variable/@Name";
                p.Namespaces = "<Namespace " + res + " />";

                bool result = p.Execute();
                Console.WriteLine(engine.Log);

                if (i == 3)
                {
                    Assert.True(result); // "Only 3rd value should pass."
                }
                else
                {
                    Assert.False(result); // "Only 3rd value should pass."
                }
            }
        }

        [Fact]
        public void PeekWithoutUsingTask()
        {
            string projectContents = @"
<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
  <Target Name='x'>
    <XmlPeek Query='abc' ContinueOnError='true' />
  </Target>
</Project>";

            // The task won't complete properly, but ContinueOnError converts the errors to warnings, so the build should succeed
            MockLogger logger = ObjectModelHelpers.BuildProjectExpectSuccess(projectContents);

            // Verify that the task was indeed found.
            logger.AssertLogDoesntContain("MSB4036");
        }

        private void Prepare(string xmlFile, out string xmlInputPath)
        {
            string dir = Path.Combine(Path.GetTempPath(), DateTime.Now.Ticks.ToString());
            Directory.CreateDirectory(dir);
            xmlInputPath = dir + Path.DirectorySeparatorChar + "doc.xml";
            File.WriteAllText(xmlInputPath, xmlFile);
        }
    }
}


<|start_filename|>src/Build/FileSystem/MSBuildFileSystemAdapter.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Build.Shared.FileSystem;

namespace Microsoft.Build.FileSystem
{
     internal class MSBuildFileSystemAdapter : IFileSystem
    {
        private readonly MSBuildFileSystemBase _msbuildFileSystem;
        public MSBuildFileSystemAdapter(MSBuildFileSystemBase msbuildFileSystem)
        {
            _msbuildFileSystem = msbuildFileSystem;
        }
        public TextReader ReadFile(string path) => _msbuildFileSystem.ReadFile(path);

        public Stream GetFileStream(string path, FileMode mode, FileAccess access, FileShare share) => _msbuildFileSystem.GetFileStream(path, mode, access, share);

        public string ReadFileAllText(string path) => _msbuildFileSystem.ReadFileAllText(path);

        public byte[] ReadFileAllBytes(string path) => _msbuildFileSystem.ReadFileAllBytes(path);

        public IEnumerable<string> EnumerateFiles(string path, string searchPattern = "*", SearchOption searchOption = SearchOption.TopDirectoryOnly)
        {
            return _msbuildFileSystem.EnumerateFiles(path, searchPattern, searchOption);
        }

        public IEnumerable<string> EnumerateDirectories(string path, string searchPattern = "*", SearchOption searchOption = SearchOption.TopDirectoryOnly)
        {
            return _msbuildFileSystem.EnumerateDirectories(path, searchPattern, searchOption);
        }

        public IEnumerable<string> EnumerateFileSystemEntries(
            string path,
            string searchPattern = "*",
            SearchOption searchOption = SearchOption.TopDirectoryOnly)
        {
            return _msbuildFileSystem.EnumerateFileSystemEntries(path, searchPattern, searchOption);
        }

        public FileAttributes GetAttributes(string path) => _msbuildFileSystem.GetAttributes(path);

        public DateTime GetLastWriteTimeUtc(string path) => _msbuildFileSystem.GetLastWriteTimeUtc(path);

        public bool DirectoryExists(string path) => _msbuildFileSystem.DirectoryExists(path);

        public bool FileExists(string path) => _msbuildFileSystem.FileExists(path);

        public bool DirectoryEntryExists(string path) => _msbuildFileSystem.FileOrDirectoryExists(path);
    }
}


<|start_filename|>src/Tasks.UnitTests/ResolveSDKReference_Tests.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using Microsoft.Build.Tasks;
using Microsoft.Build.Utilities;



using SDKReference = Microsoft.Build.Tasks.ResolveSDKReference.SDKReference;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Execution;
using Xunit;

namespace Microsoft.Build.UnitTests.ResolveSDKReference_Tests
{
    public class ResolveSDKReferenceTestFixture
    {
        private Microsoft.Build.UnitTests.MockEngine.GetStringDelegate _resourceDelegate = new Microsoft.Build.UnitTests.MockEngine.GetStringDelegate(AssemblyResources.GetString);

        private readonly string _sdkPath = NativeMethodsShared.IsWindows
                                     ? @"c:\SDKDirectory\GoodTestSDK\2.0\"
                                     : @"/SDKDirectory/GoodTestSDK/2.0/";

        #region TestMethods

        /// <summary>
        /// Make sure that SDK reference which should be good are parsed correctly.
        /// </summary>
        [Fact]
        public void ParseItemSpecGood()
        {
            TestGoodSDKReferenceIncludes(new TaskItem("Cat, Version=8.0"), "Cat", "8.0");
            TestGoodSDKReferenceIncludes(new TaskItem("Cat, Version=   8.0"), "Cat", "8.0");
            TestGoodSDKReferenceIncludes(new TaskItem("Cat, Version=8.0   "), "Cat", "8.0");
            TestGoodSDKReferenceIncludes(new TaskItem("Cat, Version=8.0.255"), "Cat", "8.0.255");
            TestGoodSDKReferenceIncludes(new TaskItem("   Cat, Version=8.0.255"), "Cat", "8.0.255");
            TestGoodSDKReferenceIncludes(new TaskItem("Cat   , Version=8.0.255"), "Cat", "8.0.255");
            TestGoodSDKReferenceIncludes(new TaskItem("Cat,Version=8.0.255"), "Cat", "8.0.255");
            TestGoodSDKReferenceIncludes(new TaskItem("Cat, Version=8.0.255"), "Cat", "8.0.255");
        }

        /// <summary>
        /// Make sure ones which are incorrect and log the correct error.
        /// </summary>
        [Fact]
        public void ParseItemSpecBadNames()
        {
            //These should all be bad the format must be   <SDKName>, Version=<SDKVersion>.
            TestBadSDKReferenceIncludes(new TaskItem(""));
            TestBadSDKReferenceIncludes(new TaskItem("Cat, Version=8"));
            TestBadSDKReferenceIncludes(new TaskItem("Cat 8.0"));
            TestBadSDKReferenceIncludes(new TaskItem("Cat Version=8.0"));
            TestBadSDKReferenceIncludes(new TaskItem("Dog, Cat, Version=8.0"));
            TestBadSDKReferenceIncludes(new TaskItem("Cat, Version=8.0, Moose"));
            TestBadSDKReferenceIncludes(new TaskItem("Cat Version=v8.0"));
            TestBadSDKReferenceIncludes(new TaskItem(" , Version=8.0"));
            TestBadSDKReferenceIncludes(new TaskItem("Cat, Version=v8.0"));
            TestBadSDKReferenceIncludes(new TaskItem("Cat, Version=8.0.344.555.666.777.666.555.444"));
            TestBadSDKReferenceIncludes(new TaskItem("Cat,"));
            TestBadSDKReferenceIncludes(new TaskItem("Cat, Version="));
        }

        /// <summary>
        /// Make sure ones which are incorrect and log the correct error.
        /// </summary>
        [Fact]
        public void ParseDependsOnString()
        {
            Assert.Empty(ResolveSDKReference.ParseDependsOnSDK(null));
            Assert.Empty(ResolveSDKReference.ParseDependsOnSDK(String.Empty));
            Assert.Empty(ResolveSDKReference.ParseDependsOnSDK(";;"));
            Assert.Empty(ResolveSDKReference.ParseDependsOnSDK("; ;"));

            List<string> parsedDependencies = ResolveSDKReference.ParseDependsOnSDK("; foo ;");
            Assert.Single(parsedDependencies);
            Assert.Equal("foo", parsedDependencies[0]);

            parsedDependencies = ResolveSDKReference.ParseDependsOnSDK(";;;bar, Version=1.0 ; ; ; foo, Version=2.0   ;;;;;;");
            Assert.Equal(2, parsedDependencies.Count);
            Assert.Equal("bar, Version=1.0", parsedDependencies[0]);
            Assert.Equal("foo, Version=2.0", parsedDependencies[1]);
        }

        /// <summary>
        /// Make sure ones which are incorrect and log the correct error.
        /// </summary>
        [Fact]
        public void GetUnResolvedDependentSDKs()
        {
            HashSet<SDKReference> resolvedSDKsEmpty = new HashSet<SDKReference>();
            List<string> dependentSDKsEmpty = new List<string>();

            HashSet<SDKReference> resolvedSDKs = new HashSet<SDKReference>() { new SDKReference(new TaskItem(), "bar", "1.0"), new SDKReference(new TaskItem(), "foo", "1.0"), new SDKReference(new TaskItem(), "Newt", "1.0") };
            List<string> dependentSDKs = new List<string>() { "bar, Version=1.0", "bar, Version=2.0", "baz, Version=2.0", "CannotParseMeAsSDK", "newt, version=1.0" };

            string[] result = ResolveSDKReference.GetUnresolvedDependentSDKs(resolvedSDKsEmpty, dependentSDKsEmpty);
            Assert.Empty(result);

            result = ResolveSDKReference.GetUnresolvedDependentSDKs(new HashSet<SDKReference>(), dependentSDKs);
            Assert.Equal(4, result.Length);
            Assert.Equal("\"bar, Version=1.0\"", result[0]);
            Assert.Equal("\"bar, Version=2.0\"", result[1]);
            Assert.Equal("\"baz, Version=2.0\"", result[2]);
            Assert.Equal("\"newt, Version=1.0\"", result[3], true);

            result = ResolveSDKReference.GetUnresolvedDependentSDKs(resolvedSDKs, dependentSDKsEmpty);
            Assert.Empty(result);

            result = ResolveSDKReference.GetUnresolvedDependentSDKs(resolvedSDKs, dependentSDKs);
            Assert.Equal(2, result.Length);
            Assert.Equal("\"bar, Version=2.0\"", result[0]);
            Assert.Equal("\"baz, Version=2.0\"", result[1]);
        }

        [Fact]
        public void VerifyBuildWarningForESDKWithoutMaxPlatformVersionOnBlueOrAbove()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "TestMaxPlatformVersionWithTargetFrameworkVersion");
            string testDirectory = Path.Combine(new[] { testDirectoryRoot, "MyPlatform", "8.0", "ExtensionSDKs", "SDkWithManifest", "2.0" }) + Path.DirectorySeparatorChar;

            // manifest does not contain MaxPlatformVersion
            string sdkManifestContents1 =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK'
                FrameworkIdentity = ''
                PlatformIdentity = 'windows'
                APPX = ''
                SDKType=''
                CopyRedistToSubDirectory=''
                SupportedArchitectures=''
                ProductFamilyName=''
                SupportsMultipleVersions=''
                ArchitectureForRuntime = ''
                DependsOn = ''
                MinOSVersion = ''
                MaxOSVersionTested = ''
               >
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            // manifest contains MaxPlatformVersion
            string sdkManifestContents2 =
            @"<FileList
                Identity = 'BadTestSDK, Version=1.0'
                DisplayName = 'BadTestSDK'
                FrameworkIdentity = ''
                PlatformIdentity = 'windows'
                APPX = ''
                SDKType=''
                CopyRedistToSubDirectory=''
                SupportedArchitectures=''
                ProductFamilyName=''
                SupportsMultipleVersions=''
                ArchitectureForRuntime = ''
                DependsOn = ''
                MinOSVersion = ''
                MaxOSVersionTested = ''
                MaxPlatformVersion = '8.1'
               >
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";


            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                installLocation.SetMetadata("PlatformVersion", "8.0");

                File.WriteAllText(sdkManifestFile, sdkManifestContents1);

                // Resolve with PlatformVersion 7.0
                MockEngine engine1 = new MockEngine();
                TaskLoggingHelper log1 = new TaskLoggingHelper(engine1, "ResolveSDKReference");
                log1.TaskResources = AssemblyResources.PrimaryResources;

                ResolveSDKReference t1 = new ResolveSDKReference();
                t1.SDKReferences = new ITaskItem[] { item };
                t1.InstalledSDKs = new ITaskItem[] { installLocation };
                t1.WarnOnMissingPlatformVersion = true;
                t1.BuildEngine = engine1;
                t1.TargetPlatformVersion = "7.0";
                t1.ProjectName = "project.proj";
                t1.TargetPlatformIdentifier = "windows";
                bool succeeded1 = t1.Execute();

                Assert.True(succeeded1);
                engine1.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.MaxPlatformVersionNotSpecified", "project.proj", "GoodTestSDK", "2.0", "windows", "8.0", "windows", t1.TargetPlatformVersion);

                // Resolve with PlatformVersion 8.0
                MockEngine engine2 = new MockEngine();
                TaskLoggingHelper log2 = new TaskLoggingHelper(engine2, "ResolveSDKReference");
                log2.TaskResources = AssemblyResources.PrimaryResources;

                ResolveSDKReference t2 = new ResolveSDKReference();
                t2.SDKReferences = new ITaskItem[] { item };
                t2.InstalledSDKs = new ITaskItem[] { installLocation };
                t2.WarnOnMissingPlatformVersion = true;
                t2.BuildEngine = engine2;
                t2.TargetPlatformVersion = "8.0";
                t2.ProjectName = "project.proj";
                t2.TargetPlatformIdentifier = "windows";
                bool succeeded2 = t2.Execute();

                Assert.True(succeeded2);
                engine2.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.MaxPlatformVersionNotSpecified", "project.proj", "GoodTestSDK", "2.0", "windows", "8.0", "windows", t2.TargetPlatformVersion);

                // Resolve with PlatformVersion 8.1
                MockEngine engine3 = new MockEngine();
                TaskLoggingHelper log3 = new TaskLoggingHelper(engine3, "ResolveSDKReference");
                log3.TaskResources = AssemblyResources.PrimaryResources;

                ResolveSDKReference t3 = new ResolveSDKReference();
                t3.SDKReferences = new ITaskItem[] { item };
                t3.InstalledSDKs = new ITaskItem[] { installLocation };
                t3.WarnOnMissingPlatformVersion = true;
                t3.BuildEngine = engine3;
                t3.TargetPlatformVersion = "8.1";
                t3.ProjectName = "project.proj";
                t3.TargetPlatformIdentifier = "windows";
                bool succeeded3 = t3.Execute();

                Assert.True(succeeded3);
                engine3.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.MaxPlatformVersionNotSpecified", "project.proj", "GoodTestSDK", "2.0", "windows", "8.0", "windows", t3.TargetPlatformVersion);

                // Resolve with PlatformVersion 8.1 with WarnOnMissingPlatformVersion = false
                MockEngine engine3a = new MockEngine();
                TaskLoggingHelper log3a = new TaskLoggingHelper(engine3a, "ResolveSDKReference");
                log3a.TaskResources = AssemblyResources.PrimaryResources;

                ResolveSDKReference t3a = new ResolveSDKReference();
                t3a.SDKReferences = new ITaskItem[] { item };
                t3a.InstalledSDKs = new ITaskItem[] { installLocation };
                t3a.WarnOnMissingPlatformVersion = false;
                t3a.BuildEngine = engine3a;
                t3a.TargetPlatformVersion = "8.1";
                t3a.ProjectName = "project.proj";
                t3a.TargetPlatformIdentifier = "windows";
                bool succeeded3a = t3a.Execute();

                Assert.True(succeeded3a);
                engine3a.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.MaxPlatformVersionNotSpecified", "project.proj", "GoodTestSDK", "2.0", "windows", "8.0", "windows", t3a.TargetPlatformVersion);

                FileUtilities.DeleteNoThrow(sdkManifestFile);
                // Manifest with MaxPlatformVersion
                File.WriteAllText(sdkManifestFile, sdkManifestContents2);

                // Resolve with PlatformVersion 8.0
                MockEngine engine4 = new MockEngine();
                TaskLoggingHelper log4 = new TaskLoggingHelper(engine4, "ResolveSDKReference");
                log4.TaskResources = AssemblyResources.PrimaryResources;
                ResolveSDKReference t4 = new ResolveSDKReference();
                t4.SDKReferences = new ITaskItem[] { item };
                t4.InstalledSDKs = new ITaskItem[] { installLocation };
                t4.WarnOnMissingPlatformVersion = true;
                t4.BuildEngine = engine4;
                t4.TargetPlatformVersion = "8.0";
                t4.ProjectName = "project.proj";
                t4.TargetPlatformIdentifier = "windows";
                bool succeeded4 = t4.Execute();

                Assert.True(succeeded4);
                engine4.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.MaxPlatformVersionNotSpecified", "project.proj", "BadTestSDK", "1.0", "windows", "8.0", "windows", t4.TargetPlatformVersion);

                // Resolve with PlatformVersion 8.1
                MockEngine engine5 = new MockEngine();
                TaskLoggingHelper log5 = new TaskLoggingHelper(engine5, "ResolveSDKReference");
                log5.TaskResources = AssemblyResources.PrimaryResources;
                ResolveSDKReference t5 = new ResolveSDKReference();
                t5.SDKReferences = new ITaskItem[] { item };
                t5.InstalledSDKs = new ITaskItem[] { installLocation };
                t5.WarnOnMissingPlatformVersion = true;
                t5.BuildEngine = engine5;
                t5.ProjectName = "project.proj";
                t5.TargetPlatformVersion = "8.1";
                t5.TargetPlatformIdentifier = "windows";
                bool succeeded5 = t5.Execute();

                Assert.True(succeeded5);
                engine5.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.MaxPlatformVersionNotSpecified", "project.proj", "BadTestSDK", "1.0", "windows", "8.0", "windows", t5.TargetPlatformVersion);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }
        /// <summary>
        /// Verify "RuntimeReferenceOnly" equals to "true" is set for specified references
        /// </summary>
        [Fact]
        public void VerifyAddMetadataToReferences()
        {
            MockEngine engine = new MockEngine();
            TaskLoggingHelper log = new TaskLoggingHelper(engine, "ResolveSDKReference");
            log.TaskResources = AssemblyResources.PrimaryResources;

            HashSet<SDKReference> references = new HashSet<SDKReference>();
            SDKReference reference1 = new SDKReference(new TaskItem(), "Microsoft.VCLibs", "12.0");
            reference1.ResolvedItem = new TaskItem();
            references.Add(reference1);

            SDKReference reference2 = new SDKReference(new TaskItem(), "Microsoft.VCLibs", "11.0");
            reference2.ResolvedItem = new TaskItem();
            references.Add(reference2);

            SDKReference reference3 = new SDKReference(new TaskItem(), "Foo", "11.0");
            reference3.ResolvedItem = new TaskItem();
            references.Add(reference3);

            // Dictionary with runtime-only dependencies
            Dictionary<string, string> dict = new Dictionary<string, string>();
            dict.Add("Microsoft.VCLibs", "11.0");

            ResolveSDKReference.AddMetadataToReferences(log, references, dict, "RuntimeReferenceOnly", "true");

            foreach (SDKReference reference in references)
            {
                if (reference.SimpleName.Equals("Microsoft.VCLibs") && reference.Version.Equals("11.0"))
                {
                    Assert.Equal("true", reference.ResolvedItem.GetMetadata("RuntimeReferenceOnly"));
                }
                else
                {
                    Assert.DoesNotContain("RuntimeReferenceOnly", reference.ResolvedItem.MetadataNames.ToString());
                }
            }
        }

        /// <summary>
        /// Make sure ones which are incorrect and log the correct warning.
        /// </summary>
        [Fact]
        public void VerifyUnResolvedSDKMessage()
        {
            MockEngine engine = new MockEngine();
            TaskLoggingHelper log = new TaskLoggingHelper(engine, "ResolveSDKReference");

            HashSet<SDKReference> references = new HashSet<SDKReference>();

            // All of the dependencies resolve correctly no warnings are expected
            SDKReference reference1 = new SDKReference(new TaskItem(), "reference1", "1.0");
            references.Add(reference1);

            SDKReference reference2 = new SDKReference(new TaskItem(), "reference2", "1.0");
            reference2.DependsOnSDK = "reference1, Version=1.0";
            references.Add(reference2);

            SDKReference reference3 = new SDKReference(new TaskItem(), "reference3", "1.0");
            reference3.DependsOnSDK = "reference1, Version=1.0;reference2, Version=1.0";
            references.Add(reference3);

            SDKReference reference4 = new SDKReference(new TaskItem(), "reference4", "1.0");
            reference4.DependsOnSDK = "reference1, Version=1.0";
            references.Add(reference4);

            SDKReference reference5 = new SDKReference(new TaskItem(), "reference5", "1.0");
            reference5.DependsOnSDK = "reference1, Version=1.0";
            references.Add(reference5);

            ResolveSDKReference.VerifySDKDependsOn(log, references); //, new Version(8, 1), "Windows", null);
            Assert.Equal(0, engine.Warnings);
            Assert.Equal(0, engine.Errors);
            Assert.Equal(0, engine.Log.Length);

            engine = new MockEngine();
            log = new TaskLoggingHelper(engine, "ResolveSDKReference");
            log.TaskResources = AssemblyResources.PrimaryResources;

            references = new HashSet<SDKReference>();

            reference1 = new SDKReference(new TaskItem(), "reference1", "1.0");
            reference1.DependsOnSDK = "NotThere, Version=1.0";
            references.Add(reference1);

            reference2 = new SDKReference(new TaskItem(), "reference2", "1.0");
            reference2.DependsOnSDK = "reference11, Version=1.0;reference2, Version=1.0;reference77, Version=1.0";
            references.Add(reference2);

            reference3 = new SDKReference(new TaskItem(), "reference3", "1.0");
            reference3.DependsOnSDK = "reference1, Version=1.0;NotThere, Version=1.0;WhereAmI, Version=1.0";
            references.Add(reference3);

            reference4 = new SDKReference(new TaskItem(), "reference4", "1.0");
            reference4.DependsOnSDK = "NotThere, Version=1.0";
            references.Add(reference4);

            ResolveSDKReference.VerifySDKDependsOn(log, references);//, new Version(8, 1), "Windows", null);
            Assert.Equal(4, engine.Warnings);
            Assert.Equal(0, engine.Errors);

            string warning = ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveSDKReference.SDKMissingDependency", reference1.SDKName, "\"NotThere, Version=1.0\"");
            engine.AssertLogContains(warning);

            warning = ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveSDKReference.SDKMissingDependency", reference2.SDKName, "\"reference11, Version=1.0\", \"reference77, Version=1.0\"");
            engine.AssertLogContains(warning);

            warning = ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveSDKReference.SDKMissingDependency", reference3.SDKName, "\"NotThere, Version=1.0\", \"WhereAmI, Version=1.0\"");
            engine.AssertLogContains(warning);

            warning = ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveSDKReference.SDKMissingDependency", reference4.SDKName, "\"NotThere, Version=1.0\"");
            engine.AssertLogContains(warning);
        }

        /// <summary>
        /// Verify if the DependsOn metadata is set on the reference item and that dependency is not resolved then cause the warning to happen.
        /// </summary>
        [Fact]
        public void VerifyDependencyWarningFromMetadata()
        {
            // Create the engine.
            MockEngine engine = new MockEngine();

            ResolveSDKReference t = new ResolveSDKReference();
            ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
            item.SetMetadata("DependsOn", "NotHere, Version=1.0");
            t.SDKReferences = new ITaskItem[] { item };
            t.References = null;
            ITaskItem installedSDK = new TaskItem(_sdkPath);
            installedSDK.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
            t.InstalledSDKs = new ITaskItem[] { installedSDK };

            t.BuildEngine = engine;
            bool succeeded = t.Execute();

            Assert.True(succeeded);
            Assert.Single(t.ResolvedSDKReferences);

            engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
            Assert.Equal(_sdkPath, t.ResolvedSDKReferences[0].ItemSpec);

            string warning = ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveSDKReference.SDKMissingDependency", "GoodTestSDK, Version=2.0", "\"NotHere, Version=1.0\"");
            engine.AssertLogContains(warning);
        }

        /// <summary>
        /// Verify we get the correct dependson warning
        /// </summary>
        [Fact]
        public void VerifyDependsOnWarningFromManifest()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "VerifyDependsOnWarningFromManifest");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity = 'ShouldNotPickup'
                FrameworkIdentity-retail = 'ShouldNotPickup'
                FrameworkIdentity-retail-Neutral = 'GoodTestSDKIdentity'
                APPX = 'ShouldNotPickup'
                APPX-Retail = 'ShouldNotPickup'
                APPX-Retail-Neutral = 'RetailX86Location'
                SDKType='Debug'
                DependsOn='Foo, Version=1.0;bar, Version=2.0;foooooggg;;;;'
                CopyRedistToSubDirectory='GoodTestSDK\Redist'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);

                string warning = ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveSDKReference.SDKMissingDependency", "GoodTestSDK, Version=2.0", "\"Foo, Version=1.0\", \"bar, Version=2.0\"");
                engine.AssertLogContains(warning);

                engine.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Make sure the equals works on the SDKReference.
        /// </summary>
        [Fact]
        public void TestSDkReferenceEquals()
        {
            ITaskItem dummyItem = new TaskItem();

            SDKReference sdkReference1 = new SDKReference(dummyItem, "Reference1", "8.0");
            SDKReference shouldBeEqualToOne = new SDKReference(dummyItem, "Reference1", "8.0");
            SDKReference sdkReference2 = new SDKReference(dummyItem, "Reference2", "8.0");
            SDKReference sdkReference2DiffVer = new SDKReference(dummyItem, "Reference2", "7.0");

            Assert.Equal(sdkReference1, sdkReference1);
            Assert.Equal(shouldBeEqualToOne, sdkReference1);
            Assert.NotEqual(sdkReference2, sdkReference1);
            Assert.NotEqual(sdkReference2DiffVer, sdkReference1);
            Assert.NotEqual(sdkReference2DiffVer, sdkReference2);
        }

        private static void TestGoodSDKReferenceIncludes(ITaskItem referenceInclude, string simpleName, string version)
        {
            // Create the engine.
            MockEngine engine = new MockEngine();

            ResolveSDKReference t = new ResolveSDKReference();
            t.BuildEngine = engine;

            SDKReference reference = t.ParseSDKReference(referenceInclude);
            Assert.NotNull(reference);
            Assert.Equal(simpleName, reference.SimpleName);
            Assert.Equal(version, reference.Version);
        }

        private static void TestBadSDKReferenceIncludes(ITaskItem referenceInclude)
        {
            // Create the engine.
            MockEngine engine = new MockEngine();

            ResolveSDKReference t = new ResolveSDKReference();
            t.BuildEngine = engine;

            Assert.Null(t.ParseSDKReference(referenceInclude));
            string errorMessage = t.Log.FormatResourceString("ResolveSDKReference.SDKReferenceIncorrectFormat", referenceInclude.ItemSpec);
            engine.AssertLogContains(errorMessage);
        }


        /// <summary>
        /// Project: Prefer32bit true  Manifest:SupportPrefer32Bit:true Target:msil Expect: No error
        /// </summary>
        [Fact]
        public void Prefer32bit1()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "Prefer32bit1");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                 SupportPrefer32Bit='true'>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKConfiguration = "Release";
                t.TargetedSDKArchitecture = "msil";
                t.Prefer32Bit = true;

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);
                Assert.Equal(0, engine.Errors); // "Expected no errors"
                Assert.Equal(0, engine.Warnings); // "Expected no warnings"
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Project: Prefer32bit true  Manifest:SupportPrefer32Bit:false Target:AnyCPU Expect: error
        /// </summary>
        [Fact]
        public void Prefer32bit2()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "Prefer32bit2");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                 SupportPrefer32Bit='false'>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKConfiguration = "Release";
                t.TargetedSDKArchitecture = "Any CPU";
                t.Prefer32Bit = true;

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.False(succeeded);
                Assert.Equal(1, engine.Errors);
                Assert.Equal(0, engine.Warnings); // "Expected no warnings"
                string errorMessage = t.Log.FormatResourceString("ResolveSDKReference.Prefer32BitNotSupportedWithNeutralProject", item.ItemSpec);
                engine.AssertLogContains(errorMessage);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }


        /// <summary>
        /// Project: Prefer32bit true  Manifest:SupportPrefer32Bit:false Target:x86 Expect: No error
        /// </summary>
        [Fact]
        public void Prefer32bit3()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "Prefer32bit3");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                 SupportPrefer32Bit='false'>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKConfiguration = "Release";
                t.TargetedSDKArchitecture = "x86";
                t.Prefer32Bit = true;

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);
                Assert.Equal(0, engine.Errors); // "Expected no errors"
                Assert.Equal(0, engine.Warnings); // "Expected no warnings"
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Project: Prefer32bit false  Manifest:SupportPrefer32Bit:false Target:msil Expect: No error
        /// </summary>
        [Fact]
        public void Prefer32bit4()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "Prefer32bit4");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                 SupportPrefer32Bit='false'>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKConfiguration = "Release";
                t.TargetedSDKArchitecture = "msil";
                t.Prefer32Bit = false;

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);
                Assert.Equal(0, engine.Errors); // "Expected no errors"
                Assert.Equal(0, engine.Warnings); // "Expected no warnings"
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Project: Prefer32bit false  Manifest:SupportPrefer32Bit:false Target:x86 Expect: No error
        /// </summary>
        [Fact]
        public void Prefer32bit5()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "Prefer32bit5");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                 SupportPrefer32Bit='false'>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKConfiguration = "Release";
                t.TargetedSDKArchitecture = "x86";
                t.Prefer32Bit = false;

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);
                Assert.Equal(0, engine.Errors); // "Expected no errors"
                Assert.Equal(0, engine.Warnings); // "Expected no warnings"
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Project: Prefer32bit true  Manifest:SupportPrefer32Bit:FOO Target:msil Expect: error
        /// </summary>
        [Fact]
        public void Prefer32bit6()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "Prefer32bit6");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                 SupportPrefer32Bit='FOO'>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKConfiguration = "Release";
                t.TargetedSDKArchitecture = "msil";
                t.Prefer32Bit = true;

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.False(succeeded);
                Assert.Equal(1, engine.Errors);
                Assert.Equal(0, engine.Warnings); // "Expected no warnings" ;
                string errorMessage = t.Log.FormatResourceString("ResolveSDKReference.Prefer32BitNotSupportedWithNeutralProject", item.ItemSpec);
                engine.AssertLogContains(errorMessage);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Project: Prefer32bit true  Manifest:SupportPrefer32Bit:empty Target:msil Expect: No error
        /// </summary>
        [Fact]
        public void Prefer32bit7()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "Prefer32bit7");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                 SupportPrefer32Bit=''>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKConfiguration = "Release";
                t.TargetedSDKArchitecture = "msil";
                t.Prefer32Bit = true;

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);
                Assert.Equal(0, engine.Warnings); // "Expected no warnings"
                Assert.Equal(0, engine.Errors); // "Expected no errors"
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Project: Prefer32bit true  Manifest:SupportPrefer32Bit:missing Target:msil Expect: No Error
        /// </summary>
        [Fact]
        public void Prefer32bit8()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "Prefer32bit8");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKConfiguration = "Release";
                t.TargetedSDKArchitecture = "msil";
                t.Prefer32Bit = true;

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);
                Assert.Equal(0, engine.Warnings); // "Expected no warnings"
                Assert.Equal(0, engine.Errors); // "Expected no errors"
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Project: Prefer32bit false  Manifest:SupportPrefer32Bit:true Target:msil Expect: No Error
        /// </summary>
        [Fact]
        public void Prefer32bit9()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "Prefer32bit9");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                SupportPrefer32Bit='true'>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKConfiguration = "Release";
                t.TargetedSDKArchitecture = "msil";
                t.Prefer32Bit = true;

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);
                Assert.Equal(0, engine.Warnings); // "Expected no warnings"
                Assert.Equal(0, engine.Errors); // "Expected no errors"
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Resolve from an SDK which exists and is not a framework SDK. This means there is no frameworkIdentity or APPXLocation.
        /// Also since no configuration or architecture were passed in we expect the defaults.
        /// </summary>
        [Fact]
        public void ResolveFromNonFrameworkNoManifest()
        {
            // Create the engine.
            MockEngine engine = new MockEngine();

            ResolveSDKReference t = new ResolveSDKReference();
            ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
            t.SDKReferences = new ITaskItem[] { item };
            t.References = null;
            ITaskItem installedSDK = new TaskItem(_sdkPath);
            installedSDK.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
            t.InstalledSDKs = new ITaskItem[] { installedSDK };

            t.BuildEngine = engine;
            bool succeeded = t.Execute();

            Assert.True(succeeded);
            Assert.Single(t.ResolvedSDKReferences);

            engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
            Assert.Equal(_sdkPath, t.ResolvedSDKReferences[0].ItemSpec);
            Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"));
            Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("PlatformIdentity"));
            Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"));
            Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("CopyRedist"), true);
            Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
            Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);
            Assert.Equal("Retail", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"), true);
            Assert.Equal("Neutral", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"), true);
            Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
        }

        /// <summary>
        /// Resolve from an SDK which exists and is not a framework SDK. This means there is no frameworkIdentity or APPXLocation.
        /// Also since no configuration or architecture were passed in we expect the defaults.
        /// </summary>
        [Fact]
        public void ResolveFromNonFrameworkPassInConfigAndArch()
        {
            // Create the engine.
            MockEngine engine = new MockEngine();

            ResolveSDKReference t = new ResolveSDKReference();
            ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
            t.SDKReferences = new ITaskItem[] { item };
            t.References = null;
            ITaskItem installedSDK = new TaskItem(_sdkPath);
            installedSDK.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
            t.InstalledSDKs = new ITaskItem[] { installedSDK };
            t.TargetedSDKConfiguration = "Release";
            t.TargetedSDKArchitecture = "msil";
            t.BuildEngine = engine;
            bool succeeded = t.Execute();

            Assert.True(succeeded);
            Assert.Single(t.ResolvedSDKReferences);

            engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
            Assert.Equal(_sdkPath, t.ResolvedSDKReferences[0].ItemSpec);
            Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"));
            Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"));
            Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
            Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);

            // Expect retail if release is passed in
            Assert.Equal("Retail", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"), true);
            Assert.Equal("Neutral", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"), true);
            Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
        }

        /// <summary>
        /// Resolve from an SDK which exists and is not a framework SDK. This means there is no frameworkIdentity or APPXLocation.
        /// Also since no configuration or architecture were passed in we expect the defaults.
        /// </summary>
        [Fact]
        public void ResolveFromNonFrameworkPassInConfigAndArchOverrideByMetadata()
        {
            // Create the engine.
            MockEngine engine = new MockEngine();

            ResolveSDKReference t = new ResolveSDKReference();
            ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
            item.SetMetadata("TargetedSDKConfiguration", "Release");
            item.SetMetadata("TargetedSDKArchitecture", "AnyCPU");

            t.SDKReferences = new ITaskItem[] { item };
            t.References = null;
            ITaskItem installedSDK = new TaskItem(_sdkPath);
            installedSDK.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
            t.InstalledSDKs = new ITaskItem[] { installedSDK };
            t.TargetedSDKConfiguration = "Debug";
            t.TargetedSDKConfiguration = "x86";
            t.BuildEngine = engine;
            bool succeeded = t.Execute();

            Assert.True(succeeded);
            Assert.Single(t.ResolvedSDKReferences);

            engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
            Assert.Equal(_sdkPath, t.ResolvedSDKReferences[0].ItemSpec);
            Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"));
            Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"));
            Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
            Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);

            // Expect retail if release is passed in
            Assert.Equal("Retail", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"));
            Assert.Equal("Neutral", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"));
            Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
        }


        /// <summary>
        /// When duplicate references are passed in we only want the first one.
        /// </summary>
        [Fact]
        public void DuplicateSDKReferences()
        {
            // Create the engine.
            MockEngine engine = new MockEngine();

            ResolveSDKReference t = new ResolveSDKReference();
            ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
            ITaskItem item2 = new TaskItem("GoodTestSDK, Version=2.0");
            t.SDKReferences = new ITaskItem[] { item, item2 };
            t.References = new TaskItem[0];
            ITaskItem installedSDK = new TaskItem(_sdkPath);
            installedSDK.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
            t.InstalledSDKs = new ITaskItem[] { installedSDK };

            t.BuildEngine = engine;
            bool succeeded = t.Execute();

            Assert.True(succeeded);
            Assert.Single(t.ResolvedSDKReferences);

            engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
            Assert.Equal(_sdkPath, t.ResolvedSDKReferences[0].ItemSpec);
            Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"));
            Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"));
            Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
            Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);
            Assert.Equal("Retail", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"), true);
            Assert.Equal("Neutral", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"), true);
            Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
        }

        /// <summary>
        /// Verify that if references have SDKName metadata on them that matches a resolved SDK then that SDK should
        /// not have its reference assemblies expanded.
        /// </summary>
        [Fact]
        public void DoNotExpandSDKsWhichAreAlsoTargetedByReferences()
        {
            // Create the engine.
            MockEngine engine = new MockEngine();

            ResolveSDKReference t = new ResolveSDKReference();
            ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
            t.SDKReferences = new ITaskItem[] { item };

            TaskItem referenceItem = new TaskItem("RandomWinMD");
            referenceItem.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
            t.References = new TaskItem[] { referenceItem };

            ITaskItem installedSDK = new TaskItem(_sdkPath);
            installedSDK.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
            t.InstalledSDKs = new ITaskItem[] { installedSDK };

            t.BuildEngine = engine;
            bool succeeded = t.Execute();

            Assert.True(succeeded);
            Assert.Single(t.ResolvedSDKReferences);

            engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
            Assert.Equal(_sdkPath, t.ResolvedSDKReferences[0].ItemSpec);
            Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"));
            Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"));
            Assert.Equal("GoodTestSDK", t.ResolvedSDKReferences[0].GetMetadata("SimpleName"), true);
            Assert.Equal("2.0", t.ResolvedSDKReferences[0].GetMetadata("Version"), true);
            Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
            Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);
            Assert.Equal("Retail", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"), true);
            Assert.Equal("Neutral", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"), true);
            Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);

            // Make sure that if the SDKName does not match the sdk being resolved then it should have no effect.
            // Create the engine.
            engine = new MockEngine();

            t = new ResolveSDKReference();
            item = new TaskItem("GoodTestSDK, Version=2.0");
            t.SDKReferences = new ITaskItem[] { item };

            referenceItem = new TaskItem("RandomWinMD");
            referenceItem.SetMetadata("SDKName", "DifferentSDK, Version=2.0");
            t.References = new TaskItem[] { referenceItem };

            installedSDK = new TaskItem(_sdkPath);
            installedSDK.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
            t.InstalledSDKs = new ITaskItem[] { installedSDK };

            t.BuildEngine = engine;
            succeeded = t.Execute();

            Assert.True(succeeded);
            Assert.Single(t.ResolvedSDKReferences);

            engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
            Assert.Equal(_sdkPath, t.ResolvedSDKReferences[0].ItemSpec);
            Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"));
            Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"));
            Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
            Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);
            Assert.Equal("Retail", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"), true);
            Assert.Equal("Neutral", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"), true);
            Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
        }

        /// <summary>
        /// When InstalledSDK is empty we should log a message and succeed.
        /// </summary>
        [Fact]
        public void InstalledSDKEmpty()
        {
            // Create the engine.
            MockEngine engine = new MockEngine();

            ResolveSDKReference t = new ResolveSDKReference();
            ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
            t.SDKReferences = new ITaskItem[] { item };
            t.References = null;
            t.InstalledSDKs = new ITaskItem[0];

            t.BuildEngine = engine;
            bool succeeded = t.Execute();

            Assert.True(succeeded);
            Assert.Empty(t.ResolvedSDKReferences);

            engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoSDKLocationsSpecified");
        }

        /// <summary>
        /// Lets have a mix of install sdk items, some are good, some are bad (missing item spec) others are bad (missing SDKName)
        /// </summary>
        [Fact]
        public void MixOfInstalledSDKItemsGoodDuplicateAndBad()
        {
            // Create the engine.
            MockEngine engine = new MockEngine();

            ResolveSDKReference t = new ResolveSDKReference();
            ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
            t.SDKReferences = new ITaskItem[] { item };
            t.References = new TaskItem[0];

            ITaskItem installedSDK1 = new TaskItem(_sdkPath);
            installedSDK1.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");

            ITaskItem installedSDK2 = new TaskItem(_sdkPath);
            installedSDK2.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");

            ITaskItem installedSDK3 = new TaskItem(String.Empty);
            installedSDK3.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");

            ITaskItem installedSDK4 = new TaskItem(_sdkPath);
            installedSDK4.SetMetadata("SDKName", String.Empty);

            ITaskItem installedSDK5 = new TaskItem(_sdkPath);

            t.InstalledSDKs = new ITaskItem[] { installedSDK1, installedSDK2, installedSDK3, installedSDK4, installedSDK5 };

            t.BuildEngine = engine;
            bool succeeded = t.Execute();

            Assert.True(succeeded);
            Assert.Single(t.ResolvedSDKReferences);

            engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
            Assert.Equal(_sdkPath, t.ResolvedSDKReferences[0].ItemSpec);
            Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"));
            Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"));
            Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("SDKType"));
            Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("DisplayName"));
            Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
            Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);
            Assert.Equal("Retail", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"), true);
            Assert.Equal("Neutral", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"), true);
            Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
            Assert.Equal("GoodTestSDK, Version=2.0", t.ResolvedSDKReferences[0].GetMetadata("SDKName"), true);
        }

        /// <summary>
        /// Make sure when no sdks are resolved there are no problems and that the names of the sdks which were not resolved are logged.
        /// </summary>
        [Fact]
        public void NOSDKResolved()
        {
            // Create the engine.
            MockEngine engine = new MockEngine();

            ResolveSDKReference t = new ResolveSDKReference();
            ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
            ITaskItem item2 = new TaskItem("GoodTestSDK2, Version=2.0");
            t.SDKReferences = new ITaskItem[] { item, item2 };

            ITaskItem installedSDK = new TaskItem("DoesNotExist");
            installedSDK.SetMetadata("SDKName", "RandomSDK, Version=1.0");
            t.InstalledSDKs = new ITaskItem[] { installedSDK };

            t.BuildEngine = engine;
            bool succeeded = t.Execute();

            Assert.False(succeeded);
            Assert.Empty(t.ResolvedSDKReferences);
            engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.CouldNotResolveSDK", "GoodTestSDK, Version=2.0");
            engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.CouldNotResolveSDK", "GoodTestSDK2, Version=2.0");
        }

        /// <summary>
        /// When there is a mix of resolved and unresolved SDKs make sure that the resolved ones are correctly found
        /// and the unresolved ones are logged.
        /// </summary>
        [Fact]
        public void MixOfResolvedAndUnResolved()
        {
            // Create the engine.
            MockEngine engine = new MockEngine();

            ResolveSDKReference t = new ResolveSDKReference();
            ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
            ITaskItem item2 = new TaskItem("RandomSDK, Version=2.0");
            t.SDKReferences = new ITaskItem[] { item, item2 };

            ITaskItem installedSDK = new TaskItem(_sdkPath);
            installedSDK.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
            t.InstalledSDKs = new ITaskItem[] { installedSDK };

            t.BuildEngine = engine;
            t.LogResolutionErrorsAsWarnings = true;
            bool succeeded = t.Execute();

            Assert.True(succeeded);
            Assert.Single(t.ResolvedSDKReferences);

            engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
            Assert.Equal(_sdkPath, t.ResolvedSDKReferences[0].ItemSpec);
            engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.FoundSDK", _sdkPath);
            engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.CouldNotResolveSDK", "RandomSDK, Version=2.0");
        }

        /// <summary>
        /// When a null is passed into the SDKReferences property make sure we get the correct exception out.
        /// </summary>
        [Fact]
        public void NullSDKReferences()
        {
            Assert.Throws<ArgumentNullException>(() =>
            {
                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                t.SDKReferences = null;
                bool succeeded = t.Execute();
            }
           );
        }
        /// <summary>
        /// When a null is passed into the set of InstalledSDKS property make sure we get the correct exception out.
        /// </summary>
        [Fact]
        public void NullInstalledSDKs()
        {
            Assert.Throws<ArgumentNullException>(() =>
            {
                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                t.InstalledSDKs = null;
                bool succeeded = t.Execute();
            }
           );
        }

        /// <summary>
        /// If no SDKReferences are passed in then we should get nothing out.
        /// </summary>
        [Fact]
        public void EmptySDKReferencesList()
        {
            // Create the engine.
            MockEngine engine = new MockEngine();

            ResolveSDKReference t = new ResolveSDKReference();
            ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
            t.SDKReferences = new ITaskItem[0];
            ITaskItem installedSDK = new TaskItem(_sdkPath);
            installedSDK.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
            t.InstalledSDKs = new ITaskItem[] { installedSDK };

            t.BuildEngine = engine;
            bool succeeded = t.Execute();

            Assert.True(succeeded);
            Assert.Empty(t.ResolvedSDKReferences);
        }

        /// <summary>
        /// When we find the SDKManifest it may be poorly formatted. If that happens we need to log the error
        /// and not resolve the SDK. We also add a good one as well to make sure resolution continues.
        /// </summary>
        [Fact]
        public void SDKFoundButBadlyFormattedSDKManifestWarnings()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "SDKFoundButBadlyFormattedSDKManifestWarnings");
            string testDirectory = Path.Combine(testDirectoryRoot, "BadTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"IAMNOTANXMLFILE";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("BadTestSDK, Version=2.0");
                ITaskItem item2 = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item, item2 };

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "BadTestSDK, Version=2.0");

                string goodSDKLocation = NativeMethodsShared.IsWindows ? "C:\\GoodSDKLocation\\" : "/GoodSDKLocation/";
                ITaskItem installLocation2 = new TaskItem(goodSDKLocation);
                installLocation2.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation, installLocation2 };
                t.BuildEngine = engine;
                t.LogResolutionErrorsAsWarnings = true;
                bool succeeded = t.Execute();

                Assert.True(succeeded);
                engine.AssertLogContains("MSB3775");

                Assert.Equal(2, t.ResolvedSDKReferences.Length);
                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal(goodSDKLocation, t.ResolvedSDKReferences[1].ItemSpec);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// When we find the SDKManifest it may be poorly formatted. If that happens we need to log the error
        /// and not resolve the SDK. We also add a good one as well to make sure resolution continues.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void SDKFoundButBadlyFormattedSDKManifestErrors()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "SDKFoundButBadlyFormattedSDKManifestErrors");
            string testDirectory = Path.Combine(testDirectoryRoot, "BadTestSDK\\2.0\\");
            string sdkManifestContents =
            @"IAMNOTANXMLFILE";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("BadTestSDK, Version=2.0");
                ITaskItem item2 = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item, item2 };

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "BadTestSDK, Version=2.0");

                ITaskItem installLocation2 = new TaskItem("C:\\GoodSDKLocation");
                installLocation2.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation, installLocation2 };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();

                Assert.False(succeeded);
                engine.AssertLogContains("MSB3775");

                Assert.Single(t.ResolvedSDKReferences);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        [Fact]
        public void TestMaxPlatformVersionWithTargetFrameworkVersion()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "TestMaxPlatformVersionWithTargetFrameworkVersion");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents1 =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK'
                FrameworkIdentity = ''
                PlatformIdentity = 'Windows'
                APPX = ''
                SDKType=''
                CopyRedistToSubDirectory=''
                SupportedArchitectures=''
                ProductFamilyName=''
                SupportsMultipleVersions=''
                ArchitectureForRuntime = ''
                DependsOn = ''
                MaxPlatformVersion = '6.0'
                MinOSVersion = ''
                MaxOSVersionTested = ''
                MoreInfo='ESDK information'
               >
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            string sdkManifestContents2 =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK'
                FrameworkIdentity = 'Windows'
                PlatformIdentity = ''
                APPX = ''
                SDKType=''
                CopyRedistToSubDirectory=''
                SupportedArchitectures=''
                ProductFamilyName=''
                SupportsMultipleVersions=''
                ArchitectureForRuntime = ''
                DependsOn = ''
                MaxPlatformVersion = '8.0'
                MinOSVersion = ''
                MaxOSVersionTested = ''
                MoreInfo='ESDK information'
               >
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";


            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");

                // In the test below the SDK MaxPlatformVersion is smaller than the TargetPlatformVersion - the build fails
                File.WriteAllText(sdkManifestFile, sdkManifestContents1);
                MockEngine engine1 = new MockEngine();
                ResolveSDKReference t1 = new ResolveSDKReference();
                t1.SDKReferences = new ITaskItem[] { item };
                t1.InstalledSDKs = new ITaskItem[] { installLocation };
                t1.TargetPlatformIdentifier = "Windows";
                t1.ProjectName = "myproject.csproj";
                t1.BuildEngine = engine1;
                bool succeeded1 = t1.Execute();

                Assert.True(succeeded1);
                engine1.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.MaxPlatformVersionLessThanTargetPlatformVersion", "myproject.csproj", "GoodTestSDK", "2.0", "Windows", "6.0", "Windows", "7.0");
                // In the test below the SDK MaxPlatformVersion is greater than the TargetPlatformVersion - the build succeeds
                File.WriteAllText(sdkManifestFile, sdkManifestContents2);
                MockEngine engine2 = new MockEngine();
                ResolveSDKReference t2 = new ResolveSDKReference();
                t2.SDKReferences = new ITaskItem[] { item };
                t2.InstalledSDKs = new ITaskItem[] { installLocation };
                t1.TargetPlatformIdentifier = "Windows";
                t1.ProjectName = "myproject.csproj";
                t2.BuildEngine = engine1;
                bool succeeded2 = t2.Execute();

                Assert.True(succeeded2);
                engine2.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.MaxPlatformVersionLessThanTargetPlatformVersion", "myproject.csproj", "GoodTestSDK", "2.0", "Windows", "6.0", "Windows", "7.0");
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where the manifest attributes are empty.
        /// </summary>
        [Fact]
        public void EmptySDKManifestAttributes()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "EmptySDKManifestAttributes");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = ''
                FrameworkIdentity = ''
                PlatformIdentity = ''
                APPX = ''
                SDKType=''
                CopyRedistToSubDirectory=''
                SupportedArchitectures=''
                ProductFamilyName=''
                SupportsMultipleVersions=''
                ArchitectureForRuntime = ''
                DependsOn = ''
                MaxPlatformVersion = ''
                MinOSVersion = ''
                MaxOSVersionTested = ''
               >
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);

                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"));
                Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"));
                Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("SDKType"));
                Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("SupportedArchitectures"));
                Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("ProductFamilyName"));
                Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("DisplayName"));
                Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("ArchitectureForRuntime"));
                Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("MaxPlatformVersion"));
                Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("MaxOSVersionTested"));
                Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("MinOSVersion"));
                Assert.Equal("Allow", t.ResolvedSDKReferences[0].GetMetadata("SupportsMultipleVersions"), true);
                Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("CopyRedistToSubDirectory"));
                Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
                Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);
                Assert.Equal("Retail", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"), true);
                Assert.Equal("Neutral", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"), true);
                Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where we override ALL of the manifest properties with ones on the metadata
        /// </summary>
        [Fact]
        public void OverrideManifestAttributes()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "OverrideManifestAttributes");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity = 'Manifest Identity'
                PlatformIdentity = 'Manifest platform Identity'
                APPX = 'Manifest Location'
                SDKType='External'
                SupportsMultipleVersions='Warning'
                MaxPlatformVersion = '8.0'
                MinOSVersion = '2.2.1'
                MaxOSVersionTested = '2.2.1'
                CopyRedistToSubDirectory = 'Manifest RedistSubDirectory'
                DependsOn ='Windows SDK, Version 8.0'>

                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />

            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                item.SetMetadata("FrameworkIdentity", "MetadataIdentity");
                item.SetMetadata("PlatformIdentity", "PlatformIdentity");
                item.SetMetadata("AppXLocation", "Metadata AppxLocation");
                item.SetMetadata("SDKType", "External");
                item.SetMetadata("SupportsMultipleVersions", "Error");
                item.SetMetadata("DisplayName", "ManifestDisplayName");
                item.SetMetadata("CopyRedist", "True");
                item.SetMetadata("ExpandReferenceAssemblies", "True");
                item.SetMetadata("CopyLocalExpandedReferenceAssemblies", "True");
                item.SetMetadata("TargetedSDKConfiguration", "Custom");
                item.SetMetadata("TargetedSDKArchitecture", "Any CPU");
                item.SetMetadata("CopyRedistToSubDirectory", "MyRedistSubDirectory");
                item.SetMetadata("MaxPlatformVersion", "9.0");
                item.SetMetadata("MaxOSVersionTested", "3.3.3");
                item.SetMetadata("MinOSVersion", "3.3.3");

                t.SDKReferences = new ITaskItem[] { item };

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);

                engine.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal("MetadataIdentity", t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"));
                Assert.Equal("PlatformIdentity", t.ResolvedSDKReferences[0].GetMetadata("PlatformIdentity"));
                Assert.Equal("Metadata AppxLocation", t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"));
                Assert.Equal("External", t.ResolvedSDKReferences[0].GetMetadata("SDKType"));
                Assert.Equal("Error", t.ResolvedSDKReferences[0].GetMetadata("SupportsMultipleVersions"));
                Assert.Equal("ManifestDisplayName", t.ResolvedSDKReferences[0].GetMetadata("DisplayName"));
                Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("CopyRedist"));
                Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"));
                Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"));
                Assert.Equal("Custom", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"));
                Assert.Equal("Neutral", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"));
                Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
                Assert.Equal("MyRedistSubDirectory", t.ResolvedSDKReferences[0].GetMetadata("CopyRedistToSubDirectory"));
                Assert.Equal("9.0", t.ResolvedSDKReferences[0].GetMetadata("MaxPlatformVersion"));
                Assert.Equal("3.3.3", t.ResolvedSDKReferences[0].GetMetadata("MaxOSVersionTested"));
                Assert.Equal("3.3.3", t.ResolvedSDKReferences[0].GetMetadata("MinOSVersion"));
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where we Have a good manifest that had framework and appx locations that exactly match the targeted sdk configuration and architecture.
        /// </summary>
        [Fact]
        public void GoodManifestMatchingConfigAndArch()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "GoodManifestMatchingConfigAndArch");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity = 'ShouldNotPickup'
                FrameworkIdentity-retail = 'ShouldNotPickup'
                FrameworkIdentity-retail-Neutral = 'GoodTestSDKIdentity'
                APPX = 'ShouldNotPickup'
                APPX-Retail = 'ShouldNotPickup'
                APPX-Retail-Neutral = 'RetailX86Location'
                SDKType='External'
                CopyRedistToSubDirectory='GoodTestSDK\Redist'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);

                engine.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal("GoodTestSDKIdentity", t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"));
                Assert.Equal("Neutral|RetailX86Location", t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"));
                Assert.Equal("External", t.ResolvedSDKReferences[0].GetMetadata("SDKType"));
                Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("CopyRedist"), true);
                Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
                Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);
                Assert.Equal("Retail", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"), true);
                Assert.Equal("Neutral", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"), true);
                Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
                Assert.Equal("GoodTestSDK\\Redist", t.ResolvedSDKReferences[0].GetMetadata("CopyRedistToSubDirectory"), true);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where we Have a good manifest that had framework and appx locations that only match the targeted sdk configuration.
        /// </summary>
        [Fact]
        public void GoodManifestMatchingConfigOnly()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "GoodManifestMatchingConfigOnly");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity = 'ShouldNotPickup'
                FrameworkIdentity-Retail = 'GoodTestSDKIdentity'
                FrameworkIdentity-Retail-x64 = 'ShouldNotPickup'
                APPX = 'ShouldNotPickup'
                APPX-Retail = 'RetailNeutralLocation'
                SDKType='External'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);

                engine.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal("GoodTestSDKIdentity", t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"), true);
                Assert.Equal("Neutral|RetailNeutralLocation", t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"), true);
                Assert.Equal("External", t.ResolvedSDKReferences[0].GetMetadata("SDKType"), true);
                Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
                Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);
                Assert.Equal("Retail", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"), true);
                Assert.Equal("Neutral", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"), true);
                Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// TVerify that when a platform identity is found that we do not copy the references or redist
        /// </summary>
        [Fact]
        public void NoCopyOnPlatformIdentityFound()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "NoCopyOnPlatformIdentityFound");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                PlatformIdentity = 'PlatformID'
                SDKType='External'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);

                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"));
                Assert.Empty(t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"));
                Assert.Equal("PlatformID", t.ResolvedSDKReferences[0].GetMetadata("PlatformIdentity"), true);
                Assert.Equal("External", t.ResolvedSDKReferences[0].GetMetadata("SDKType"), true);
                Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("CopyRedist"), true);
                Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
                Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);
                Assert.Equal("Retail", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"), true);
                Assert.Equal("Neutral", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"), true);
                Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where we Have a good manifest that had framework and appx locations that does not match any of the config arch combinations but does match
        /// and entry name simply FrameworkIdentity or APPX
        /// </summary>
        [Fact]
        public void GoodManifestMatchingBaseNameOnly()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "GoodManifestMatchingConfigOnly");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                PlatformIdentity = 'Good Platform'
                FrameworkIdentity = 'GoodTestSDKIdentity'
                FrameworkIdentity-Debug = 'ShouldNotPickup'
                FrameworkIdentity-Debug-x64 = 'ShouldNotPickup'
                APPX = 'Location'
                APPX-Debug = 'ShouldNotPickup'
                APPX-Debug-X64 = 'ShouldNotPickup'
                SDKType='External'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.TargetedSDKArchitecture = "x86";
                t.TargetedSDKConfiguration = "Release";
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);

                engine.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal("GoodTestSDKIdentity", t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"), true);
                Assert.Equal("Good Platform", t.ResolvedSDKReferences[0].GetMetadata("PlatformIdentity"), true);
                Assert.Equal("Neutral|Location", t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"), true);
                Assert.Equal("External", t.ResolvedSDKReferences[0].GetMetadata("SDKType"), true);
                Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
                Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);
                Assert.Equal("Retail", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"), true);
                Assert.Equal("X86", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"), true);
                Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where we only have the arm APPX and it can be found
        /// </summary>
        [Fact]
        public void ManifestOnlyHasArmLocation()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "ManifestOnlyHasArmLocation");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                PlatformIdentity = 'Good Platform'
                FrameworkIdentity = 'GoodTestSDKIdentity'
                APPX-ARM = 'ARMAppx'
                SDKType='External'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.TargetedSDKArchitecture = "arm";
                t.TargetedSDKConfiguration = "Debug";
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);
                Assert.Single(t.ResolvedSDKReferences);
                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal("GoodTestSDKIdentity", t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"));
                Assert.Equal("Good Platform", t.ResolvedSDKReferences[0].GetMetadata("PlatformIdentity"));
                Assert.Equal("arm|ARMAppx", t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"), true);
                Assert.Equal("External", t.ResolvedSDKReferences[0].GetMetadata("SDKType"), true);
                Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
                Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);
                Assert.Equal("Debug", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"), true);
                Assert.Equal("arm", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"), true);
                Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where we have a number of locations and arm APPX and can be found
        /// </summary>
        [Fact]
        public void ManifestArmLocationWithOthers()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "ManifestArmLocationWithOthers");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                PlatformIdentity = 'Good Platform'
                FrameworkIdentity = 'GoodTestSDKIdentity'
                APPX-ARM = 'ARMAppx'
                APPX-X86 = 'x86Appx'
                APPX-X64 = 'x64Appx'
                SDKType='External'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.TargetedSDKArchitecture = "arm";
                t.TargetedSDKConfiguration = "Debug";
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);
                Assert.Single(t.ResolvedSDKReferences);
                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal("GoodTestSDKIdentity", t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"), true);
                Assert.Equal("Good Platform", t.ResolvedSDKReferences[0].GetMetadata("PlatformIdentity"), true);
                Assert.Equal("arm|ARMAppx|x64|x64Appx|x86|x86Appx", t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"), true);
                Assert.Equal("External", t.ResolvedSDKReferences[0].GetMetadata("SDKType"), true);
                Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
                Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);
                Assert.Equal("Debug", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"), true);
                Assert.Equal("arm", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"), true);
                Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where there are framework identity attributes but none of the match and there is no base FrameworkIdentity, the
        /// same is true for APPX.
        /// </summary>
        [Fact]
        public void MatchNoNamesButNamesExistWarning()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "MatchNoNamesButNamesExistWarning");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity-Debug = 'ShouldNotPickup'
                FrameworkIdentity-Debug-x64 = 'ShouldNotPickup'
                APPX-Debug = 'ShouldNotPickup'
                APPX-Debug-X64 = 'ShouldNotPickup'
                SDKType='External'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.TargetedSDKArchitecture = "x86";
                t.TargetedSDKConfiguration = "Release";
                t.BuildEngine = engine;
                t.LogResolutionErrorsAsWarnings = true;
                bool succeeded = t.Execute();
                Assert.True(succeeded);

                Assert.Single(t.ResolvedSDKReferences);

                string message = ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveSDKReference.ReadingSDKManifestFile", sdkManifestFile);
                engine.AssertLogContains(message);

                string errorMessage = ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveSDKReference.NoMatchingFrameworkIdentity", sdkManifestFile, "Retail", "x86");
                engine.AssertLogContains(errorMessage);

                errorMessage = ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveSDKReference.NoMatchingAppxLocation", sdkManifestFile, "Retail", "x86");
                engine.AssertLogContains(errorMessage);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where there are framework identity attributes but none of the match and there is no base FrameworkIdentity, the
        /// same is true for APPX.
        /// </summary>
        [Fact]
        public void MatchNoNamesButNamesExistError()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "MatchNoNamesButNamesExistError");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity-Debug = 'ShouldNotPickup'
                FrameworkIdentity-Debug-x64 = 'ShouldNotPickup'
                APPX-Debug = 'ShouldNotPickup'
                APPX-Debug-X64 = 'ShouldNotPickup'
                SDKType='External'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.TargetedSDKArchitecture = "x86";
                t.TargetedSDKConfiguration = "Release";
                t.LogResolutionErrorsAsWarnings = false;
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.False(succeeded);

                Assert.Empty(t.ResolvedSDKReferences);

                string errorMessage = ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveSDKReference.NoMatchingFrameworkIdentity", sdkManifestFile, "Retail", "x86");
                engine.AssertLogContains(errorMessage);

                errorMessage = ResourceUtilities.FormatResourceStringStripCodeAndKeyword("ResolveSDKReference.NoMatchingAppxLocation", sdkManifestFile, "Retail", "x86");
                engine.AssertLogContains(errorMessage);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }


        /// <summary>
        /// Test the case where there is a single supported architecture and the project targets that architecture
        /// </summary>
        [Fact]
        public void SingleSupportedArchitectureMatchesProject()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "SingleSupportedArchitectureMatchesProject");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity-retail-x86 = 'GoodTestSDKIdentity'
                APPX-Retail-x86 = 'RetailX86Location'
                APPX-Retail-x64 = 'RetailX64Location'
                SDKType='External'
                SupportedArchitectures = 'X86'
                CopyRedistToSubDirectory='GoodTestSDK\Redist'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKArchitecture = "x86";
                t.TargetedSDKConfiguration = "Release";

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);

                engine.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal("GoodTestSDKIdentity", t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"), true);
                Assert.Equal("x64|RetailX64Location|x86|RetailX86Location", t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"), true);
                Assert.Equal("External", t.ResolvedSDKReferences[0].GetMetadata("SDKType"), true);
                Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("CopyRedist"), true);
                Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
                Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);
                Assert.Equal("Retail", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"), true);
                Assert.Equal("X86", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"), true);
                Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
                Assert.Equal("GoodTestSDK\\Redist", t.ResolvedSDKReferences[0].GetMetadata("CopyRedistToSubDirectory"), true);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where the productfamily is set in the manifest and not as metadata on the reference item.
        /// </summary>
        [Fact]
        public void ProductFamilySetInManifest()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "ProductFamilySetInManifest");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity-retail-x86 = 'GoodTestSDKIdentity'
                APPX-Retail-x86 = 'RetailX86Location'
                APPX-Retail-x64 = 'RetailX64Location'
                SDKType='External'
                SupportedArchitectures = 'X86'
                ProductFamilyName = 'MyFamily'
                CopyRedistToSubDirectory='GoodTestSDK\Redist'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKArchitecture = "x86";
                t.TargetedSDKConfiguration = "Release";

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);

                engine.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal("MyFamily", t.ResolvedSDKReferences[0].GetMetadata("ProductFamilyName"));
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where the productfamily is set in the manifest and as metadata on the reference item. Expect the metadata to win.
        /// </summary>
        [Fact]
        public void ProductFamilySetInManifestAndMetadata()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "ProductFamilySetInManifestAndMetadata");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity-retail-x86 = 'GoodTestSDKIdentity'
                APPX-Retail-x86 = 'RetailX86Location'
                APPX-Retail-x64 = 'RetailX64Location'
                SDKType='External'
                SupportedArchitectures = 'X86'
                ProductFamilyName = 'MyFamily'
                CopyRedistToSubDirectory='GoodTestSDK\Redist'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                item.SetMetadata("ProductFamilyName", "MetadataFamily");

                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKArchitecture = "x86";
                t.TargetedSDKConfiguration = "Release";

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);

                engine.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal("MetadataFamily", t.ResolvedSDKReferences[0].GetMetadata("ProductFamilyName"));
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where the SupportsMultipleVersions is NOT in the manifest or on metadata
        /// </summary>
        [Fact]
        public void SupportsMultipleVersionsNotInManifest()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "SupportsMultipleVersionsNotInManifest");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity-retail-x86 = 'GoodTestSDKIdentity'
                APPX-Retail-x86 = 'RetailX86Location'
                APPX-Retail-x64 = 'RetailX64Location'
                SDKType='External'
                SupportedArchitectures = 'X86'
                ProductFamilyName = 'MyFamily'
                CopyRedistToSubDirectory='GoodTestSDK\Redist'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKArchitecture = "x86";
                t.TargetedSDKConfiguration = "Release";

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);
                Assert.Equal(0, engine.Warnings);
                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal("Allow", t.ResolvedSDKReferences[0].GetMetadata("SupportsMultipleVersions"));
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where metadata on the item is bad, we should then read from the manifest.
        /// </summary>
        [Fact]
        public void SupportsMultipleVersionsBadMetadata()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "SupportsMultipleVersionsBadMetadata");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity-retail-x86 = 'GoodTestSDKIdentity'
                APPX-Retail-x86 = 'RetailX86Location'
                APPX-Retail-x64 = 'RetailX64Location'
                SDKType='External'
                SupportedArchitectures = 'X86'
                ProductFamilyName = 'MyFamily'
                SupportsMultipleVersions='Warning'
                CopyRedistToSubDirectory='GoodTestSDK\Redist'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                item.SetMetadata("SupportsMultipleVersions", "WoofWoof");

                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKArchitecture = "x86";
                t.TargetedSDKConfiguration = "Release";

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);

                engine.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal("Warning", t.ResolvedSDKReferences[0].GetMetadata("SupportsMultipleVersions"));
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where there are conflicts between sdks of the same product family
        /// </summary>
        [Fact]
        public void ConflictsBetweenSameProductFamilySameName()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "ConflictsBetweenSameProductFamilySameName");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "1.0") + Path.DirectorySeparatorChar;
            string testDirectory2 = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string testDirectory3 = Path.Combine(testDirectoryRoot, "GoodTestSDK", "3.0") + Path.DirectorySeparatorChar;

            string sdkManifestContents1 =
            @"<FileList
                Identity = 'GoodTestSDK, Version=1.0'
                DisplayName = 'GoodTestSDK 1.0'
                ProductFamilyName = 'MyFamily'
                SupportsMultipleVersions='Warning'>
            </FileList>";

            string sdkManifestContents2 =
           @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                ProductFamilyName = 'MyFamily'
                SupportsMultipleVersions='Error'>
            </FileList>";

            string sdkManifestContents3 =
           @"<FileList
                Identity = 'GoodTestSDK, Version=3.0'
                DisplayName = 'GoodTestSDK 3.0'
                ProductFamilyName = 'MyFamily'
                SupportsMultipleVersions='Allow'>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                string sdkManifestFile2 = Path.Combine(testDirectory2, "SDKManifest.xml");
                string sdkManifestFile3 = Path.Combine(testDirectory3, "SDKManifest.xml");

                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);
                Directory.CreateDirectory(testDirectory2);
                Directory.CreateDirectory(testDirectory3);

                File.WriteAllText(sdkManifestFile, sdkManifestContents1);
                File.WriteAllText(sdkManifestFile2, sdkManifestContents2);
                File.WriteAllText(sdkManifestFile3, sdkManifestContents3);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=1.0");
                ITaskItem item2 = new TaskItem("GoodTestSDK, Version=2.0");
                ITaskItem item3 = new TaskItem("GoodTestSDK, Version=3.0");

                t.SDKReferences = new ITaskItem[] { item, item2, item3 };
                t.TargetedSDKArchitecture = "x86";
                t.TargetedSDKConfiguration = "Release";

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=1.0");

                ITaskItem installLocation2 = new TaskItem(testDirectory2);
                installLocation2.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");

                ITaskItem installLocation3 = new TaskItem(testDirectory3);
                installLocation3.SetMetadata("SDKName", "GoodTestSDK, Version=3.0");

                t.InstalledSDKs = new ITaskItem[] { installLocation, installLocation2, installLocation3 };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.False(succeeded);

                engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.CannotReferenceTwoSDKsSameFamily", "GoodTestSDK, Version=1.0", "\"GoodTestSDK, Version=2.0\", \"GoodTestSDK, Version=3.0\"", "MyFamily");
                engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.CannotReferenceTwoSDKsSameFamily", "GoodTestSDK, Version=2.0", "\"GoodTestSDK, Version=1.0\", \"GoodTestSDK, Version=3.0\"", "MyFamily");
                Assert.Equal(1, engine.Warnings);
                Assert.Equal(1, engine.Errors);

                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal(testDirectory2, t.ResolvedSDKReferences[1].ItemSpec);
                Assert.Equal(testDirectory3, t.ResolvedSDKReferences[2].ItemSpec);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where there are conflicts between sdks of the same product family
        /// </summary>
        [Fact]
        public void ConflictsBetweenSameProductFamilyDiffName()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "ConflictsBetweenSameProductFamilyDiffName");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "1.0") + Path.DirectorySeparatorChar;
            string testDirectory2 = Path.Combine(testDirectoryRoot, "GoodTestSDK1", "2.0") + Path.DirectorySeparatorChar;
            string testDirectory3 = Path.Combine(testDirectoryRoot, "GoodTestSDK3", "3.0") + Path.DirectorySeparatorChar;

            string sdkManifestContents1 =
            @"<FileList
                Identity = 'GoodTestSDK, Version=1.0'
                DisplayName = 'GoodTestSDK 1.0'
                ProductFamilyName = 'MyFamily'
                SupportsMultipleVersions='Warning'>
            </FileList>";

            string sdkManifestContents2 =
           @"<FileList
                Identity = 'GoodTestSDK2, Version=2.0'
                DisplayName = 'GoodTestSDK2 2.0'
                ProductFamilyName = 'MyFamily'
                SupportsMultipleVersions='Error'>
            </FileList>";

            string sdkManifestContents3 =
           @"<FileList
                Identity = 'GoodTestSDK3, Version=3.0'
                DisplayName = 'GoodTestSDK3 3.0'
                ProductFamilyName = 'MyFamily'
                SupportsMultipleVersions='Allow'>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                string sdkManifestFile2 = Path.Combine(testDirectory2, "SDKManifest.xml");
                string sdkManifestFile3 = Path.Combine(testDirectory3, "SDKManifest.xml");

                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);
                Directory.CreateDirectory(testDirectory2);
                Directory.CreateDirectory(testDirectory3);

                File.WriteAllText(sdkManifestFile, sdkManifestContents1);
                File.WriteAllText(sdkManifestFile2, sdkManifestContents2);
                File.WriteAllText(sdkManifestFile3, sdkManifestContents3);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=1.0");
                ITaskItem item2 = new TaskItem("GoodTestSDK2, Version=2.0");
                ITaskItem item3 = new TaskItem("GoodTestSDK3, Version=3.0");

                t.SDKReferences = new ITaskItem[] { item, item2, item3 };
                t.TargetedSDKArchitecture = "x86";
                t.TargetedSDKConfiguration = "Release";

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=1.0");

                ITaskItem installLocation2 = new TaskItem(testDirectory2);
                installLocation2.SetMetadata("SDKName", "GoodTestSDK2, Version=2.0");

                ITaskItem installLocation3 = new TaskItem(testDirectory3);
                installLocation3.SetMetadata("SDKName", "GoodTestSDK3, Version=3.0");

                t.InstalledSDKs = new ITaskItem[] { installLocation, installLocation2, installLocation3 };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.False(succeeded);

                engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.CannotReferenceTwoSDKsSameFamily", "GoodTestSDK, Version=1.0", "\"GoodTestSDK2, Version=2.0\", \"GoodTestSDK3, Version=3.0\"", "MyFamily");
                engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.CannotReferenceTwoSDKsSameFamily", "GoodTestSDK2, Version=2.0", "\"GoodTestSDK, Version=1.0\", \"GoodTestSDK3, Version=3.0\"", "MyFamily");
                Assert.Equal(1, engine.Warnings);
                Assert.Equal(1, engine.Errors);

                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal(testDirectory2, t.ResolvedSDKReferences[1].ItemSpec);
                Assert.Equal(testDirectory3, t.ResolvedSDKReferences[2].ItemSpec);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where there are conflicts between sdks of the same product family
        /// </summary>
        [Fact]
        public void ConflictsBetweenMIXPFAndName()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "ConflictsBetweenSameProductFamilyDiffName");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "1.0") + Path.DirectorySeparatorChar;
            string testDirectory2 = Path.Combine(testDirectoryRoot, "GoodTestSDK2", "2.0") + Path.DirectorySeparatorChar;
            string testDirectory3 = Path.Combine(testDirectoryRoot, "GoodTestSDK3", "3.0") + Path.DirectorySeparatorChar;
            string testDirectory4 = Path.Combine(testDirectoryRoot, "GoodTestSDK3", "4.0") + Path.DirectorySeparatorChar;

            string sdkManifestContents1 =
            @"<FileList
                Identity = 'GoodTestSDK, Version=1.0'
                DisplayName = 'GoodTestSDK 1.0'
                ProductFamilyName = 'MyFamily'
                SupportsMultipleVersions='Warning'>
            </FileList>";

            string sdkManifestContents2 =
           @"<FileList
                Identity = 'GoodTestSDK2, Version=2.0'
                DisplayName = 'GoodTestSDK2 2.0'
                ProductFamilyName = 'MyFamily'
                SupportsMultipleVersions='Allow'>
            </FileList>";

            string sdkManifestContents3 =
           @"<FileList
                Identity = 'GoodTestSDK3, Version=3.0'
                DisplayName = 'GoodTestSDK3 3.0'
                SupportsMultipleVersions='Warning'>
            </FileList>";


            string sdkManifestContents4 =
           @"<FileList
                Identity = 'GoodTestSDK3, Version=4.0'
                DisplayName = 'GoodTestSDK3 4.0'
                SupportsMultipleVersions='Allow'>
            </FileList>";
            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                string sdkManifestFile2 = Path.Combine(testDirectory2, "SDKManifest.xml");
                string sdkManifestFile3 = Path.Combine(testDirectory3, "SDKManifest.xml");
                string sdkManifestFile4 = Path.Combine(testDirectory4, "SDKManifest.xml");

                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);
                Directory.CreateDirectory(testDirectory2);
                Directory.CreateDirectory(testDirectory3);
                Directory.CreateDirectory(testDirectory4);

                File.WriteAllText(sdkManifestFile, sdkManifestContents1);
                File.WriteAllText(sdkManifestFile2, sdkManifestContents2);
                File.WriteAllText(sdkManifestFile3, sdkManifestContents3);
                File.WriteAllText(sdkManifestFile4, sdkManifestContents4);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=1.0");
                ITaskItem item2 = new TaskItem("GoodTestSDK2, Version=2.0");
                ITaskItem item3 = new TaskItem("GoodTestSDK3, Version=3.0");
                ITaskItem item4 = new TaskItem("GoodTestSDK3, Version=4.0");

                t.SDKReferences = new ITaskItem[] { item, item2, item3, item4 };
                t.TargetedSDKArchitecture = "x86";
                t.TargetedSDKConfiguration = "Release";

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=1.0");

                ITaskItem installLocation2 = new TaskItem(testDirectory2);
                installLocation2.SetMetadata("SDKName", "GoodTestSDK2, Version=2.0");

                ITaskItem installLocation3 = new TaskItem(testDirectory3);
                installLocation3.SetMetadata("SDKName", "GoodTestSDK3, Version=3.0");

                ITaskItem installLocation4 = new TaskItem(testDirectory4);
                installLocation4.SetMetadata("SDKName", "GoodTestSDK3, Version=4.0");

                t.InstalledSDKs = new ITaskItem[] { installLocation, installLocation2, installLocation3, installLocation4 };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);

                engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.CannotReferenceTwoSDKsSameFamily", "GoodTestSDK, Version=1.0", "\"GoodTestSDK2, Version=2.0\"", "MyFamily");
                engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.CannotReferenceTwoSDKsSameName", "GoodTestSDK3, Version=3.0", "\"GoodTestSDK3, Version=4.0\"");
                Assert.Equal(2, engine.Warnings);
                Assert.Equal(0, engine.Errors);

                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal(testDirectory2, t.ResolvedSDKReferences[1].ItemSpec);
                Assert.Equal(testDirectory3, t.ResolvedSDKReferences[2].ItemSpec);
                Assert.Equal(testDirectory4, t.ResolvedSDKReferences[3].ItemSpec);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where there are conflicts between sdks of the same SDK Name
        /// </summary>
        [Fact]
        public void ConflictsBetweenSameSDKName()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "ConflictsBetweenSameSDKName");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "1.0") + Path.DirectorySeparatorChar;
            string testDirectory2 = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string testDirectory3 = Path.Combine(testDirectoryRoot, "GoodTestSDK", "3.0") + Path.DirectorySeparatorChar;

            string sdkManifestContents1 =
            @"<FileList
                Identity = 'GoodTestSDK, Version=1.0'
                DisplayName = 'GoodTestSDK 1.0'
                ProductFamilyName = 'MyFamily'
                SupportsMultipleVersions='Warning'>
            </FileList>";

            string sdkManifestContents2 =
           @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                ProductFamilyName = 'MyFamily2'
                SupportsMultipleVersions='Error'>
            </FileList>";

            string sdkManifestContents3 =
           @"<FileList
                Identity = 'GoodTestSDK, Version=3.0'
                DisplayName = 'GoodTestSDK 3.0'
                ProductFamilyName = 'MyFamily3'
                SupportsMultipleVersions='Allow'>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                string sdkManifestFile2 = Path.Combine(testDirectory2, "SDKManifest.xml");
                string sdkManifestFile3 = Path.Combine(testDirectory3, "SDKManifest.xml");

                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);
                Directory.CreateDirectory(testDirectory2);
                Directory.CreateDirectory(testDirectory3);

                File.WriteAllText(sdkManifestFile, sdkManifestContents1);
                File.WriteAllText(sdkManifestFile2, sdkManifestContents2);
                File.WriteAllText(sdkManifestFile3, sdkManifestContents3);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=1.0");
                ITaskItem item2 = new TaskItem("GoodTestSDK, Version=2.0");
                ITaskItem item3 = new TaskItem("GoodTestSDK, Version=3.0");

                t.SDKReferences = new ITaskItem[] { item, item2, item3 };
                t.TargetedSDKArchitecture = "x86";
                t.TargetedSDKConfiguration = "Release";

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=1.0");

                ITaskItem installLocation2 = new TaskItem(testDirectory2);
                installLocation2.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");

                ITaskItem installLocation3 = new TaskItem(testDirectory3);
                installLocation3.SetMetadata("SDKName", "GoodTestSDK, Version=3.0");

                t.InstalledSDKs = new ITaskItem[] { installLocation, installLocation2, installLocation3 };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.False(succeeded);

                engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.CannotReferenceTwoSDKsSameName", "GoodTestSDK, Version=1.0", "\"GoodTestSDK, Version=2.0\", \"GoodTestSDK, Version=3.0\"");
                engine.AssertLogContainsMessageFromResource(_resourceDelegate, "ResolveSDKReference.CannotReferenceTwoSDKsSameName", "GoodTestSDK, Version=2.0", "\"GoodTestSDK, Version=1.0\", \"GoodTestSDK, Version=3.0\"");
                Assert.Equal(1, engine.Warnings);
                Assert.Equal(1, engine.Errors);

                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal(testDirectory2, t.ResolvedSDKReferences[1].ItemSpec);
                Assert.Equal(testDirectory3, t.ResolvedSDKReferences[2].ItemSpec);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where metadata on the item is bad, we should then read from the manifest.
        /// </summary>
        [Fact]
        public void SupportsMultipleVersionsReadManifest()
        {
            SupportsMultipleVersionsVerifyManifestReading("Error");
            SupportsMultipleVersionsVerifyManifestReading("Warning");
            SupportsMultipleVersionsVerifyManifestReading("Allow");
            SupportsMultipleVersionsVerifyManifestReading("WoofWoof");
        }

        private void SupportsMultipleVersionsVerifyManifestReading(string manifestEntry)
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "SupportsMultipleVersionsVerifyManifestReading");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity-retail-x86 = 'GoodTestSDKIdentity'
                APPX-Retail-x86 = 'RetailX86Location'
                APPX-Retail-x64 = 'RetailX64Location'
                SDKType='External'
                SupportedArchitectures = 'X86'
                ProductFamilyName = 'MyFamily'
                SupportsMultipleVersions='" + manifestEntry + @"'
                CopyRedistToSubDirectory='GoodTestSDK\Redist'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");

                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKArchitecture = "x86";
                t.TargetedSDKConfiguration = "Release";

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);

                engine.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                if (String.Equals(manifestEntry, "WoofWoof", StringComparison.OrdinalIgnoreCase))
                {
                    Assert.Equal("Allow", t.ResolvedSDKReferences[0].GetMetadata("SupportsMultipleVersions"));
                }
                else
                {
                    Assert.Equal(manifestEntry, t.ResolvedSDKReferences[0].GetMetadata("SupportsMultipleVersions"));
                }
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where the supportedArchitectures are empty
        /// </summary>
        [Fact]
        public void EmptyArchitectures()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "OverrideManifestWithMetadata");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity-retail-x86 = 'GoodTestSDKIdentity'
                APPX = 'NeutralLocation'
                APPX-Retail-x86 = 'RetailX86Location'
                APPX-Retail-x64 = 'RetailX64Location'
                APPX-Retail-Arm = 'RetailArmLocation'
                SDKType='External'
                SupportedArchitectures = ';  ;  ;  ;'
                CopyRedistToSubDirectory='GoodTestSDK\Redist'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                item.SetMetadata("SupportedArchitectures", "X86");

                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKArchitecture = "X86";
                t.TargetedSDKConfiguration = "Release";

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);

                engine.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal("GoodTestSDKIdentity", t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"), true);
                Assert.Equal("Arm|RetailArmLocation|Neutral|NeutralLocation|X64|RetailX64Location|X86|RetailX86Location", t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"), true);
                Assert.Equal("External", t.ResolvedSDKReferences[0].GetMetadata("SDKType"), true);
                Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("CopyRedist"), true);
                Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
                Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);
                Assert.Equal("Retail", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"), true);
                Assert.Equal("X86", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"), true);
                Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
                Assert.Equal("GoodTestSDK\\Redist", t.ResolvedSDKReferences[0].GetMetadata("CopyRedistToSubDirectory"), true);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where the metadata on the reference overrides what is in the manifest but it does not match what is being targeted
        /// </summary>
        [Fact]
        public void OverrideManifestWithMetadataButMetadataDoesNotMatch()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "OverrideManifestWithMetadataButMetadataDoesNotMatch");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity-retail-x86 = 'GoodTestSDKIdentity'
                APPX = 'ShouldNotPickup'
                APPX-Retail-x86 = 'RetailX86Location'
                APPX-Retail-x64 = 'RetailX64Location'
                SDKType='External'
                SupportedArchitectures = 'X86'
                CopyRedistToSubDirectory='GoodTestSDK\Redist'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                item.SetMetadata("SupportedArchitectures", "ARM");

                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKArchitecture = "X86";
                t.TargetedSDKConfiguration = "Release";

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.False(succeeded);

                Assert.Empty(t.ResolvedSDKReferences);
                engine.AssertLogContains("MSB3779");
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where the metadata on the reference overrides what is in the manifest
        /// </summary>
        [Fact]
        public void OverrideManifestWithMetadata()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "OverrideManifestWithMetadata");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity-retail-x86 = 'GoodTestSDKIdentity'
                APPX = 'NeutralLocation'
                APPX-Debug-x86 = 'DebugX86Location'
                APPX-Debug-x64 = 'DebugX64Location'
                APPX-Retail-x86 = 'RetailX86Location'
                APPX-Retail-x64 = 'RetailX64Location'
                SDKType='External'
                SupportedArchitectures = 'ARM'
                CopyRedistToSubDirectory='GoodTestSDK\Redist'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                item.SetMetadata("SupportedArchitectures", "X64;X86;Neutral");

                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKArchitecture = "X86";
                t.TargetedSDKConfiguration = "Release";

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);

                engine.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal("GoodTestSDKIdentity", t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"));
                Assert.Equal("Neutral|NeutralLocation|X64|RetailX64Location|X86|RetailX86Location", t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"), true);
                Assert.Equal("External", t.ResolvedSDKReferences[0].GetMetadata("SDKType"), true);
                Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("CopyRedist"), true);
                Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
                Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);
                Assert.Equal("Retail", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"), true);
                Assert.Equal("X86", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"), true);
                Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
                Assert.Equal("GoodTestSDK\\Redist", t.ResolvedSDKReferences[0].GetMetadata("CopyRedistToSubDirectory"), true);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where there is a single supported architecture and the project does not target that architecture
        /// </summary>
        [Fact]
        public void SingleSupportedArchitectureDoesNotMatchProject()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "SingleSupportedArchitectureDoesNotMatchProject");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity-retail-x86 = 'GoodTestSDKIdentity'
                APPX = 'ShouldNotPickup'
                APPX-Retail-x86 = 'RetailX86Location'
                APPX-Retail-x64 = 'RetailX64Location'
                SDKType='External'
                SupportedArchitectures = 'ARM'
                CopyRedistToSubDirectory='GoodTestSDK\Redist'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKArchitecture = "X86";
                t.TargetedSDKConfiguration = "Release";

                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.False(succeeded);

                Assert.Empty(t.ResolvedSDKReferences);
                engine.AssertLogContains("MSB3779");
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where there is are multiple supported architecture and the project targets one of those architectures
        /// </summary>
        [Fact]
        public void MultipleSupportedArchitectureMatchesProject()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "MultipleSupportedArchitectureMatchesProject");
            string testDirectory = Path.Combine(testDirectoryRoot, "GoodTestSDK", "2.0") + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity-retail-Neutral = 'GoodTestSDKIdentity'
                APPX = 'ShouldNotPickup'
                APPX-Retail-Neutral = 'RetailNeutralLocation'
                SDKType='External'
                SupportedArchitectures = 'X86;Neutral;X64'
                CopyRedistToSubDirectory='GoodTestSDK\Redist'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKArchitecture = "AnyCPU";
                t.TargetedSDKConfiguration = "Release";
                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.True(succeeded);

                engine.AssertLogDoesntContainMessageFromResource(_resourceDelegate, "ResolveSDKReference.NoFrameworkIdentitiesFound");
                Assert.Equal(testDirectory, t.ResolvedSDKReferences[0].ItemSpec);
                Assert.Equal("GoodTestSDKIdentity", t.ResolvedSDKReferences[0].GetMetadata("FrameworkIdentity"), true);
                Assert.Equal("Neutral|RetailNeutralLocation", t.ResolvedSDKReferences[0].GetMetadata("AppXLocation"), true);
                Assert.Equal("External", t.ResolvedSDKReferences[0].GetMetadata("SDKType"), true);
                Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("CopyRedist"), true);
                Assert.Equal("True", t.ResolvedSDKReferences[0].GetMetadata("ExpandReferenceAssemblies"), true);
                Assert.Equal("False", t.ResolvedSDKReferences[0].GetMetadata("CopyLocalExpandedReferenceAssemblies"), true);
                Assert.Equal("Retail", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"), true);
                Assert.Equal("Neutral", t.ResolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"), true);
                Assert.Equal(item.ItemSpec, t.ResolvedSDKReferences[0].GetMetadata("OriginalItemSpec"), true);
                Assert.Equal("GoodTestSDK\\Redist", t.ResolvedSDKReferences[0].GetMetadata("CopyRedistToSubDirectory"), true);
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        /// <summary>
        /// Test the case where there is are multiple supported architecture and the project does not match one of those architectures
        /// </summary>
        [Fact]
        public void MultipleSupportedArchitectureDoesNotMatchProject()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "MultipleSupportedArchitectureMatchesProject");
            string testDirectory =
                Path.Combine(new[] { testDirectoryRoot, "MyPlatform", "8.0", "ExtensionSDKs", "SDkWithManifest", "2.0" })
                + Path.DirectorySeparatorChar;
            string sdkManifestContents =
            @"<FileList
                Identity = 'GoodTestSDK, Version=2.0'
                DisplayName = 'GoodTestSDK 2.0'
                FrameworkIdentity-retail-Neutral = 'GoodTestSDKIdentity'
                APPX = 'ShouldNotPickup'
                APPX-Retail-Neutral = 'RetailNeutralLocation'
                SDKType='External'
                SupportedArchitectures = 'X86;Neutral;X64'
                CopyRedistToSubDirectory='GoodTestSDK\Redist'>
                <File WinMD = 'GoodTestSDK.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            try
            {
                string sdkManifestFile = Path.Combine(testDirectory, "SDKManifest.xml");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectory);

                File.WriteAllText(sdkManifestFile, sdkManifestContents);

                // Create the engine.
                MockEngine engine = new MockEngine();

                ResolveSDKReference t = new ResolveSDKReference();
                ITaskItem item = new TaskItem("GoodTestSDK, Version=2.0");
                t.SDKReferences = new ITaskItem[] { item };
                t.TargetedSDKArchitecture = "ARM";
                t.TargetedSDKConfiguration = "Release";
                ITaskItem installLocation = new TaskItem(testDirectory);
                installLocation.SetMetadata("SDKName", "GoodTestSDK, Version=2.0");
                t.InstalledSDKs = new ITaskItem[] { installLocation };
                t.BuildEngine = engine;
                bool succeeded = t.Execute();
                Assert.False(succeeded);

                Assert.Empty(t.ResolvedSDKReferences);
                engine.AssertLogContains("MSB3779");
            }
            finally
            {
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }
        #endregion
    }

    /// <summary>
    /// Test the output groups which will be used to generate the recipe fileGatherSDKOutputGroups
    /// </summary>
    public class GatherSDKOutputGroupsTestFixture
    {
        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]     // No GetResolvedSDKReferences target in Unix
        public void GatherSDKOutputGroupsTargetArchitectureExists()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "GatherSDKOutputGroupsWithFramework");
            string sdkDirectory = Path.Combine(testDirectoryRoot, "MyPlatform\\8.0\\ExtensionSDKs\\SDkWithManifest\\2.0\\");
            string archRedist = Path.Combine(sdkDirectory, "Redist\\Retail\\x86");
            string neutralRedist = Path.Combine(sdkDirectory, "Redist\\Retail\\Neutral");
            string archCommonRedist = Path.Combine(sdkDirectory, "Redist\\CommonConfiguration\\x86");
            string neutralCommonRedist = Path.Combine(sdkDirectory, "Redist\\CommonConfiguration\\Neutral");

            string sdkDirectory3 = Path.Combine(testDirectoryRoot, "MyPlatform\\8.0\\ExtensionSDKs\\FrameworkSDkWithManifest\\2.0\\");
            string archRedist3 = Path.Combine(sdkDirectory3, "Redist\\Retail\\x64");
            string archRedist33 = Path.Combine(sdkDirectory3, "Redist\\Retail\\Neutral");
            string archCommonRedist3 = Path.Combine(sdkDirectory3, "Redist\\CommonConfiguration\\x64");

            string sdkManifestContents =
            @"<FileList
                Identity = 'SDkWithManifest, Version=2.0'
                APPX ='AppxLocation'
                SDKType ='External'
                DisplayName = 'SDkWithManifest 2.0'
                CopyRedistToSubDirectory='SomeOtherRedistDirectory'>
                <File WinMD = 'SDkWithManifest.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            string sdkManifestContents2 =
          @"<FileList
                Identity = 'FrameworkSDkWithManifest, Version=2.0'
                FrameworkIdentity='FrameworkSDK'
                APPX ='AppxLocation'
                SDKType ='External'
                DisplayName = 'AnotherSDkWithManifest 2.0'
                CopyRedistToSubDirectory='SomeOtherRedistDirectory'> 
                <File WinMD = 'AnotherSDkWithManifest.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            string tempProjectContents = ObjectModelHelpers.CleanupFileContents(
             @"
             <Project DefaultTargets=""ExpandSDKReferenceAssemblies"" ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""msbuildnamespace"">
                 <ItemGroup>
                  <SDKReference Include=""SDkWithManifest, Version=2.0"">
                      <TargetedSDKConfiguration>Release</TargetedSDKConfiguration>
                      <CopyRedistToSubDirectory>AnotherRedistLocation</CopyRedistToSubDirectory>
                   </SDKReference>
                <SDKReference Include=""FrameworkSDKWithManifest, Version=2.0"">
                      <TargetedSDKArchitecture>amd64</TargetedSDKArchitecture>
                      <CopyRedistToSubDirectory>AnotherRedistLocation</CopyRedistToSubDirectory>
                   </SDKReference>
                 </ItemGroup>
                 <PropertyGroup>
                     <Configuration>CAT</Configuration>" +
                    @"<OutputPath>" + testDirectoryRoot + "</OutputPath>" +
                    @"<TargetPlatformIdentifier>MyPlatform</TargetPlatformIdentifier> 
                    <TargetPlatformVersion>8.0</TargetPlatformVersion>
                 </PropertyGroup>
                 <Import Project=""$(MSBuildBinPath)\Microsoft.Common.targets""/>
              </Project>");

            try
            {
                Environment.SetEnvironmentVariable("MSBUILDSDKREFERENCEDIRECTORY", testDirectoryRoot);
                Environment.SetEnvironmentVariable("MSBUILDDISABLEREGISTRYFORSDKLOOKUP", "true");

                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectoryRoot);
                Directory.CreateDirectory(sdkDirectory);
                Directory.CreateDirectory(archRedist);
                Directory.CreateDirectory(neutralRedist);
                Directory.CreateDirectory(archCommonRedist);
                Directory.CreateDirectory(neutralCommonRedist);

                Directory.CreateDirectory(sdkDirectory3);
                Directory.CreateDirectory(archRedist3);
                Directory.CreateDirectory(archRedist33);
                Directory.CreateDirectory(archCommonRedist3);

                string sdkManifestFile = Path.Combine(sdkDirectory, "SDKManifest.xml");
                string sdkManifestFile2 = Path.Combine(sdkDirectory3, "SDKManifest.xml");
                string testProjectFile = Path.Combine(testDirectoryRoot, "testproject.csproj");

                File.WriteAllText(sdkManifestFile, sdkManifestContents);
                File.WriteAllText(sdkManifestFile2, sdkManifestContents2);
                File.WriteAllText(testProjectFile, tempProjectContents);


                string redist1 = Path.Combine(archRedist, "A.dll");
                string redist2 = Path.Combine(neutralRedist, "B.dll");
                string redist3 = Path.Combine(archCommonRedist, "C.dll");
                string redist4 = Path.Combine(neutralCommonRedist, "D.dll");
                string redist5 = Path.Combine(archRedist33, "A.dll");
                string redist6 = Path.Combine(archCommonRedist3, "B.dll");

                File.WriteAllText(redist1, "Test");
                File.WriteAllText(redist2, "Test");
                File.WriteAllText(redist3, "Test");
                File.WriteAllText(redist4, "Test");
                File.WriteAllText(redist5, "Test");
                File.WriteAllText(redist6, "Test");

                MockLogger logger = new MockLogger();

                ProjectCollection pc = new ProjectCollection();
                ProjectInstance project = pc.LoadProject(testProjectFile).CreateProjectInstance();
                project.SetProperty("SDKReferenceDirectoryRoot", testDirectoryRoot);
                project.SetProperty("SDKReferenceRegistryRoot", "");

                IDictionary<string, TargetResult> targetResults = new Dictionary<string, TargetResult>();
                bool success = project.Build(new string[] { "GetResolvedSDKReferences" }, new ILogger[] { logger }, out targetResults);
                Assert.True(success);
                Assert.True(targetResults.ContainsKey("GetResolvedSDKReferences"));
                TargetResult result = targetResults["GetResolvedSDKReferences"];
                ITaskItem[] resolvedSDKReferences = result.Items;
                Assert.Equal(2, resolvedSDKReferences.Length);

                logger = new MockLogger();
                targetResults = new Dictionary<string, TargetResult>();
                success = project.Build(new string[] { "SDKRedistOutputGroup" }, new ILogger[] { logger }, out targetResults);
                Assert.True(success);
                Assert.True(targetResults.ContainsKey("SDKRedistOutputGroup"));
                result = targetResults["SDKRedistOutputGroup"];
                ITaskItem[] SDkRedistFolders = result.Items;
                Assert.Equal(2, SDkRedistFolders.Length);
            }
            finally
            {
                Environment.SetEnvironmentVariable("MSBUILDSDKREFERENCEDIRECTORY", null);
                Environment.SetEnvironmentVariable("MSBUILDDISABLEREGISTRYFORSDKLOOKUP", null);

                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]     // No GetResolvedSDKReferences target in Unix
        public void GatherSDKOutputGroupsTargetArchitectureExists2()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "GatherSDKOutputGroupsWithFramework");
            string sdkDirectory = Path.Combine(testDirectoryRoot, "MyPlatform\\8.0\\ExtensionSDKs\\SDkWithManifest\\2.0\\");
            string archRedist = Path.Combine(sdkDirectory, "Redist\\Retail\\x86");
            string neutralRedist = Path.Combine(sdkDirectory, "Redist\\Retail\\Neutral");
            string archCommonRedist = Path.Combine(sdkDirectory, "Redist\\CommonConfiguration\\x86");
            string neutralCommonRedist = Path.Combine(sdkDirectory, "Redist\\CommonConfiguration\\Neutral");

            string sdkDirectory3 = Path.Combine(testDirectoryRoot, "MyPlatform\\8.0\\ExtensionSDKs\\FrameworkSDkWithManifest\\2.0\\");
            string archRedist3 = Path.Combine(sdkDirectory3, "Redist\\Retail\\x64");
            string archRedist33 = Path.Combine(sdkDirectory3, "Redist\\Retail\\Neutral");
            string archCommonRedist3 = Path.Combine(sdkDirectory3, "Redist\\CommonConfiguration\\x64");

            string sdkManifestContents =
            @"<FileList
                Identity = 'SDkWithManifest, Version=2.0'
                APPX ='AppxLocation'
                SDKType ='External'
                DisplayName = 'SDkWithManifest 2.0'
                CopyRedistToSubDirectory='SomeOtherRedistDirectory'>
                <File WinMD = 'SDkWithManifest.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            string sdkManifestContents2 =
          @"<FileList
                Identity = 'FrameworkSDkWithManifest, Version=2.0'
                FrameworkIdentity='FrameworkSDK'
                APPX ='AppxLocation'
                SDKType ='External'
                DisplayName = 'AnotherSDkWithManifest 2.0'
                CopyRedistToSubDirectory='SomeOtherRedistDirectory'>
                <File WinMD = 'AnotherSDkWithManifest.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            string tempProjectContents = ObjectModelHelpers.CleanupFileContents(
             @"
             <Project DefaultTargets=""ExpandSDKReferenceAssemblies"" ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""msbuildnamespace"">
                 <ItemGroup>
                  <SDKReference Include=""SDkWithManifest, Version=2.0"">
                      <TargetedSDKConfiguration>Release</TargetedSDKConfiguration>
                   </SDKReference>
                <SDKReference Include=""FrameworkSDKWithManifest, Version=2.0"">
                      <TargetedSDKArchitecture>amd64</TargetedSDKArchitecture>
                   </SDKReference>
                 </ItemGroup>
                 <PropertyGroup>
                     <Configuration>CAT</Configuration>" +
                    @"<OutputPath>" + testDirectoryRoot + "</OutputPath>" +
                    @"<TargetPlatformIdentifier>MyPlatform</TargetPlatformIdentifier> 
                    <TargetPlatformVersion>8.0</TargetPlatformVersion>
                 </PropertyGroup>
                 <Import Project=""$(MSBuildBinPath)\Microsoft.Common.targets""/>
              </Project>");

            try
            {
                Environment.SetEnvironmentVariable("MSBUILDSDKREFERENCEDIRECTORY", testDirectoryRoot);
                Environment.SetEnvironmentVariable("MSBUILDDISABLEREGISTRYFORSDKLOOKUP", "true");

                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectoryRoot);
                Directory.CreateDirectory(sdkDirectory);
                Directory.CreateDirectory(archRedist);
                Directory.CreateDirectory(neutralRedist);
                Directory.CreateDirectory(archCommonRedist);
                Directory.CreateDirectory(neutralCommonRedist);

                Directory.CreateDirectory(sdkDirectory3);
                Directory.CreateDirectory(archRedist3);
                Directory.CreateDirectory(archRedist33);
                Directory.CreateDirectory(archCommonRedist3);

                string sdkManifestFile = Path.Combine(sdkDirectory, "SDKManifest.xml");
                string sdkManifestFile2 = Path.Combine(sdkDirectory3, "SDKManifest.xml");
                string testProjectFile = Path.Combine(testDirectoryRoot, "testproject.csproj");

                File.WriteAllText(sdkManifestFile, sdkManifestContents);
                File.WriteAllText(sdkManifestFile2, sdkManifestContents2);
                File.WriteAllText(testProjectFile, tempProjectContents);


                string redist1 = Path.Combine(archRedist, "A.dll");
                string redist2 = Path.Combine(neutralRedist, "B.dll");
                string redist3 = Path.Combine(archCommonRedist, "C.dll");
                string redist4 = Path.Combine(neutralCommonRedist, "D.dll");
                string redist5 = Path.Combine(archRedist3, "D.dll");
                string redist6 = Path.Combine(archRedist33, "A.dll");
                string redist7 = Path.Combine(archCommonRedist3, "B.dll");

                File.WriteAllText(redist1, "Test");
                File.WriteAllText(redist2, "Test");
                File.WriteAllText(redist3, "Test");
                File.WriteAllText(redist4, "Test");
                File.WriteAllText(redist5, "Test");
                File.WriteAllText(redist6, "Test");
                File.WriteAllText(redist7, "Test");

                MockLogger logger = new MockLogger();

                ProjectCollection pc = new ProjectCollection();
                ProjectInstance project = pc.LoadProject(testProjectFile).CreateProjectInstance();
                project.SetProperty("SDKReferenceDirectoryRoot", testDirectoryRoot);
                project.SetProperty("SDKReferenceRegistryRoot", "");

                IDictionary<string, TargetResult> targetResults = new Dictionary<string, TargetResult>();
                bool success = project.Build(new string[] { "GetResolvedSDKReferences" }, new ILogger[] { logger }, out targetResults);
                Assert.True(success);
                Assert.True(targetResults.ContainsKey("GetResolvedSDKReferences"));
                TargetResult result = targetResults["GetResolvedSDKReferences"];
                ITaskItem[] resolvedSDKReferences = result.Items;
                Assert.Equal(2, resolvedSDKReferences.Length);

                logger = new MockLogger();
                targetResults = new Dictionary<string, TargetResult>();
                success = project.Build(new string[] { "SDKRedistOutputGroup" }, new ILogger[] { logger }, out targetResults);
                Assert.True(success);
                Assert.True(targetResults.ContainsKey("SDKRedistOutputGroup"));
                result = targetResults["SDKRedistOutputGroup"];
                ITaskItem[] SDkRedistFolders = result.Items;
                Assert.Equal(2, SDkRedistFolders.Length);
            }
            finally
            {
                Environment.SetEnvironmentVariable("MSBUILDSDKREFERENCEDIRECTORY", null);
                Environment.SetEnvironmentVariable("MSBUILDDISABLEREGISTRYFORSDKLOOKUP", null);

                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }


        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]     // No GetResolvedSDKReferences target in Unix
        public void GatherSDKOutputGroupsTargetArchitectureDoesNotExists()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "GatherSDKOutputGroupsTargetArchitectureDoesNotExists");
            string sdkDirectory = Path.Combine(testDirectoryRoot, "MyPlatform\\8.0\\ExtensionSDKs\\SDkWithManifest\\2.0\\");
            string x86Redist = Path.Combine(sdkDirectory, "Redist\\Retail\\x86");
            string neutralRedist = Path.Combine(sdkDirectory, "Redist\\Retail\\Neutral");
            string x86CommonRedist = Path.Combine(sdkDirectory, "Redist\\CommonConfiguration\\x86");
            string neutralCommonRedist = Path.Combine(sdkDirectory, "Redist\\CommonConfiguration\\Neutral");

            string sdkManifestContents =
            @"<FileList
                Identity = 'SDkWithManifest, Version=2.0'
                APPX ='AppxLocation'
                SDKType ='External'
                DisplayName = 'SDkWithManifest 2.0'>
                <File WinMD = 'SDkWithManifest.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            string tempProjectContents = ObjectModelHelpers.CleanupFileContents(
             @"
             <Project DefaultTargets=""ExpandSDKReferenceAssemblies"" ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""msbuildnamespace"">
                 <ItemGroup>
                  <SDKReference Include=""SDkWithManifest, Version=2.0"">
                      <TargetedSDKConfiguration>Release</TargetedSDKConfiguration>
                   </SDKReference>
                 </ItemGroup>
                 <PropertyGroup>
                      <Configuration>CAT</Configuration>" +
                    @"<OutputPath>" + testDirectoryRoot + "</OutputPath>" +
                    @"<TargetPlatformIdentifier>MyPlatform</TargetPlatformIdentifier> 
                    <TargetPlatformVersion>8.0</TargetPlatformVersion>
                 </PropertyGroup>
                 <Import Project=""$(MSBuildBinPath)\Microsoft.Common.targets""/>
              </Project>");

            try
            {
                Environment.SetEnvironmentVariable("MSBUILDSDKREFERENCEDIRECTORY", testDirectoryRoot);
                Environment.SetEnvironmentVariable("MSBUILDDISABLEREGISTRYFORSDKLOOKUP", "true");

                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectoryRoot);
                Directory.CreateDirectory(sdkDirectory);
                Directory.CreateDirectory(x86Redist);
                Directory.CreateDirectory(x86CommonRedist);
                Directory.CreateDirectory(neutralRedist);
                Directory.CreateDirectory(neutralCommonRedist);

                string sdkManifestFile = Path.Combine(sdkDirectory, "SDKManifest.xml");
                string testProjectFile = Path.Combine(testDirectoryRoot, "testproject.csproj");

                File.WriteAllText(sdkManifestFile, sdkManifestContents);
                File.WriteAllText(testProjectFile, tempProjectContents);


                string redist1 = Path.Combine(x86CommonRedist, "A.dll");
                string redist2 = Path.Combine(x86Redist, "B.dll");
                string redist3 = Path.Combine(neutralRedist, "C.dll");
                string redist4 = Path.Combine(neutralCommonRedist, "D.dll");

                File.WriteAllText(redist1, "Test");
                File.WriteAllText(redist2, "Test");
                File.WriteAllText(redist3, "Test");
                File.WriteAllText(redist4, "Test");

                MockLogger logger = new MockLogger();

                ProjectCollection pc = new ProjectCollection();
                ProjectInstance project = pc.LoadProject(testProjectFile).CreateProjectInstance();
                project.SetProperty("SDKReferenceDirectoryRoot", testDirectoryRoot);
                project.SetProperty("SDKReferenceRegistryRoot", "");

                IDictionary<string, TargetResult> targetResults = new Dictionary<string, TargetResult>();
                bool success = project.Build(new string[] { "GetResolvedSDKReferences" }, new ILogger[] { logger }, out targetResults);
                Assert.True(success);
                Assert.True(targetResults.ContainsKey("GetResolvedSDKReferences"));
                TargetResult result = targetResults["GetResolvedSDKReferences"];
                ITaskItem[] resolvedSDKReferences = result.Items;
                Assert.Single(resolvedSDKReferences);

                logger = new MockLogger();
                targetResults = new Dictionary<string, TargetResult>();
                success = project.Build(new string[] { "SDKRedistOutputGroup" }, new ILogger[] { logger }, out targetResults);
                Assert.True(success);
                Assert.True(targetResults.ContainsKey("SDKRedistOutputGroup"));
                result = targetResults["SDKRedistOutputGroup"];
                ITaskItem[] SDkRedistFolders = result.Items;
                Assert.Equal(2, SDkRedistFolders.Length);
            }
            finally
            {
                Environment.SetEnvironmentVariable("MSBUILDSDKREFERENCEDIRECTORY", null);
                Environment.SetEnvironmentVariable("MSBUILDDISABLEREGISTRYFORSDKLOOKUP", null);


                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]     // No GetResolvedSDKReferences target in Unix
        public void CheckDefaultingOfTargetConfigAndArchitecture()
        {
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "CheckDefaultingOfTargetConfigAndArchitecture");
            string sdkDirectory = Path.Combine(testDirectoryRoot, "MyPlatform\\8.0\\ExtensionSDKs\\SDkWithManifest\\2.0\\");
            string neutralRedist = Path.Combine(sdkDirectory, "Redist\\Retail\\Neutral");
            string neutralCommonRedist = Path.Combine(sdkDirectory, "Redist\\CommonConfiguration\\Neutral");

            string sdkManifestContents =
            @"<FileList
                Identity = 'SDkWithManifest, Version=2.0'
                APPX ='AppxLocation'
                SDKType ='External'
                DisplayName = 'SDkWithManifest 2.0'>
                <File WinMD = 'SDkWithManifest.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            string tempProjectContents = ObjectModelHelpers.CleanupFileContents(
             @"
             <Project DefaultTargets=""ExpandSDKReferenceAssemblies"" ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""msbuildnamespace"">
                 <ItemGroup>
                  <SDKReference Include=""SDkWithManifest, Version=2.0""/>
                 </ItemGroup>
                 <PropertyGroup>
                    <Configuration>CAT</Configuration>" +
                    @"<OutputPath>" + testDirectoryRoot + "</OutputPath>" +
                    @"<TargetPlatformIdentifier>MyPlatform</TargetPlatformIdentifier> 
                    <TargetPlatformVersion>8.0</TargetPlatformVersion>
                 </PropertyGroup>
                 <Import Project=""$(MSBuildBinPath)\Microsoft.Common.targets""/>
              </Project>");

            try
            {
                Environment.SetEnvironmentVariable("MSBUILDSDKREFERENCEDIRECTORY", testDirectoryRoot);
                Environment.SetEnvironmentVariable("MSBUILDDISABLEREGISTRYFORSDKLOOKUP", "true");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectoryRoot);
                Directory.CreateDirectory(sdkDirectory);
                Directory.CreateDirectory(neutralRedist);
                Directory.CreateDirectory(neutralCommonRedist);

                string sdkManifestFile = Path.Combine(sdkDirectory, "SDKManifest.xml");
                string testProjectFile = Path.Combine(testDirectoryRoot, "testproject.csproj");

                File.WriteAllText(sdkManifestFile, sdkManifestContents);
                File.WriteAllText(testProjectFile, tempProjectContents);

                string redist1 = Path.Combine(neutralRedist, "B.dll");
                string redist2 = Path.Combine(neutralCommonRedist, "C.dll");

                File.WriteAllText(redist1, "Test");
                File.WriteAllText(redist2, "Test");

                MockLogger logger = new MockLogger();

                ProjectCollection pc = new ProjectCollection();
                ProjectInstance project = pc.LoadProject(testProjectFile).CreateProjectInstance();
                project.SetProperty("SDKReferenceDirectoryRoot", testDirectoryRoot);
                project.SetProperty("SDKReferenceRegistryRoot", "");

                IDictionary<string, TargetResult> targetResults = new Dictionary<string, TargetResult>();
                bool success = project.Build(new string[] { "GetResolvedSDKReferences" }, new ILogger[] { logger }, out targetResults);
                Assert.True(success);
                Assert.True(targetResults.ContainsKey("GetResolvedSDKReferences"));
                TargetResult result = targetResults["GetResolvedSDKReferences"];
                ITaskItem[] resolvedSDKReferences = result.Items;
                Assert.Single(resolvedSDKReferences);
                Assert.Equal("Retail", resolvedSDKReferences[0].GetMetadata("TargetedSDKConfiguration"));
                Assert.Equal("Neutral", resolvedSDKReferences[0].GetMetadata("TargetedSDKArchitecture"));

                logger = new MockLogger();
                targetResults = new Dictionary<string, TargetResult>();
                success = project.Build(new string[] { "SDKRedistOutputGroup" }, new ILogger[] { logger }, out targetResults);
                Assert.True(success);
                Assert.True(targetResults.ContainsKey("SDKRedistOutputGroup"));
                result = targetResults["SDKRedistOutputGroup"];
                ITaskItem[] SDkRedistFolders = result.Items;
                Assert.Equal(2, SDkRedistFolders.Length);
            }
            finally
            {
                Environment.SetEnvironmentVariable("MSBUILDSDKREFERENCEDIRECTORY", null);
                Environment.SetEnvironmentVariable("MSBUILDDISABLEREGISTRYFORSDKLOOKUP", null);
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        [Fact]
        [PlatformSpecific(TestPlatforms.Windows)]     // No GetResolvedSDKReferences target in Unix
        public void CheckAttributesFromManifestArePassedToResolvedAssemblies()
        {
            /* \Microsoft SDKs\Windows\v8.0\ExtensionSDKs */
            string testDirectoryRoot = Path.Combine(Path.GetTempPath(), "CheckDefaultingOfTargetConfigAndArchitecture");
            string sdkDirectory = Path.Combine(testDirectoryRoot, "MyPlatform\\v8.0\\ExtensionSDKs\\SDkWithManifest\\2.0\\");
            string neutralRedist = Path.Combine(sdkDirectory, "Redist\\Retail\\Neutral");
            string neutralCommonRedist = Path.Combine(sdkDirectory, "Redist\\CommonConfiguration\\Neutral");

            string sdkManifestContents1 =
            @"<FileList
                Identity = 'SDkWithManifest, Version=2.0'
                APPX ='AppxLocation'
                SDKType ='External'
                DisplayName = 'SDkWithManifest 2.0'
                MoreInfo = 'http://msdn.microsoft.com/MySDK'
                MaxPlatformVersion = '9.0'
                MinOSVersion = '6.2.0'
                MaxOSVersionTested = '6.2.3'>
                <File WinMD = 'SDkWithManifest.Sprint, Version=8.0' />
                <File AssemblyName = 'Assembly1, Version=8.0' />
                <DependsOn Identity='Windows SDK, Version 8.0'/>
            </FileList>";

            // This is not a framework SDK because it does not have FrameworkIdentity set
            string sdkManifestContents2 = @"
                <FileList
                    DisplayName = ""My SDK""
                    ProductFamilyName = ""UnitTest SDKs""
                    MoreInfo = ""http://msdn.microsoft.com/MySDK"">

                    <File Reference = ""MySDK.Sprint.winmd"" Implementation = ""XNASprintImpl.dll"">
                        <Registration Type = ""Flipper"" Implementation = ""XNASprintFlipperImpl.dll"" />
                        <Registration Type = ""Flexer"" Implementation = ""XNASprintFlexerImpl.dll"" />
                        <ToolboxItems VSCategory = ""Toolbox.Default"" />
                    </File>
                </FileList>";



            string tempProjectContents = ObjectModelHelpers.CleanupFileContents(@"
             <Project DefaultTargets=""ExpandSDKReferenceAssemblies"" ToolsVersion=""msbuilddefaulttoolsversion"" xmlns=""msbuildnamespace"">
                 <ItemGroup>
                  <SDKReference Include=""SDkWithManifest, Version=2.0""/>
                 </ItemGroup>
                 <PropertyGroup>
                    <Configuration>CAT</Configuration>" +
                    @"<OutputPath>" + testDirectoryRoot + "</OutputPath>" +
                    @"<TargetPlatformIdentifier>MyPlatform</TargetPlatformIdentifier> 
                    <TargetPlatformVersion>8.0</TargetPlatformVersion>
                 </PropertyGroup>
                 <Import Project=""$(MSBuildBinPath)\Microsoft.Common.targets""/>
              </Project>");

            try
            {
                Environment.SetEnvironmentVariable("MSBUILDSDKREFERENCEDIRECTORY", testDirectoryRoot);
                Environment.SetEnvironmentVariable("MSBUILDDISABLEREGISTRYFORSDKLOOKUP", "true");
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }

                Directory.CreateDirectory(testDirectoryRoot);
                Directory.CreateDirectory(sdkDirectory);
                Directory.CreateDirectory(neutralRedist);
                Directory.CreateDirectory(neutralCommonRedist);

                string redist1 = Path.Combine(neutralRedist, "B.dll");
                string redist2 = Path.Combine(neutralCommonRedist, "C.dll");

                File.WriteAllText(redist1, "Test");
                File.WriteAllText(redist2, "Test");

                MockLogger logger = new MockLogger();

                string testProjectFile = Path.Combine(testDirectoryRoot, "testproject.csproj");
                File.WriteAllText(testProjectFile, tempProjectContents);

                string sdkManifestFile = Path.Combine(sdkDirectory, "SDKManifest.xml");

                File.WriteAllText(sdkManifestFile, sdkManifestContents1);
                ITaskItem[] resolvedSDKReferences1 = RunBuildAndReturnResolvedSDKReferences(logger, testProjectFile, testDirectoryRoot);
                Assert.Single(resolvedSDKReferences1);

                Assert.Equal("http://msdn.microsoft.com/MySDK", resolvedSDKReferences1[0].GetMetadata("MoreInfo"));
                Assert.Equal("9.0", resolvedSDKReferences1[0].GetMetadata("MaxPlatformVersion"));
                Assert.Equal("6.2.0", resolvedSDKReferences1[0].GetMetadata("MinOSVersion"));
                Assert.Equal("6.2.3", resolvedSDKReferences1[0].GetMetadata("MaxOSVersionTested"));

                File.WriteAllText(sdkManifestFile, sdkManifestContents2);
                ITaskItem[] resolvedSDKReferences2 = RunBuildAndReturnResolvedSDKReferences(logger, testProjectFile, testDirectoryRoot);
                Assert.Single(resolvedSDKReferences2);

                Assert.Equal("http://msdn.microsoft.com/MySDK", resolvedSDKReferences2[0].GetMetadata("MoreInfo"));
                Assert.Equal(String.Empty, resolvedSDKReferences2[0].GetMetadata("MaxPlatformVersion"));
                Assert.Equal(String.Empty, resolvedSDKReferences2[0].GetMetadata("MinOSVersion"));
                Assert.Equal(String.Empty, resolvedSDKReferences2[0].GetMetadata("MaxOSVersionTested"));
            }
            finally
            {
                Environment.SetEnvironmentVariable("MSBUILDSDKREFERENCEDIRECTORY", null);
                Environment.SetEnvironmentVariable("MSBUILDDISABLEREGISTRYFORSDKLOOKUP", null);
                if (Directory.Exists(testDirectoryRoot))
                {
                    FileUtilities.DeleteDirectoryNoThrow(testDirectoryRoot, true);
                }
            }
        }

        private ITaskItem[] RunBuildAndReturnResolvedSDKReferences(ILogger logger, string testProjectFile, string testDirectoryRoot)
        {
            ProjectCollection pc = new ProjectCollection();
            ProjectInstance project = pc.LoadProject(testProjectFile).CreateProjectInstance();
            project.SetProperty("SDKReferenceDirectoryRoot", testDirectoryRoot);
            project.SetProperty("SDKReferenceRegistryRoot", "");

            IDictionary<string, TargetResult> targetResults = new Dictionary<string, TargetResult>();
            bool success = project.Build(new string[] { "GetResolvedSDKReferences" }, new ILogger[] { logger }, out targetResults);
            Assert.True(success);

            Assert.True(targetResults.ContainsKey("GetResolvedSDKReferences"));
            TargetResult result = targetResults["GetResolvedSDKReferences"];
            return result.Items;
        }
    }
}


<|start_filename|>src/Xunit.NetCore.Extensions/Discoverers/ConditionalTestDiscoverer.cs<|end_filename|>
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Xunit.Abstractions;
using Xunit.Sdk;

namespace Xunit.NetCore.Extensions
{
    // Internal helper class for code common to conditional test discovery through
    // [ConditionalFact] and [ConditionalTheory]
    internal class ConditionalTestDiscoverer
    {
        // This helper method evaluates the given condition member names for a given set of test cases.
        // If any condition member evaluates to 'false', the test cases are marked to be skipped.
        // The skip reason is the collection of all the condition members that evalated to 'false'.
        internal static IEnumerable<IXunitTestCase> Discover(
                                                        ITestFrameworkDiscoveryOptions discoveryOptions,
                                                        IMessageSink diagnosticMessageSink,
                                                        ITestMethod testMethod,
                                                        IEnumerable<IXunitTestCase> testCases,
                                                        object[] conditionArguments)
        {
            // A null or empty list of conditionMemberNames is treated as "no conditions".
            // and the test cases will not be skipped.
            // Example: [ConditionalFact()]
            if (conditionArguments == null || conditionArguments.Length == 0)
            {
                return testCases;
            }

            string [] conditionMemberNames;

            Type calleeType = conditionArguments[0] as Type;
            if (calleeType != null)
            {
                if (conditionArguments.Length < 2)
                {
                    // [ConditionalFact(typeof(x))] no provided methods.
                    return testCases;
                }

                // [ConditionalFact(typeof(x), "MethodName")]
                conditionMemberNames = conditionArguments[1] as string[];
            }
            else
            {
                // [ConditionalFact("MethodName")]
                conditionMemberNames = conditionArguments[0] as string[];
            }

            // [ConditionalFact((string[]) null)]
            int conditionCount = conditionMemberNames == null ? 0 : conditionMemberNames.Count();
            if (conditionCount == 0)
            {
                return testCases;
            }

            MethodInfo testMethodInfo = testMethod.Method.ToRuntimeMethod();
            Type testMethodDeclaringType = testMethodInfo.DeclaringType;
            List<string> falseConditions = new List<string>(conditionCount);

            foreach (string entry in conditionMemberNames)
            {
                string conditionMemberName = entry;

                // Null condition member names are silently tolerated
                if (string.IsNullOrWhiteSpace(conditionMemberName))
                {
                    continue;
                }

                Type declaringType;

                if (calleeType != null)
                {
                    declaringType = calleeType;
                }
                else
                {
                    declaringType = testMethodDeclaringType;

                    string[] symbols = conditionMemberName.Split('.');
                    if (symbols.Length == 2)
                    {
                        conditionMemberName = symbols[1];
                        ITypeInfo type = testMethod.TestClass.Class.Assembly.GetTypes(false).Where(t => t.Name.Contains(symbols[0])).FirstOrDefault();
                        if (type != null)
                        {
                            declaringType = type.ToRuntimeType();
                        }
                    }
                }

                MethodInfo conditionMethodInfo;
                if ((conditionMethodInfo = LookupConditionalMethod(declaringType, conditionMemberName)) == null)
                {
                    return new[] 
                    {
                        new ExecutionErrorTestCase(
                            diagnosticMessageSink,
                            discoveryOptions.MethodDisplayOrDefault(),
                            TestMethodDisplayOptions.None,
                            testMethod,
                            GetFailedLookupString(conditionMemberName, declaringType))
                    };
                }

                // In the case of multiple conditions, collect the results of all
                // of them to produce a summary skip reason.
                try
                {
                    if (!(bool)conditionMethodInfo.Invoke(null, null))
                    {
                        falseConditions.Add(conditionMemberName);
                    }
                }
                catch (Exception exc)
                {
                    falseConditions.Add($"{conditionMemberName} ({exc.GetType().Name})");
                }
            }

            // Compose a summary of all conditions that returned false.
            if (falseConditions.Count > 0)
            {
                string skippedReason = string.Format("Condition(s) not met: \"{0}\"", string.Join("\", \"", falseConditions));
                return testCases.Select(tc => new SkippedTestCase(tc, skippedReason));
            }

            // No conditions returned false (including the absence of any conditions).
            return testCases;
        }

        internal static string GetFailedLookupString(string name, Type type)
        {
            return
                $"An appropriate member '{name}' could not be found. " +
                $"The conditional method needs to be a static method or property on the type {type} or any ancestor, " +
                "of any visibility, accepting zero arguments, and having a return type of Boolean.";
        }
        
        internal static MethodInfo LookupConditionalMethod(Type t, string name)
        {
            if (t == null || name == null)
                return null;

            TypeInfo ti = t.GetTypeInfo();

            MethodInfo mi = ti.GetDeclaredMethod(name);
            if (mi?.IsStatic == true && mi.GetParameters().Length == 0 && mi.ReturnType == typeof(bool))
                return mi;

            PropertyInfo pi = ti.GetDeclaredProperty(name);
            if (pi?.PropertyType == typeof(bool) && pi.GetMethod?.IsStatic == true && pi.GetMethod.GetParameters().Length == 0)
                return pi.GetMethod;

            return LookupConditionalMethod(ti.BaseType, name);
        }
    }
}


<|start_filename|>src/Framework/XamlTypes/ItemType.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.ComponentModel;

namespace Microsoft.Build.Framework.XamlTypes
{
    /// <summary>
    /// Used to deserialize the item type information 
    /// </summary>
    public sealed class ItemType : ISupportInitialize, IProjectSchemaNode
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public ItemType()
        {
            // by default it is included in up-to-date check
            UpToDateCheckInput = true;
        }

        /// <summary>
        /// serializes IItemType.Name
        /// </summary>
        public string Name
        {
            get;
            set;
        }

        /// <summary>
        /// serializes IItemType.DisplayName
        /// </summary>
        [Localizable(true)]
        public string DisplayName
        {
            get;
            set;
        }

        /// <summary>
        /// serializes IItemType.ItemType
        /// </summary>
        public string DefaultContentType
        {
            get;
            set;
        }

        /// <summary>
        /// serializes IItemType.UpToDateCheckInput
        /// </summary>
        public bool UpToDateCheckInput
        {
            get;
            set;
        }

        #region ISupportInitialize Members

        /// <summary>
        /// See ISupportInitialize.
        /// </summary>
        public void BeginInit()
        {
        }

        /// <summary>
        /// See ISupportInitialize.
        /// </summary>
        public void EndInit()
        {
        }

        #endregion

        #region IProjectSchemaNode Members
        /// <summary>
        /// see IProjectSchemaNode
        /// </summary>
        public IEnumerable<Type> GetSchemaObjectTypes()
        {
            yield return typeof(ItemType);
        }

        /// <summary>
        /// see IProjectSchemaNode
        /// </summary>
        public IEnumerable<object> GetSchemaObjects(Type type)
        {
            if (type == typeof(ItemType))
            {
                yield return this;
            }
        }
        #endregion
    }
}


<|start_filename|>src/Build.UnitTests/TargetsFile_Test.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.IO;

using Microsoft.Build.Shared;
using Microsoft.Build.Evaluation;
using Xunit;

namespace Microsoft.Build.UnitTests
{
    /// <summary>
    /// Tests from Orcas
    /// </summary>
    sealed public class TargetsFile_Test
    {
#if FEATURE_COMPILE_IN_TESTS
        /// <summary>
        /// Check that the ARM flag is passed to the compiler when targeting ARM.
        /// </summary>
        [Fact]
        public void TargetARM()
        {
            string file = null;
            string outputPath = Path.GetTempPath() + "\\" + Guid.NewGuid().ToString("N");

            try
            {
                file = Helpers.CreateFiles("class1.cs")[0];

                MockLogger logger = new MockLogger();

                Project project = ObjectModelHelpers.CreateInMemoryProject(
                    @"
                   <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>" + outputPath + @"</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>Library</OutputType>
                        <Configuration>Debug</Configuration>
                        <PlatformTarget>arm</PlatformTarget>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`" + file + @"` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` />
                    </Project>
                ",
                 logger
                 );

                project.Build();

                logger.AssertLogContains(" /platform:arm ");
            }
            finally
            {
                if (file != null)
                {
                    File.Delete(file);
                }

                ObjectModelHelpers.DeleteDirectory(outputPath);
            }
        }

        #region 32bit preferred

        /// <summary>
        /// Check that with an empty platformtarget (equivalent to anycpu), library type assemblies do not 
        /// get forced to anycpu32bitpreferred by default. 
        /// </summary>
        [Fact]
        public void AnyCPULibraryProjectIsNot32BitPreferred()
        {
            string file = null;
            string outputPath = Path.GetTempPath() + "\\" + Guid.NewGuid().ToString("N");

            try
            {
                file = Helpers.CreateFiles("class1.cs")[0];

                MockLogger logger = new MockLogger();

                Project project = ObjectModelHelpers.CreateInMemoryProject(
                    @"
                   <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>" + outputPath + @"</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>Library</OutputType>
                        <Configuration>Debug</Configuration>
                        <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`" + file + @"` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` />
                    </Project>
                ",
                 logger
                 );

                project.Build();

                logger.AssertLogDoesntContain(" /platform:");
            }
            finally
            {
                if (file != null)
                {
                    File.Delete(file);
                }

                ObjectModelHelpers.DeleteDirectory(outputPath);
            }
        }

        /// <summary>
        /// Check that with an explicit platform of anycpu, library type assemblies do not 
        /// get forced to anycpu32bitpreferred by default. 
        /// </summary>
        [Fact]
        public void ExplicitAnyCPULibraryProjectIsNot32BitPreferred()
        {
            string file = null;
            string outputPath = Path.GetTempPath() + "\\" + Guid.NewGuid().ToString("N");

            try
            {
                file = Helpers.CreateFiles("class1.cs")[0];

                MockLogger logger = new MockLogger();

                Project project = ObjectModelHelpers.CreateInMemoryProject(
                    @"
                   <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>" + outputPath + @"</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>Library</OutputType>
                        <Configuration>Debug</Configuration>
                        <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
                        <PlatformTarget>AnyCPU</PlatformTarget>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`" + file + @"` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` />
                    </Project>
                ",
                 logger
                 );

                project.Build();

                logger.AssertLogContains(" /platform:AnyCPU ");
            }
            finally
            {
                if (file != null)
                {
                    File.Delete(file);
                }

                ObjectModelHelpers.DeleteDirectory(outputPath);
            }
        }

        /// <summary>
        /// Check that with an empty platformtarget (equivalent to anycpu), winmdobj type assemblies do not 
        /// get forced to anycpu32bitpreferred by default. 
        /// </summary>
        [Fact]
        public void AnyCPUWinMDObjProjectIsNot32BitPreferred()
        {
            string file = null;
            string outputPath = Path.GetTempPath() + "\\" + Guid.NewGuid().ToString("N");

            try
            {
                file = Helpers.CreateFiles("class1.cs")[0];

                MockLogger logger = new MockLogger();

                Project project = ObjectModelHelpers.CreateInMemoryProject(
                    @"
                   <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>" + outputPath + @"</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>winmdobj</OutputType>
                        <Configuration>Debug</Configuration>
                      </PropertyGroup>
                      <!-- For dealing with the case where the Jupiter targets do not exist, in order to follow the appropriate codepaths in the standard managed
                           we need to be .NET 4.5 or greater -->
                      <PropertyGroup Condition=`!Exists('$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets')`>
                        <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`" + file + @"` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets` Condition=`Exists('$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets')` />
                      <!-- Fall back to CSharp targets for the sake of this test if the Jupiter targets don't exist, since what we're testing can be equally well resolved by either -->
                      <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` Condition=`!Exists('$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets')` />
                   </Project>
                ",
                 logger
                 );

                project.Build();

                logger.AssertLogDoesntContain(" /platform:");
            }
            finally
            {
                if (file != null)
                {
                    File.Delete(file);
                }

                ObjectModelHelpers.DeleteDirectory(outputPath);
            }
        }

        /// <summary>
        /// Check that with an explicit platformtarget of anycpu, winmdobj type assemblies do not 
        /// get forced to anycpu32bitpreferred by default. 
        /// </summary>
        [Fact]
        public void ExplicitAnyCPUWinMDObjProjectIsNot32BitPreferred()
        {
            string file = null;
            string outputPath = Path.GetTempPath() + "\\" + Guid.NewGuid().ToString("N");

            try
            {
                file = Helpers.CreateFiles("class1.cs")[0];

                MockLogger logger = new MockLogger();

                Project project = ObjectModelHelpers.CreateInMemoryProject(
                    @"
                   <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>" + outputPath + @"</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>winmdobj</OutputType>
                        <Configuration>Debug</Configuration>
                        <PlatformTarget>AnyCPU</PlatformTarget>
                      </PropertyGroup>
                      <!-- For dealing with the case where the Jupiter targets do not exist, in order to follow the appropriate codepaths in the standard managed
                           we need to be .NET 4.5 or greater -->
                      <PropertyGroup Condition=`!Exists('$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets')`>
                        <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`" + file + @"` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets` Condition=`Exists('$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets')` />
                      <!-- Fall back to CSharp targets for the sake of this test if the Jupiter targets don't exist, since what we're testing can be equally well resolved by either -->
                      <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` Condition=`!Exists('$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets')` />
                   </Project>
                ",
                 logger
                 );

                project.Build();

                logger.AssertLogContains(" /platform:AnyCPU ");
            }
            finally
            {
                if (file != null)
                {
                    File.Delete(file);
                }

                ObjectModelHelpers.DeleteDirectory(outputPath);
            }
        }

        /// <summary>
        /// Check that with an empty platformtarget (equivalent to anycpu), exe type assemblies 
        /// get forced to anycpu32bitpreferred by default. 
        /// </summary>
        [Fact]
        public void AnyCPUExeProjectIs32BitPreferred()
        {
            string file = null;
            string outputPath = Path.GetTempPath() + "\\" + Guid.NewGuid().ToString("N");

            try
            {
                file = Helpers.CreateFiles("class1.cs")[0];

                MockLogger logger = new MockLogger();

                Project project = ObjectModelHelpers.CreateInMemoryProject(
                    @"
                   <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>" + outputPath + @"</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>Exe</OutputType>
                        <Configuration>Debug</Configuration>
                        <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`" + file + @"` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` />
                    </Project>
                ",
                 logger
                 );

                project.Build();

                logger.AssertLogContains(" /platform:anycpu32bitpreferred ");
            }
            finally
            {
                if (file != null)
                {
                    File.Delete(file);
                }

                ObjectModelHelpers.DeleteDirectory(outputPath);
            }
        }

        /// <summary>
        /// Check that with an explicit platformtarget of anycpu, exe type assemblies 
        /// get forced to anycpu32bitpreferred by default. 
        /// </summary>
        [Fact]
        public void ExplicitAnyCPUExeProjectIs32BitPreferred()
        {
            string file = null;
            string outputPath = Path.GetTempPath() + "\\" + Guid.NewGuid().ToString("N");

            try
            {
                file = Helpers.CreateFiles("class1.cs")[0];

                MockLogger logger = new MockLogger();

                Project project = ObjectModelHelpers.CreateInMemoryProject(
                    @"
                   <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>" + outputPath + @"</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>Exe</OutputType>
                        <Configuration>Debug</Configuration>
                        <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
                        <PlatformTarget>AnyCPU</PlatformTarget>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`" + file + @"` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` />
                    </Project>
                ",
                 logger
                 );

                project.Build();

                logger.AssertLogContains(" /platform:anycpu32bitpreferred ");
            }
            finally
            {
                if (file != null)
                {
                    File.Delete(file);
                }

                ObjectModelHelpers.DeleteDirectory(outputPath);
            }
        }

        /// <summary>
        /// Check that with an empty platformtarget (equivalent to anycpu), exe type assemblies 
        /// that are targeting .NET 4.0 do not get forced to anycpu32bitpreferred by default. 
        /// </summary>
        [Fact]
        public void AnyCPU40ExeProjectIsNot32BitPreferred()
        {
            string file = null;
            string outputPath = Path.GetTempPath() + "\\" + Guid.NewGuid().ToString("N");

            try
            {
                file = Helpers.CreateFiles("class1.cs")[0];

                MockLogger logger = new MockLogger();

                Project project = ObjectModelHelpers.CreateInMemoryProject(
                    @"
                   <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>" + outputPath + @"</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>Exe</OutputType>
                        <Configuration>Debug</Configuration>
                        <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`" + file + @"` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` />
                    </Project>
                ",
                 logger
                 );

                project.Build();

                logger.AssertLogDoesntContain(" /platform:");
            }
            finally
            {
                if (file != null)
                {
                    File.Delete(file);
                }

                ObjectModelHelpers.DeleteDirectory(outputPath);
            }
        }

        /// <summary>
        /// Check that with an explicit platformtarget of anycpu, exe type assemblies that are 
        /// targeting .NET 4.0 do not get forced to anycpu32bitpreferred by default. 
        /// </summary>
        [Fact]
        public void ExplicitAnyCPU40ExeProjectIsNot32BitPreferred()
        {
            string file = null;
            string outputPath = Path.GetTempPath() + "\\" + Guid.NewGuid().ToString("N");

            try
            {
                file = Helpers.CreateFiles("class1.cs")[0];

                MockLogger logger = new MockLogger();

                Project project = ObjectModelHelpers.CreateInMemoryProject(
                    @"
                   <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>" + outputPath + @"</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>Exe</OutputType>
                        <Configuration>Debug</Configuration>
                        <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
                        <PlatformTarget>AnyCPU</PlatformTarget>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`" + file + @"` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` />
                    </Project>
                ",
                 logger
                 );

                project.Build();

                logger.AssertLogContains(" /platform:AnyCPU ");
            }
            finally
            {
                if (file != null)
                {
                    File.Delete(file);
                }

                ObjectModelHelpers.DeleteDirectory(outputPath);
            }
        }

        /// <summary>
        /// Check that with an empty platformtarget (equivalent to anycpu), appcontainerexe type assemblies 
        /// get forced to anycpu32bitpreferred by default. 
        /// </summary>
        [Fact]
        public void AnyCPUAppContainerExeProjectIs32BitPreferred()
        {
            string file = null;
            string outputPath = Path.GetTempPath() + "\\" + Guid.NewGuid().ToString("N");

            try
            {
                file = Helpers.CreateFiles("class1.cs")[0];

                MockLogger logger = new MockLogger();

                Project project = ObjectModelHelpers.CreateInMemoryProject(
                    @"
                   <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>" + outputPath + @"</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>AppContainerExe</OutputType>
                        <Configuration>Debug</Configuration>
                      </PropertyGroup>
                      <!-- For dealing with the case where the Jupiter targets do not exist, in order to follow the appropriate codepaths in the standard managed
                           we need to be .NET 4.5 or greater -->
                      <PropertyGroup Condition=`!Exists('$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets')`>
                        <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`" + file + @"` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets` Condition=`Exists('$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets')` />
                      <!-- Fall back to CSharp targets for the sake of this test if the Jupiter targets don't exist, since what we're testing can be equally well resolved by either -->
                      <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` Condition=`!Exists('$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets')` />
                   </Project>
                ",
                 logger
                 );

                project.Build();

                logger.AssertLogContains(" /platform:anycpu32bitpreferred");
            }
            finally
            {
                if (file != null)
                {
                    File.Delete(file);
                }

                ObjectModelHelpers.DeleteDirectory(outputPath);
            }
        }

        /// <summary>
        /// Check that with an explicit platformtarget of anycpu, appcontainerexe type assemblies 
        /// get forced to anycpu32bitpreferred by default. 
        /// </summary>
        [Fact]
        public void ExplicitAnyCPUAppContainerExeProjectIs32BitPreferred()
        {
            string file = null;
            string outputPath = Path.GetTempPath() + "\\" + Guid.NewGuid().ToString("N");

            try
            {
                file = Helpers.CreateFiles("class1.cs")[0];

                MockLogger logger = new MockLogger();

                Project project = ObjectModelHelpers.CreateInMemoryProject(
                    @"
                   <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>" + outputPath + @"</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>AppContainerExe</OutputType>
                        <Configuration>Debug</Configuration>
                        <PlatformTarget>AnyCPU</PlatformTarget>
                      </PropertyGroup>
                      <!-- For dealing with the case where the Jupiter targets do not exist, in order to follow the appropriate codepaths in the standard managed
                           we need to be .NET 4.5 or greater -->
                      <PropertyGroup Condition=`!Exists('$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets')`>
                        <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`" + file + @"` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets` Condition=`Exists('$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets')` />
                      <!-- Fall back to CSharp targets for the sake of this test if the Jupiter targets don't exist, since what we're testing can be equally well resolved by either -->
                      <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` Condition=`!Exists('$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets')` />
                   </Project>
                ",
                 logger
                 );

                project.Build();

                logger.AssertLogContains(" /platform:anycpu32bitpreferred");
            }
            finally
            {
                if (file != null)
                {
                    File.Delete(file);
                }

                ObjectModelHelpers.DeleteDirectory(outputPath);
            }
        }

        /// <summary>
        /// Although AnyCPU library projects should not default to AnyCPU32BitPreferred, because that platform is 
        /// not supported for library projects, if Prefer32Bit is explicitly set, we should still respect that. 
        /// </summary>
        [Fact]
        public void AnyCPULibraryProjectIs32BitPreferredIfPrefer32BitSet()
        {
            string file = null;
            string outputPath = Path.GetTempPath() + "\\" + Guid.NewGuid().ToString("N");

            try
            {
                file = Helpers.CreateFiles("class1.cs")[0];

                MockLogger logger = new MockLogger();

                Project project = ObjectModelHelpers.CreateInMemoryProject(
                    @"
                   <Project DefaultTargets=`Build` ToolsVersion=`Current` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>" + outputPath + @"</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>Library</OutputType>
                        <Configuration>Debug</Configuration>
                        <PlatformTarget>AnyCPU</PlatformTarget>
                        <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
                        <Prefer32Bit>true</Prefer32Bit>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`" + file + @"` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` />
                   </Project>
                ",
                 logger
                 );

                project.Build();

                logger.AssertLogContains(" /platform:anycpu32bitpreferred");
            }
            finally
            {
                if (file != null)
                {
                    File.Delete(file);
                }

                ObjectModelHelpers.DeleteDirectory(outputPath);
            }
        }

        /// <summary>
        /// A project with no explicit OutputType will end up defaulting its OutputType to exe, 
        /// so it should also default to Prefer32Bit = true. 
        /// </summary>
        [Fact]
        public void AnyCPUProjectWithNoExplicitOutputTypeIs32BitPreferred()
        {
            string file = null;
            string outputPath = Path.GetTempPath() + "\\" + Guid.NewGuid().ToString("N");

            try
            {
                file = Helpers.CreateFiles("class1.cs")[0];

                MockLogger logger = new MockLogger();

                Project project = ObjectModelHelpers.CreateInMemoryProject(
                    @"
                   <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>" + outputPath + @"</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <Configuration>Debug</Configuration>
                        <PlatformTarget>AnyCPU</PlatformTarget>
                        <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`" + file + @"` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` />
                   </Project>
                ",
                 logger
                 );

                project.Build();

                logger.AssertLogContains(" /platform:anycpu32bitpreferred");
            }
            finally
            {
                if (file != null)
                {
                    File.Delete(file);
                }

                ObjectModelHelpers.DeleteDirectory(outputPath);
            }
        }

        /// <summary>
        /// A project with no explicit OutputType will end up defaulting its OutputType to exe, 
        /// so it should also default to Prefer32Bit = true. 
        /// </summary>
        [Fact]
        public void AnyCPUJupiterProjectWithNoExplicitOutputTypeIs32BitPreferred()
        {
            string file = null;
            string outputPath = Path.GetTempPath() + "\\" + Guid.NewGuid().ToString("N");

            try
            {
                file = Helpers.CreateFiles("class1.cs")[0];

                MockLogger logger = new MockLogger();

                Project project = ObjectModelHelpers.CreateInMemoryProject(
                    @"
                   <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>" + outputPath + @"</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <Configuration>Debug</Configuration>
                        <PlatformTarget>AnyCPU</PlatformTarget>
                        <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`" + file + @"` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets` Condition=`Exists('$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets')` />
                      <!-- Fall back to CSharp targets for the sake of this test if the Jupiter targets don't exist, since what we're testing can be equally well resolved by either -->
                      <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` Condition=`!Exists('$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v1.0\Microsoft.Windows.UI.Xaml.CSharp.targets')` />
                   </Project>
                ",
                 logger
                 );

                project.Build();

                logger.AssertLogContains(" /platform:anycpu32bitpreferred");
            }
            finally
            {
                if (file != null)
                {
                    File.Delete(file);
                }

                ObjectModelHelpers.DeleteDirectory(outputPath);
            }
        }
        #endregion 32bit preferred

        /// <summary>
        /// Validate that the GetFrameworkPaths target 
        /// </summary>
        [Fact]
        public void TestGetFrameworkPaths()
        {
            MockLogger logger = new MockLogger();

            Project project = ObjectModelHelpers.CreateInMemoryProject(
                @"
<Project ToolsVersion=`msbuilddefaulttoolsversion` DefaultTargets=`GetPaths` xmlns=`msbuildnamespace`>
  <Target Name=`GetPaths` DependsOnTargets=`GetFrameworkPaths`>
    <Message Text=`Framework 4.0 = @(_TargetFramework40DirectoryItem)` Importance=`High`/>
    <Message Text=`Framework 3.5 = @(_TargetFramework35DirectoryItem)` Importance=`High`/>
    <Message Text=`Framework 3.0 = @(_TargetFramework30DirectoryItem)` Importance=`High`/>
    <Message Text=`Framework 2.0 = @(_TargetFramework20DirectoryItem)` Importance=`High`/>
  </Target>
  <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` />
</Project>",
             logger
             );

            project.Build();

            logger.AssertLogContains(false/* not case sensitive */, "Framework 4.0 = " + FrameworkLocationHelper.PathToDotNetFrameworkV40);

            // Only check .NET 3.5 and below if they're actually on the box.
            if (FrameworkLocationHelper.PathToDotNetFrameworkV35 != null)
            {
                logger.AssertLogContains(false/* not case sensitive */, "Framework 3.5 = " + FrameworkLocationHelper.PathToDotNetFrameworkV35);
                logger.AssertLogContains(false/* not case sensitive */, "Framework 3.0 = " + FrameworkLocationHelper.PathToDotNetFrameworkV30);
                logger.AssertLogContains(false/* not case sensitive */, "Framework 2.0 = " + FrameworkLocationHelper.PathToDotNetFrameworkV20);
            }
        }

        /// <summary>
        /// Validate that the GetFrameworkPaths target 
        /// </summary>
        [Fact]
        public void TestTargetFrameworkPaths()
        {
            string[] targetFrameworkVersions = { "v2.0", "v3.0", "v3.5", "v4.0", "v4.5", "" };
            foreach (var version in targetFrameworkVersions)
            {
                MockLogger logger = new MockLogger();
                string projString = ObjectModelHelpers.CleanupFileContents(
                    @"
<Project ToolsVersion=`msbuilddefaulttoolsversion` DefaultTargets=`GetPaths` xmlns=`msbuildnamespace`>
  <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` />
  <Target
      Name='GetPaths'
      DependsOnTargets='GetFrameworkPaths'>
    <Message Text='Target Framework Folder = @(_TargetedFrameworkDirectoryItem)' />
  </Target>
</Project>"
                   );
                Project project = ObjectModelHelpers.CreateInMemoryProject(
                 projString,
                 logger
                 );

                project.SetProperty("TargetFrameworkVersion", version);
                project.Build();

                string targetFrameworkVersion = project.GetPropertyValue("TargetFrameworkVersion");
                string msbuildFrameworkToolsRoot = project.GetPropertyValue("MSBuildFrameworkToolsRoot");

                if (targetFrameworkVersion.Equals("v2.0"))
                {
                    if (FrameworkLocationHelper.PathToDotNetFrameworkV20 != null)
                    {
                        logger.AssertLogContains(false/* not case sensitive */, "Target Framework Folder = " + FrameworkLocationHelper.PathToDotNetFrameworkV20);
                    }
                    else
                    {
                        // If Framework v2.0 isn't present we use the hard coded version for this validation
                        logger.AssertLogContains(false/* not case sensitive */, "Target Framework Folder = " + msbuildFrameworkToolsRoot + "v2.0.50727");
                    }
                }
                else if (targetFrameworkVersion.Equals("v3.0") || targetFrameworkVersion.Equals("v3.5"))
                {
                    logger.AssertLogContains(false/* not case sensitive */, "Target Framework Folder = " + msbuildFrameworkToolsRoot + "\\" + targetFrameworkVersion);
                }
                else if (targetFrameworkVersion.Equals("v4.0"))
                {
                    logger.AssertLogContains(false/* not case sensitive */, "Target Framework Folder = " + FrameworkLocationHelper.PathToDotNetFrameworkV40);
                }
                else if (targetFrameworkVersion.Equals("v4.5"))
                {
                    logger.AssertLogContains(false/* not case sensitive */, "Target Framework Folder = " + FrameworkLocationHelper.PathToDotNetFrameworkV45);
                }
                else if (String.IsNullOrEmpty(targetFrameworkVersion))
                {
                    logger.AssertLogContains(false/* not case sensitive */, "Target Framework Folder = " + FrameworkLocationHelper.PathToDotNetFrameworkV45);
                }
            }
        }

        #region AssignLinkMetadata targets tests

        /// <summary>
        /// Doesn't synthesize Link metadata if the items are defined in the project  
        /// </summary>
        [Fact]
        public void NoLinkMetadataSynthesisWhenDefinedInProject()
        {
            string[] files = null;
            string outputPath = Path.Combine(Path.GetTempPath(),Guid.NewGuid().ToString("N"));

            try
            {
                files = Helpers.CreateFiles("class1.cs", "File1.txt", "Content1.foo");

                MockLogger logger = new MockLogger();

                Project project = ObjectModelHelpers.CreateInMemoryProject(
                    @"
                   <Project DefaultTargets=`Build` ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>" + outputPath + @"</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>Library</OutputType>
                        <Configuration>Debug</Configuration>
                        <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
                        <SynthesizeLinkMetadata>true</SynthesizeLinkMetadata>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`" + files[0] + @"` />
                        <None Include=`" + files[1] + @"` />
                        <Content Include=`" + files[2] + @"` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` />
                      <Target Name=`AfterBuild`>
                        <Message Text=`%(Compile.Identity): [%(Compile.Link)]` />
                        <Message Text=`%(None.Identity): [%(None.Link)]` />
                        <Message Text=`%(Content.Identity): [%(Content.Link)]` />
                      </Target>
                    </Project>
                ",
                 logger
                 );

                project.Build();

                logger.AssertLogContains(String.Format("{0}: []", files[0]));
                logger.AssertLogContains(String.Format("{0}: []", files[1]));
                logger.AssertLogContains(String.Format("{0}: []", files[2]));
            }
            finally
            {
                if (files != null)
                {
                    foreach (string file in files)
                    {
                        File.Delete(file);
                    }
                }

                ObjectModelHelpers.DeleteDirectory(outputPath);
            }
        }

        /// <summary>
        /// Synthesizes Link metadata if the items are defined in an import and are on the whitelist
        /// </summary>
        [Fact]
        public void SynthesizeLinkMetadataForItemsOnWhitelist()
        {
            string outputPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
            string directoryToDelete = null;

            try
            {
                string[] files = Helpers.CreateFiles("class1.cs", "File1.txt", "Content1.foo", "a.proj");

                directoryToDelete = Path.GetDirectoryName(files[0]);
                string subProjectDirectory = Path.Combine(Path.GetDirectoryName(files[0]), "SubFolder");
                Directory.CreateDirectory(subProjectDirectory);

                string classPath = Path.Combine(subProjectDirectory, "Class1.cs");
                string textFilePath = Path.Combine(subProjectDirectory, "File1.txt");
                string contentPath = Path.Combine(subProjectDirectory, "Content1.foo");

                File.Move(files[0], classPath);
                File.Move(files[1], textFilePath);
                File.Move(files[2], contentPath);

                string sharedFilesProjectContents =
                            @"<Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
                              <ItemGroup>
                                <Compile Include=`" + classPath + @"` />
                                <None Include=`" + textFilePath + @"` />
                                <Content Include=`" + contentPath + @"` />
                              </ItemGroup>
                           </Project>";

                File.WriteAllText(files[3], ObjectModelHelpers.CleanupFileContents(sharedFilesProjectContents));

                MockLogger logger = new MockLogger();

                Project project = ObjectModelHelpers.CreateInMemoryProject(
                    @"
                   <Project DefaultTargets=`Build` ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>" + outputPath + @"</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>Library</OutputType>
                        <Configuration>Debug</Configuration>
                        <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
                        <SynthesizeLinkMetadata>true</SynthesizeLinkMetadata>
                      </PropertyGroup>
                      <Import Project=`" + files[3] + @"` />
                      <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` />
                      <Target Name=`AfterBuild`>
                        <Message Text=`%(Compile.Identity): [%(Compile.Link)]` />
                        <Message Text=`%(None.Identity): [%(None.Link)]` />
                        <Message Text=`%(Content.Identity): [%(Content.Link)]` />
                      </Target>
                    </Project>
                ",
                 logger
                 );

                project.Build();

                logger.AssertLogContains(String.Format(@"{0}: []", classPath));
                logger.AssertLogContains(String.Format(@"{0}: [SubFolder" + Path.DirectorySeparatorChar + "File1.txt]", textFilePath));
                logger.AssertLogContains(String.Format(@"{0}: [SubFolder" + Path.DirectorySeparatorChar + "Content1.foo]", contentPath));
            }
            finally
            {
                if (directoryToDelete != null)
                {
                    ObjectModelHelpers.DeleteDirectory(directoryToDelete);
                }

                ObjectModelHelpers.DeleteDirectory(outputPath);
            }
        }

        /// <summary>
        /// Don't synthesize link metadata if the SynthesizeLinkMetadata property is false
        /// </summary>
        [Fact]
        public void DontSynthesizeLinkMetadataIfPropertyNotSet()
        {
            string outputPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
            string directoryToDelete = null;

            try
            {
                string[] files = Helpers.CreateFiles("class1.cs", "File1.txt", "Content1.foo", "a.proj");

                directoryToDelete = Path.GetDirectoryName(files[0]);
                string subProjectDirectory = Path.Combine(Path.GetDirectoryName(files[0]), "SubFolder");
                Directory.CreateDirectory(subProjectDirectory);

                string classPath = Path.Combine(subProjectDirectory, "Class1.cs");
                string textFilePath = Path.Combine(subProjectDirectory, "File1.txt");
                string contentPath = Path.Combine(subProjectDirectory, "Content1.foo");

                File.Move(files[0], classPath);
                File.Move(files[1], textFilePath);
                File.Move(files[2], contentPath);

                string sharedFilesProjectContents =
                         @"<Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
                              <ItemGroup>
                                <Compile Include=`" + classPath + @"` />
                                <None Include=`" + textFilePath + @"` />
                                <Content Include=`" + contentPath + @"` />
                              </ItemGroup>
                           </Project>";

                File.WriteAllText(files[3], ObjectModelHelpers.CleanupFileContents(sharedFilesProjectContents));

                MockLogger logger = new MockLogger();

                Project project = ObjectModelHelpers.CreateInMemoryProject(
                    @"
                   <Project DefaultTargets=`Build` ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>" + outputPath + @"</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>Library</OutputType>
                        <Configuration>Debug</Configuration>
                        <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
                        <SynthesizeLinkMetadata>false</SynthesizeLinkMetadata>
                      </PropertyGroup>
                      <Import Project=`" + files[3] + @"` />
                      <Import Project=`$(MSBuildToolsPath)\Microsoft.CSharp.targets` />
                      <Target Name=`AfterBuild`>
                        <Message Text=`%(Compile.Identity): [%(Compile.Link)]` />
                        <Message Text=`%(None.Identity): [%(None.Link)]` />
                        <Message Text=`%(Content.Identity): [%(Content.Link)]` />
                      </Target>
                    </Project>
                ",
                 logger
                 );

                project.Build();

                logger.AssertLogContains(String.Format(@"{0}: []", classPath));
                logger.AssertLogContains(String.Format(@"{0}: []", textFilePath));
                logger.AssertLogContains(String.Format(@"{0}: []", contentPath));
            }
            finally
            {
                if (directoryToDelete != null)
                {
                    ObjectModelHelpers.DeleteDirectory(directoryToDelete);
                }

                ObjectModelHelpers.DeleteDirectory(outputPath);
            }
        }

        #endregion AssignLinkMetadata targets tests
#endif

#if _NOT_YET_FULLY_CONVERTED_
        /// <summary>
        /// Tests that exercise the SplitResourcesByCulture Target in Microsoft.Common.targets.
        /// This target's job is to separate the items that need to run through resgen from 
        /// those that need to go directly into CSC. Also, Culture and non-Culture resources 
        /// are split.
        /// </summary>
        [Test]
        public void SplitResourcesByCultureTarget()
        {
            Project p = ObjectModelHelpers.CreateInMemoryProject(@"

                   <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                      <PropertyGroup>
                        <OutputPath>bin\Debug\</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>Exe</OutputType>
                        <Configuration>Debug</Configuration>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`Class1.cs` />
                        <EmbeddedResource Include=`Resource1.txt` />
                        <EmbeddedResource Include=`Resource2.resx` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
                    </Project>
                "); 

            p.Build(new string [] {"SplitResourcesByCulture"}, null);

            ProjectItem[] items = p.GetItems("EmbeddedResource").ToArray();                        

            Assert.AreEqual("Resource2.resx", items[0].EvaluatedInclude);
            Assert.AreEqual("false", items[0].GetMetadataValue("WithCulture"));
            Assert.AreEqual("Resx", items[0].GetMetadataValue("Type"));

            Assert.AreEqual("Resource1.txt", items[1].EvaluatedInclude);
            Assert.AreEqual("false", items[1].GetMetadataValue("WithCulture"));
            Assert.AreEqual("Non-Resx", items[1].GetMetadataValue("Type"));
        }

        /// <summary>
        /// Test to make sure that referenced projects are being cleaned properly.
        /// </summary>
        [Test]
        public void Regress565788()
        {
            Helper.CreateTempCSharpProjectWithClassLibrary();

            string[] buildTarget = new string[1];
            buildTarget[0] = "Build";
            MockLogger log = ObjectModelHelpers.BuildTempProjectFileWithTargetsExpectSuccess(@"ConsoleApplication\ConsoleApplication.csproj", buildTarget, null);

            ObjectModelHelpers.AssertFileExistsInTempProjectDirectory(@"ClassLibrary\bin\debug\ClassLibrary.dll",
                "Failed to create ClassLibrary.dll, which should have been created because there was P2P reference from ConsoleApplication");

            buildTarget[0] = "Clean";
            log = ObjectModelHelpers.BuildTempProjectFileWithTargetsExpectSuccess(@"ConsoleApplication\ConsoleApplication.csproj", buildTarget, null);

            ObjectModelHelpers.AssertFileDoesNotExistInTempProjectDirectory(@"ClassLibrary\bin\debug\ClassLibrary.dll",
                "Failed to delete ClassLibrary.dll, which should have been deleted because there was P2P reference from ConsoleApplication");
        }

        /// <summary>
        /// Tests that we correctly handle .RESTEXT files marked as EmbeddedResource in the project.
        /// </summary>
        [Test]
        public void ResTextFiles_CSharp()
        {
            ObjectModelHelpers.DeleteTempProjectDirectory();

            // ----------------------------------------------------------------------------
            // ConsoleApplication37.csproj
            // ----------------------------------------------------------------------------
            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"ConsoleApplication37.csproj", @"

                <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                    <PropertyGroup>
                        <Configuration Condition=` '$(Configuration)' == '' `>Debug</Configuration>
                        <Platform Condition=` '$(Platform)' == '' `>AnyCPU</Platform>
                        <ProductVersion>8.0.50510</ProductVersion>
                        <SchemaVersion>2.0</SchemaVersion>
                        <ProjectGuid>{1EE23632-5998-4CF5-9EAD-11FDC67456E6}</ProjectGuid>
                        <OutputType>Exe</OutputType>
                        <AppDesignerFolder>Properties</AppDesignerFolder>
                        <RootNamespace>ConsoleApplication37</RootNamespace>
                        <AssemblyName>ConsoleApplication37</AssemblyName>
                    </PropertyGroup>
                    <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' `>
                        <DebugSymbols>true</DebugSymbols>
                        <DebugType>full</DebugType>
                        <Optimize>false</Optimize>
                        <OutputPath>bin\Debug\</OutputPath>
                        <DefineConstants>DEBUG;TRACE</DefineConstants>
                        <ErrorReport>prompt</ErrorReport>
                        <WarningLevel>4</WarningLevel>
                    </PropertyGroup>
                    <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Release|AnyCPU' `>
                        <DebugType>pdbonly</DebugType>
                        <Optimize>true</Optimize>
                        <OutputPath>bin\Release\</OutputPath>
                        <DefineConstants>TRACE</DefineConstants>
                        <ErrorReport>prompt</ErrorReport>
                        <WarningLevel>4</WarningLevel>
                    </PropertyGroup>
                    <ItemGroup>
                        <Reference Include=`System` />
                        <Reference Include=`System.Data` />
                        <Reference Include=`System.Xml` />
                    </ItemGroup>
                    <ItemGroup>
                        <Compile Include=`Program.cs` />
                    </ItemGroup>
                    <ItemGroup>
                        <EmbeddedResource Include=`Strings1.restext` />
                        <EmbeddedResource Include=`Strings2.restext`>
                            <LogicalName>MyStrings2.resources</LogicalName>
                        </EmbeddedResource>
                        <EmbeddedResource Include=`Subfolder\Strings3.restext` />
                    </ItemGroup>
                    <ItemGroup>
                        <Folder Include=`Properties\` />
                    </ItemGroup>
                    <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
                </Project>

                ");

            // ----------------------------------------------------------------------------
            // Program.cs
            // ----------------------------------------------------------------------------
            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"Program.cs", @"

                using System;
                using System.Collections.Generic;
                using System.Text;
                using System.Resources;
                using System.Reflection;

                namespace ConsoleApplication37
                {
	                class Program
	                {
		                static int Main(string[] args)
		                {
                            try
                            {
			                    ResourceManager rm;
                    			
			                    rm = new ResourceManager(`ConsoleApplication37.Strings1`, Assembly.GetExecutingAssembly());
			                    Console.WriteLine(rm.GetString(`Usage`));
                    			
			                    rm = new ResourceManager(`MyStrings2`, Assembly.GetExecutingAssembly());
			                    Console.WriteLine(String.Format(rm.GetString(`InvalidChildElement`), `Foo`));

			                    rm = new ResourceManager(`ConsoleApplication37.Subfolder.Strings3`, Assembly.GetExecutingAssembly());
			                    Console.WriteLine(rm.GetString(`CopyrightMessage`));

                                return 0;
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine(e.ToString());
                                return 1;
                            }
		                }
	                }
                }

                ");

            // ----------------------------------------------------------------------------
            // Strings1.restext
            // ----------------------------------------------------------------------------
            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"Strings1.restext", 
                @"Usage=Hello world!  Isn't it a beautiful day?");

            // ----------------------------------------------------------------------------
            // Strings2.restext
            // ----------------------------------------------------------------------------
            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"Strings2.restext", 
                @"InvalidChildElement=The element {0} is not allowed here.");

            // ----------------------------------------------------------------------------
            // Subfolder\Strings3.restext
            // ----------------------------------------------------------------------------
            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"Subfolder\Strings3.restext", 
                @"CopyrightMessage=Copyright (C) 2005, The MSBuild Team");

            MockLogger logger = ObjectModelHelpers.BuildTempProjectFileExpectSuccess(@"ConsoleApplication37.csproj");

            string stdout = ObjectModelHelpers.RunTempProjectBuiltApplication(@"bin\debug\ConsoleApplication37.exe");

            Assert.IsTrue(@"ConsoleApplication37.exe did not emit Usage string.  See test output (Attachments in Azure Pipelines) for details.", 
                stdout.Contains("Hello world!  Isn't it a beautiful day?"));

            Assert.IsTrue(@"ConsoleApplication37.exe did not emit InvalidChildElement string.  See test output (Attachments in Azure Pipelines) for details.", 
                stdout.Contains("The element Foo is not allowed here."));

            Assert.IsTrue(@"ConsoleApplication37.exe did not emit CopyrightMessage string.  See test output (Attachments in Azure Pipelines) for details.", 
                stdout.Contains("Copyright (C) 2005, The MSBuild Team"));
        }

        /// <summary>
        /// Tests that we correctly handle .RESTEXT files marked as EmbeddedResource in the project.
        /// </summary>
        [Test]
        public void ResTextFiles_VB()
        {
            ObjectModelHelpers.DeleteTempProjectDirectory();

            // ----------------------------------------------------------------------------
            // ConsoleApplication38.vbproj
            // ----------------------------------------------------------------------------
            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"ConsoleApplication38.vbproj", @"

                <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                    <PropertyGroup>
                        <Configuration Condition=` '$(Configuration)' == '' `>Debug</Configuration>
                        <Platform Condition=` '$(Platform)' == '' `>AnyCPU</Platform>
                        <ProductVersion>8.0.50510</ProductVersion>
                        <SchemaVersion>2.0</SchemaVersion>
                        <ProjectGuid>{136C326F-8E8F-4164-9AFC-CA8BC754F103}</ProjectGuid>
                        <OutputType>Exe</OutputType>
                        <StartupObject>ConsoleApplication38.Module1</StartupObject>
                        <RootNamespace>ConsoleApplication38</RootNamespace>
                        <AssemblyName>ConsoleApplication38</AssemblyName>
                        <MyType>Console</MyType>
                    </PropertyGroup>
                    <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' `>
                        <DebugSymbols>true</DebugSymbols>
                        <DebugType>full</DebugType>
                        <DefineDebug>true</DefineDebug>
                        <DefineTrace>true</DefineTrace>
                        <OutputPath>bin\Debug\</OutputPath>
                        <DocumentationFile>ConsoleApplication38.xml</DocumentationFile>
                        <NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
                    </PropertyGroup>
                    <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Release|AnyCPU' `>
                        <DebugType>pdbonly</DebugType>
                        <DefineDebug>false</DefineDebug>
                        <DefineTrace>true</DefineTrace>
                        <Optimize>true</Optimize>
                        <OutputPath>bin\Release\</OutputPath>
                        <DocumentationFile>ConsoleApplication38.xml</DocumentationFile>
                        <NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
                    </PropertyGroup>
                    <ItemGroup>
                        <Reference Include=`System` />
                        <Reference Include=`System.Data` />
                        <Reference Include=`System.Deployment` />
                        <Reference Include=`System.Xml` />
                    </ItemGroup>
                    <ItemGroup>
                        <Import Include=`Microsoft.VisualBasic` />
                        <Import Include=`System` />
                        <Import Include=`System.Collections` />
                        <Import Include=`System.Collections.Generic` />
                        <Import Include=`System.Data` />
                        <Import Include=`System.Diagnostics` />
                        <Import Include=`System.Reflection` />
                        <Import Include=`System.Resources` />
                    </ItemGroup>
                    <ItemGroup>
                        <Compile Include=`Module1.vb` />
                        <EmbeddedResource Include=`Strings1.restext` />
                        <EmbeddedResource Include=`Strings2.restext`>
                            <LogicalName>MyStrings2.resources</LogicalName>
                        </EmbeddedResource>
                        <EmbeddedResource Include=`Subfolder\Strings3.restext` />
                    </ItemGroup>
                    <Import Project=`$(MSBuildBinPath)\Microsoft.VisualBasic.targets` />
                </Project>

                ");

            // ----------------------------------------------------------------------------
            // Module1.vb
            // ----------------------------------------------------------------------------
            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"Module1.vb", @"

                Module Module1

                    Sub Main()
                        Try
                            Dim rm1 As New ResourceManager(`ConsoleApplication38.Strings1`, Assembly.GetExecutingAssembly())
                            Console.WriteLine(rm1.GetString(`Usage`))

                            Dim rm2 As New ResourceManager(`MyStrings2`, Assembly.GetExecutingAssembly())
                            Console.WriteLine(String.Format(rm2.GetString(`InvalidChildElement`), `Foo`))

                            Dim rm3 As New ResourceManager(`ConsoleApplication38.Strings3`, Assembly.GetExecutingAssembly())
                            Console.WriteLine(rm3.GetString(`CopyrightMessage`))

                        Catch ex As Exception

                            Console.WriteLine(ex.ToString())

                        End Try
                    End Sub

                End Module

                ");

            // ----------------------------------------------------------------------------
            // Strings1.restext
            // ----------------------------------------------------------------------------
            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"Strings1.restext", 
                @"Usage=Hello world!  Isn't it a beautiful day?");

            // ----------------------------------------------------------------------------
            // Strings2.restext
            // ----------------------------------------------------------------------------
            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"Strings2.restext", 
                @"InvalidChildElement=The element {0} is not allowed here.");

            // ----------------------------------------------------------------------------
            // Subfolder\Strings3.restext
            // ----------------------------------------------------------------------------
            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"Subfolder\Strings3.restext", 
                @"CopyrightMessage=Copyright (C) 2005, The MSBuild Team");

            MockLogger logger = ObjectModelHelpers.BuildTempProjectFileExpectSuccess(@"ConsoleApplication38.vbproj");

            string stdout = ObjectModelHelpers.RunTempProjectBuiltApplication(@"bin\debug\ConsoleApplication38.exe");

            Assert.IsTrue(@"ConsoleApplication38.exe did not emit Usage string.  See test output (Attachments in Azure Pipelines) for details.", 
                stdout.Contains("Hello world!  Isn't it a beautiful day?"));

            Assert.IsTrue(@"ConsoleApplication38.exe did not emit InvalidChildElement string.  See test output (Attachments in Azure Pipelines) for details.", 
                stdout.Contains("The element Foo is not allowed here."));

            Assert.IsTrue(@"ConsoleApplication38.exe did not emit CopyrightMessage string.  See test output (Attachments in Azure Pipelines) for details.", 
                stdout.Contains("Copyright (C) 2005, The MSBuild Team"));
        }
    }

    /// <summary>
    /// Regress specific bugs.
    /// </summary>
    [TestFixture]
    sealed public class Bugs
    {
        /// <summary>
        /// In this bug, calling Project.EvaluatedProperties cached properties and the next call
        /// to run a target didn't invalidate the cache. The result was that the TargetFrameworkDirectory
        /// wasn't visible to VS.
        /// </summary>
        [Test]
        public void Regress381480()
        {
            string f0 = FileUtilities.GetTemporaryFile();
            string f1 = FileUtilities.GetTemporaryFile();
            try
            {
                Project p0 = ObjectModelHelpers.CreateInMemoryProject(@"
    
                        <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`> 
                            <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
                        </Project>

                    ");

                Project p1 = ObjectModelHelpers.CreateInMemoryProject(@"
    
                        <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`> 
                           <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
                        </Project>

                    ");

                p0.FullPath = f0;
                p1.FullPath = f1;

                p0.Build("GetFrameworkPaths");
                Dictionary<string, string> preEvaluated = p1.EvaluatedProperties;
                p1.Build("GetFrameworkPaths");
                Dictionary<string, string> postEvaluated = p1.EvaluatedProperties;

                Assert.IsTrue("Expected a value for TargetFrameworkDirectory.", postEvaluated["TargetFrameworkDirectory"].Value.Length > 0);
                Assert.IsTrue("Expected a different property group.", preEvaluated != postEvaluated);
            }
            finally
            {
                File.Delete(f0);
                File.Delete(f1);
            }

        }
    }

    /// <summary>
    /// Tests the MainBuiltProjectOutputGroup Target which is responsible for quickly (i.e. without
    /// building) returning the name of the EXE or DLL that would be built.
    /// </summary>
    [TestFixture]
    sealed public class GetTargetPath        
    {
        /// <summary>
        /// Try a basic workings.
        /// </summary>
        [Test]
        public void Basic()
        {
            Project p = ObjectModelHelpers.CreateInMemoryProject(@"

                   <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`> 
                      <PropertyGroup>
                        <OutputPath>bin\Debug\</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>Exe</OutputType>
                        <Configuration>Debug</Configuration>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`Class1.cs` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
                   </Project>
                ");            
            
            Hashtable h = new Hashtable();
            p.Build(new string[] {"GetTargetPath" }, h);
            ObjectModelHelpers.AssertSingleItemInDictionary(h, "<|proj|>bin\\Debug\\MyAssembly.exe");
        }
    }    

    /// <summary>
    /// Tests that exercise the PrepareResourceNames Target in 
    /// Microsoft.VisualBasic.targets.
    /// 
    /// This target's job is to create manifest resource names for each of
    /// the resource files.
    /// </summary>
    [TestFixture]
    sealed public class PrepareResourceNamesTarget        
    {
        /// <summary>
        /// Basic test.
        /// </summary>
        [Test]
        public void BasicVbResourceNames()
        {
            Project p = ObjectModelHelpers.CreateInMemoryProject(@"

                   <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`> 
                      <PropertyGroup>
                        <OutputPath>bin\Debug\</OutputPath>
                        <AssemblyName>MyAssembly</AssemblyName>
                        <OutputType>Exe</OutputType>
                        <RootNamespace>MyNamespace</RootNamespace>
                        <MSBuildTargetsVerbose>true</MSBuildTargetsVerbose>
                        <Configuration>Debug</Configuration>
                      </PropertyGroup>
                      <ItemGroup>
                        <Compile Include=`Class1.vb` />
                        <EmbeddedResource Include=`Resource1.txt` />
                        <EmbeddedResource Include=`Resource2.resx` />
                        <EmbeddedResource Include=`Resource2.fr.resx` />
                      </ItemGroup>
                      <Import Project=`$(MSBuildBinPath)\Microsoft.VisualBasic.targets` />
                    </Project>
                ");            

            p.Build(new string [] {"PrepareResourceNames"}, null);

            ProjectItem[] items = p.GetItems("EmbeddedResource").ToArray();            

            Assert.AreEqual("Resource2.resx", items[0].EvaluatedInclude);
            Assert.AreEqual("false", items[0].GetMetadataValue("WithCulture"));
            Assert.AreEqual("Resx", items[0].GetMetadataValue("Type"));
            Assert.AreEqual("MyNamespace.Resource2", items[0].GetMetadataValue("ManifestResourceName"));

            Assert.AreEqual("Resource2.fr.resx", items[1].EvaluatedInclude);
            Assert.AreEqual("true", items[1].GetMetadataValue("WithCulture"));
            Assert.AreEqual("Resx", items[1].GetMetadataValue("Type"));
            Assert.AreEqual("MyNamespace.Resource2.fr", items[1].GetMetadataValue("ManifestResourceName"));            

            Assert.AreEqual("Resource1.txt", items[2].EvaluatedInclude);
            Assert.AreEqual("false", items[2].GetMetadataValue("WithCulture"));
            Assert.AreEqual("Non-Resx", items[2].GetMetadataValue("Type"));
            Assert.AreEqual("MyNamespace.Resource1.txt", items[2].GetMetadataValue("ManifestResourceName"));
        }
    }

    /// <summary>
    /// Tests the CopyAppConfigFile target.
    /// </summary>
    [TestFixture]
    sealed public class CopyAppConfigFile
    {
        [Test]
        public void CopyAppConfigFileEvenForDllProjects()
        {
            ObjectModelHelpers.DeleteTempProjectDirectory();

            // ---------------------
            // Foo.csproj
            // ---------------------
            ObjectModelHelpers.CreateFileInTempProjectDirectory("foo.csproj", @"
                <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                <PropertyGroup>
                    <Configuration Condition=` '$(Configuration)' == '' `>Debug</Configuration>
                    <Platform Condition=` '$(Platform)' == '' `>AnyCPU</Platform>
                    <ProductVersion>8.0.50413</ProductVersion>
                    <SchemaVersion>2.0</SchemaVersion>
                    <OutputType>Library</OutputType>
                    <AppDesignerFolder>Properties</AppDesignerFolder>
                    <RootNamespace>ClassLibrary16</RootNamespace>
                    <AssemblyName>ClassLibrary16</AssemblyName>
                </PropertyGroup>
                <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' `>
                    <DebugSymbols>true</DebugSymbols>
                    <DebugType>full</DebugType>
                    <Optimize>false</Optimize>
                    <OutputPath>bin\Debug\</OutputPath>
                    <DefineConstants>DEBUG;TRACE</DefineConstants>
                    <ErrorReport>prompt</ErrorReport>
                    <WarningLevel>4</WarningLevel>
                </PropertyGroup>
                <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Release|AnyCPU' `>
                    <DebugType>pdbonly</DebugType>
                    <Optimize>true</Optimize>
                    <OutputPath>bin\Release\</OutputPath>
                    <DefineConstants>TRACE</DefineConstants>
                    <ErrorReport>prompt</ErrorReport>
                    <WarningLevel>4</WarningLevel>
                </PropertyGroup>
                <ItemGroup>
                    <Reference Include=`System` />
                    <Reference Include=`System.Data` />
                    <Reference Include=`System.Xml` />
                </ItemGroup>
                <ItemGroup>
                    <Compile Include=`Class1.cs` />
                </ItemGroup>
                <ItemGroup>
                    <None Include=`App.config` />
                </ItemGroup>
                <ItemGroup>
                    <Folder Include=`Properties\` />
                </ItemGroup>
                <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
                <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
                    Other similar extension points exist, see Microsoft.Common.targets.
                <Target Name=`BeforeBuild`>
                </Target>
                <Target Name=`AfterBuild`>
                </Target>
                -->
                </Project>
            ");
            
            // ---------------------
            // Class1.cs
            // ---------------------
            ObjectModelHelpers.CreateFileInTempProjectDirectory("Class1.cs", @"
                using System;
                using System.Collections.Generic;
                using System.Text;
                using System.Reflection;
                using System.Runtime.CompilerServices;
                using System.Runtime.InteropServices;

                // General Information about an assembly is controlled through the following 
                // set of attributes. Change these attribute values to modify the information
                // associated with an assembly.
                [assembly: AssemblyTitle(`ClassLibrary16`)]
                [assembly: AssemblyDescription(``)]
                [assembly: AssemblyConfiguration(``)]
                [assembly: AssemblyCompany(`Microsoft`)]
                [assembly: AssemblyProduct(`ClassLibrary16`)]
                [assembly: AssemblyCopyright(`Copyright © Microsoft 2005`)]
                [assembly: AssemblyTrademark(``)]
                [assembly: AssemblyCulture(``)]

                // Setting ComVisible to false makes the types in this assembly not visible 
                // to COM components.  If you need to access a type in this assembly from 
                // COM, set the ComVisible attribute to true on that type.
                [assembly: ComVisible(false)]

                // The following GUID is for the ID of the typelib if this project is exposed to COM
                [assembly: Guid(`3c11545e-2e63-403b-bd07-5fb2e0f78c92`)]

                // Version information for an assembly consists of the following four values:
                //
                //      Major Version
                //      Minor Version 
                //      Build Number
                //      Revision
                //
                // You can specify all the values or you can default the Revision and Build Numbers 
                // by using the '*' as shown below:
                [assembly: AssemblyVersion(`1.0.0.0`)]
                [assembly: AssemblyFileVersion(`1.0.0.0`)]

                namespace ClassLibrary16
                {
	                public class Class1
	                {
	                }
                }
            ");

            // ---------------------
            // App.config
            // ---------------------
            ObjectModelHelpers.CreateFileInTempProjectDirectory("App.config", @"
                <?xml version=`1.0` encoding=`utf-8` ?>
                <configuration>
                </configuration>
            ");

            ObjectModelHelpers.BuildTempProjectFileExpectSuccess("foo.csproj");

            Assert.IsTrue(@"Did not find expected file bin\debug\ClassLibrary16.dll.config",
                File.Exists(Path.Combine(ObjectModelHelpers.TempProjectDir, @"bin\debug\ClassLibrary16.dll.config")));
        }

        /// <summary>
        /// Find app.config in various locations
        /// </summary>
        /// <remarks>
        ///    The search order is:
        ///
        ///    (1) Choose the value $(AppConfig) set in the main project.
        ///    (2) Choose @(None) App.Config in the same folder as the project.
        ///    (3) Choose @(Content) App.Config in the same folder as the project.
        ///    (4) Choose @(None) App.Config in any subfolder in the project.
        ///    (5) Choose @(Content) App.Config in any subfolder in the project.
        ///
        ///If an app.config is not found in one of these locations then there is no app.config for this project.
        /// </remarks>
        [Test]
        public void AppConfigLocation()
        {
            // Try each of the cases in turn, by manipulating a single project
            ProjectCollection e = new ProjectCollection();
            e.SetGlobalProperty("case", "0"); // Make project loadable
            Project p = ObjectModelHelpers.CreateInMemoryProject(e, @"

                   <Project ToolsVersion=`4.0` xmlns=`msbuildnamespace`> 
                      <PropertyGroup>
                        <OutputType>Library</OutputType>
                        <AssemblyName>foo</AssemblyName>
                        <AppConfig Condition=`'$(case)'&lt;=1`>foo.exe.config</AppConfig>
                      </PropertyGroup>
                      <ItemGroup>
                        <None Include=`app.config` Condition=`'$(case)'&lt;=2`/>
                        <Content Include=`app.config` Condition=`'$(case)'&lt;=3 and '$(case)'!=2`/>
                        <None Include=`foo\app.config` Condition=`'$(case)'&lt;=4`/>
                        <Content Include=`bar\app.config` Condition=`'$(case)'&lt;=5`/>
                      </ItemGroup>
                      <Import Project=`$(MSBuildBinPath)\Microsoft.VisualBasic.targets` />
                    </Project>
                ", null);

            ///    (1) Choose the value $(AppConfig) set in the main project.
            p.SetGlobalProperty("case", "1");
            p.Build(new string[] { "PrepareForBuild" });
            ProjectItemm item = ObjectModelHelpers.AssertSingleItem(p, "AppConfigWithTargetPath", "foo.exe.config");
            Assert.AreEqual("foo.dll.config", item.GetMetadataValue("TargetPath"));

            ///    (2) Choose @(None) App.Config in the same folder as the project.
            p.SetGlobalProperty("case", "2");
            p.Build(new string[] { "PrepareForBuild" });
            item = ObjectModelHelpers.AssertSingleItem(p, "AppConfigWithTargetPath", "app.config");
            Assert.AreEqual("foo.dll.config", item.GetMetadataValue("TargetPath"));

            ///    (3) Choose @(Content) App.Config in the same folder as the project.
            p.SetGlobalProperty("case", "3");
            p.Build(new string[] { "PrepareForBuild" });
            item = ObjectModelHelpers.AssertSingleItem(p, "AppConfigWithTargetPath", "app.config");
            Assert.AreEqual("foo.dll.config", item.GetMetadataValue("TargetPath"));
            
            ///    (4) Choose @(None) App.Config in any subfolder in the project.
            p.SetGlobalProperty("case", "4");
            p.Build(new string[] { "PrepareForBuild" });
            item = ObjectModelHelpers.AssertSingleItem(p, "AppConfigWithTargetPath", "foo\\app.config");
            Assert.AreEqual("foo.dll.config", item.GetMetadataValue("TargetPath"));

            ///    (5) Choose @(Content) App.Config in any subfolder in the project.
            p.SetGlobalProperty("case", "5");
            p.Build(new string[] { "PrepareForBuild" });
            item = ObjectModelHelpers.AssertSingleItem(p, "AppConfigWithTargetPath", "bar\\app.config");
            Assert.AreEqual("foo.dll.config", item.GetMetadataValue("TargetPath"));

            ///If an app.config is not found in one of these locations then there is no app.config for this project.
            p.SetGlobalProperty("case", "6");
            p.Build(new string[] { "PrepareForBuild" });
            ObjectModelHelpers.AssertNoItem(p, "AppConfigWithTargetPath");
        }

        /// <summary>
        /// Handle app.config's specified with paths like "..\..\app.config"
        /// In this case both app.config's do not match exactly "app.config" so we should take the /last/
        /// match listed. This arbitrary choice matches the behavior we shipped.
        /// </summary>
        [Test]
        public void AppConfigLocationRelativeDir()
        {
            ProjectCollection e = new ProjectCollection();
            Project p = ObjectModelHelpers.CreateInMemoryProject(e, @"

                   <Project ToolsVersion=`4.0` xmlns=`msbuildnamespace`> 
                      <PropertyGroup>
                        <OutputType>Library</OutputType>
                        <AssemblyName>foo</AssemblyName>
                      </PropertyGroup>
                      <ItemGroup>
                        <None Include=`..\..\app.config`/>
                        <None Include=`.\app.config`/>
                      </ItemGroup>
                      <Import Project=`$(MSBuildBinPath)\Microsoft.VisualBasic.targets` />
                    </Project>
                ", null);

            ///    Pick the last one
            p.Build(new string[] { "PrepareForBuild" });
            ProjectItemm item = ObjectModelHelpers.AssertSingleItem(p, "AppConfigWithTargetPath", @".\app.config");
            Assert.AreEqual("foo.dll.config", item.GetMetadataValue("TargetPath"));
        }

        /// <summary>
        /// None should be chosen in preference to Content
        /// </summary>
        [Test]
        public void AppConfigLocationNoneWinsOverContent()
        {
            ProjectCollection e = new ProjectCollection();
            Project p = ObjectModelHelpers.CreateInMemoryProject(e, @"

                   <Project ToolsVersion=`4.0` xmlns=`msbuildnamespace`> 
                      <PropertyGroup>
                        <OutputType>Library</OutputType>
                        <AssemblyName>foo</AssemblyName>
                      </PropertyGroup>
                      <ItemGroup>
                        <None Include=`c:\foo\app.config`/>
                        <Content Include=`d:\bar\app.config`/>
                      </ItemGroup>
                      <Import Project=`$(MSBuildBinPath)\Microsoft.VisualBasic.targets` />
                    </Project>
                ", null);

            ///    Pick the last one, trying None first
            p.Build(new string[] { "PrepareForBuild" });
            ProjectItemm item = ObjectModelHelpers.AssertSingleItem(p, "AppConfigWithTargetPath", @"c:\foo\app.config");
            Assert.AreEqual("foo.dll.config", item.GetMetadataValue("TargetPath"));
        }
    }

    /// <summary>
    /// Tests some general things about our .TARGETS files, such as which properties are referenced.
    /// </summary>
    [TestFixture]
    sealed public class General
    {
        /// <summary>
        /// Tests that our .TARGETS files do not condition on $(Configuration), thereby adding
        /// configs to the VS config dropdown when they don't really exist in the project file.
        /// </summary>
        [Test]
        public void ConfigurationsReferencedInCSharpProject()
        {
            Project p = ObjectModelHelpers.CreateInMemoryProject(@"

                <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                    <PropertyGroup>
                        <Configuration Condition=` '$(Configuration)' == '' `>Debug</Configuration>
                        <Platform Condition=` '$(Platform)' == '' `>AnyCPU</Platform>
                        <ProductVersion>8.0.50502</ProductVersion>
                        <SchemaVersion>2.0</SchemaVersion>
                        <ProjectGuid>{083A5AF7-1AD5-416F-8770-BE564F54DA22}</ProjectGuid>
                        <OutputType>Exe</OutputType>
                        <AppDesignerFolder>Properties</AppDesignerFolder>
                        <RootNamespace>ConsoleApplication27</RootNamespace>
                        <AssemblyName>ConsoleApplication27</AssemblyName>
                    </PropertyGroup>
                    <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'FooConfig|AnyCPU' `>
                        <DebugSymbols>true</DebugSymbols>
                        <DebugType>full</DebugType>
                        <Optimize>false</Optimize>
                        <OutputPath>bin\Debug\</OutputPath>
                        <DefineConstants>DEBUG;TRACE</DefineConstants>
                        <ErrorReport>prompt</ErrorReport>
                        <WarningLevel>4</WarningLevel>
                    </PropertyGroup>
                    <ItemGroup>
                        <Reference Include=`System` />
                        <Reference Include=`System.Data` />
                        <Reference Include=`System.Xml` />
                    </ItemGroup>
                    <ItemGroup>
                        <Compile Include=`Program.cs` />
                        <Compile Include=`Properties\AssemblyInfo.cs` />
                    </ItemGroup>
                    <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
                </Project>
                ");            

            string[] configurations = p.GetConditionedProperties("Configuration");

            Console.WriteLine("Configurations found = " + String.Join(", ", configurations));
            Assert.AreEqual("See test output (Attachments in Azure Pipelines) for details", 1, configurations.Length);
            Assert.AreEqual("See test output (Attachments in Azure Pipelines) for details", "FooConfig", configurations[0]);
        }

        /// <summary>
        /// Tests that our .TARGETS files do not condition on $(Configuration), thereby adding
        /// configs to the VS config dropdown when they don't really exist in the project file.
        /// </summary>
        [Test]
        public void ConfigurationsReferencedInVBProject()
        {
            Project p = ObjectModelHelpers.CreateInMemoryProject(@"
                <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                    <PropertyGroup>
                        <Configuration Condition=` '$(Configuration)' == '' `>Debug</Configuration>
                        <Platform Condition=` '$(Platform)' == '' `>AnyCPU</Platform>
                        <ProductVersion>8.0.50502</ProductVersion>
                        <SchemaVersion>2.0</SchemaVersion>
                        <ProjectGuid>{DB0F2DFA-0164-4071-902D-348330C940E6}</ProjectGuid>
                        <OutputType>Exe</OutputType>
                        <StartupObject>ConsoleApplication28.Module1</StartupObject>
                        <RootNamespace>ConsoleApplication28</RootNamespace>
                        <AssemblyName>ConsoleApplication28</AssemblyName>
                        <MyType>Console</MyType>
                    </PropertyGroup>
                    <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'FooConfig|AnyCPU' `>
                        <DebugSymbols>true</DebugSymbols>
                        <DebugType>full</DebugType>
                        <DefineDebug>true</DefineDebug>
                        <DefineTrace>true</DefineTrace>
                        <OutputPath>bin\Debug\</OutputPath>
                        <DocumentationFile>ConsoleApplication28.xml</DocumentationFile>
                        <NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
                    </PropertyGroup>
                    <ItemGroup>
                        <Reference Include=`System` />
                        <Reference Include=`System.Data` />
                        <Reference Include=`System.Deployment` />
                        <Reference Include=`System.Xml` />
                    </ItemGroup>
                    <ItemGroup>
                        <Import Include=`Microsoft.VisualBasic` />
                        <Import Include=`System` />
                        <Import Include=`System.Collections` />
                        <Import Include=`System.Collections.Generic` />
                        <Import Include=`System.Data` />
                        <Import Include=`System.Diagnostics` />
                    </ItemGroup>
                    <ItemGroup>
                        <Compile Include=`Module1.vb` />
                        <Compile Include=`My Project\AssemblyInfo.vb` />
                        <Compile Include=`My Project\Application.Designer.vb`>
                        <AutoGen>True</AutoGen>
                        <DependentUpon>Application.myapp</DependentUpon>
                        </Compile>
                        <Compile Include=`My Project\Resources.Designer.vb`>
                        <AutoGen>True</AutoGen>
                        <DesignTime>True</DesignTime>
                        <DependentUpon>Resources.resx</DependentUpon>
                        </Compile>
                        <Compile Include=`My Project\Settings.Designer.vb`>
                        <AutoGen>True</AutoGen>
                        <DependentUpon>Settings.settings</DependentUpon>
                        <DesignTimeSharedInput>True</DesignTimeSharedInput>
                        </Compile>
                    </ItemGroup>
                    <ItemGroup>
                        <EmbeddedResource Include=`My Project\Resources.resx`>
                        <Generator>VbMyResourcesResXFileCodeGenerator</Generator>
                        <LastGenOutput>Resources.Designer.vb</LastGenOutput>
                        <CustomToolNamespace>My.Resources</CustomToolNamespace>
                        </EmbeddedResource>
                    </ItemGroup>
                    <ItemGroup>
                        <None Include=`My Project\Application.myapp`>
                        <Generator>MyApplicationCodeGenerator</Generator>
                        <LastGenOutput>Application.Designer.vb</LastGenOutput>
                        </None>
                        <None Include=`My Project\Settings.settings`>
                        <Generator>SettingsSingleFileGenerator</Generator>
                        <LastGenOutput>Settings.Designer.vb</LastGenOutput>
                        </None>
                    </ItemGroup>
                    <Import Project=`$(MSBuildBinPath)\Microsoft.VisualBasic.targets` />
                </Project>

                ");            

            string[] configurations = p.GetConditionedProperties("Configuration");

            Console.WriteLine("Configurations found = " + String.Join(", ", configurations));
            Assert.AreEqual("See test output (Attachments in Azure Pipelines) for details", 1, configurations.Length);
            Assert.AreEqual("See test output (Attachments in Azure Pipelines) for details", "FooConfig", configurations[0]);
        }

        /// <summary>
        /// This is the infamous path-too-long problem.  All absolute paths in question are within 
        /// the 260 character limit that the filesystem imposes.  However, when paths are accessed 
        /// using relative paths, sometimes the simple concatenation of the current directory with the
        /// relative path can exceed 260 characters.  MSBuild should solve this scenario by doing 
        /// smarter path manipulation.
        /// </summary>
        [Test]
        public void ProjectToProjectReferenceWithLongRelativePath()
        {
            ObjectModelHelpers.DeleteTempProjectDirectory();

            string tempProjectRoot = ObjectModelHelpers.TempProjectDir;

            // Set deepRelativePath = abc\abc\abc\ ... \abc\abc\abc\

            // minus 55 to leave room for ConsoleApp\obj\debug\ResolveAssemblyReference.cache
            // div 4 because that's how much each subdir costs.
            int MAX_PATH = 260;
            int numberOfSubDirectoriesToCreate = (MAX_PATH - tempProjectRoot.Length - 55) / 4;  
            StringBuilder deepRelativePath = new StringBuilder();
            for (int i = 0 ; i < numberOfSubDirectoriesToCreate ; i++)
            {
                deepRelativePath.Append(@"abc\");
            }

            // Set relativePathToConsoleAppDir = abc\abc\abc\ ... \abc\abc\abc\ConsoleApp\
            string relativePathToConsoleAppDir = deepRelativePath.ToString() + @"ConsoleApp\";

            // Set relativePathToClassLibDir = abc\abc\abc\ ... \abc\abc\abc\ClassLib\
            string relativePathToClassLibDir = deepRelativePath.ToString() + @"ClassLib\";

            // ====================================
            // ConsoleApp\ConsoleApp.csproj
            // ====================================
            ObjectModelHelpers.CreateFileInTempProjectDirectory(relativePathToConsoleAppDir + "ConsoleApp.csproj", @"
                <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                    <PropertyGroup>
                        <CleanFile>CleanFile.txt</CleanFile>
                        <Configuration Condition=` '$(Configuration)' == '' `>Debug</Configuration>
                        <Platform Condition=` '$(Platform)' == '' `>AnyCPU</Platform>
                        <OutputType>Exe</OutputType>
                        <RootNamespace>ConsoleApp</RootNamespace>
                        <AssemblyName>ConsoleApp</AssemblyName>
                    </PropertyGroup>
                    <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' `>
                        <DebugSymbols>true</DebugSymbols>
                        <DebugType>full</DebugType>
                        <Optimize>false</Optimize>
                        <OutputPath>bin\Debug\</OutputPath>
                        <DefineConstants>DEBUG;TRACE</DefineConstants>
                        <ErrorReport>prompt</ErrorReport>
                        <WarningLevel>4</WarningLevel>
                    </PropertyGroup>
                    <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Release|AnyCPU' `>
                        <DebugType>pdbonly</DebugType>
                        <Optimize>true</Optimize>
                        <OutputPath>bin\Release\</OutputPath>
                        <DefineConstants>TRACE</DefineConstants>
                        <ErrorReport>prompt</ErrorReport>
                        <WarningLevel>4</WarningLevel>
                    </PropertyGroup>
                    <ItemGroup>
                        <Reference Include=`System` />
                        <Reference Include=`System.Data` />
                        <Reference Include=`System.Xml` />
                    </ItemGroup>
                    <ItemGroup>
                        <Compile Include=`Program.cs` />
                    </ItemGroup>
                    <ItemGroup>
                        <ProjectReference Include=`..\..\..\..\..\..\..\abc\abc\abc\abc\abc\abc\ClassLib\ClassLib.csproj` />
                    </ItemGroup>
                    <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
                </Project>
                ");

            // ====================================
            // ConsoleApp\Program.cs
            // ====================================
            ObjectModelHelpers.CreateFileInTempProjectDirectory(relativePathToConsoleAppDir + "Program.cs", @"
                namespace ConsoleApplication79
                {
	                class Program
	                {
		                static void Main(string[] args)
		                {
			                ClassLibrary1.LongPathBug foo = new ClassLibrary1.LongPathBug();
		                }
	                }
                }
                ");

            // ====================================
            // ClassLib\ClassLib.csproj
            // ====================================
            ObjectModelHelpers.CreateFileInTempProjectDirectory(relativePathToClassLibDir + "ClassLib.csproj", @"
                <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                    <PropertyGroup>
                        <CleanFile>CleanFile.txt</CleanFile>
                        <Configuration Condition=` '$(Configuration)' == '' `>Debug</Configuration>
                        <Platform Condition=` '$(Platform)' == '' `>AnyCPU</Platform>
                        <OutputType>Library</OutputType>
                        <AppDesignerFolder>Properties</AppDesignerFolder>
                        <RootNamespace>ClassLib</RootNamespace>
                        <AssemblyName>ClassLib</AssemblyName>
                    </PropertyGroup>
                    <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' `>
                        <DebugSymbols>true</DebugSymbols>
                        <DebugType>full</DebugType>
                        <Optimize>false</Optimize>
                        <OutputPath>bin\Debug\</OutputPath>
                        <DefineConstants>DEBUG;TRACE</DefineConstants>
                        <ErrorReport>prompt</ErrorReport>
                        <WarningLevel>4</WarningLevel>
                    </PropertyGroup>
                    <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Release|AnyCPU' `>
                        <DebugType>pdbonly</DebugType>
                        <Optimize>true</Optimize>
                        <OutputPath>bin\Release\</OutputPath>
                        <DefineConstants>TRACE</DefineConstants>
                        <ErrorReport>prompt</ErrorReport>
                        <WarningLevel>4</WarningLevel>
                    </PropertyGroup>
                    <ItemGroup>
                        <Reference Include=`System` />
                        <Reference Include=`System.Data` />
                        <Reference Include=`System.Xml` />
                    </ItemGroup>
                    <ItemGroup>
                        <Compile Include=`Class1.cs` />
                    </ItemGroup>
                    <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
                    <!-- The old OM, which is what this solution is being built under, doesn't understand
                         BeforeTargets, so this test was failing, because _AssignManagedMetadata was set 
                         up as a BeforeTarget for Build.  Copied here so that build will return the correct
                         information again. -->
                    <Target Name=`BeforeBuild`>
                        <ItemGroup>
                            <BuiltTargetPath Include=`$(TargetPath)`>
                                <ManagedAssembly>$(ManagedAssembly)</ManagedAssembly>
                            </BuiltTargetPath>
                        </ItemGroup>
                    </Target>
                </Project>
                ");

            // ====================================
            // ClassLib\Class1.cs
            // ====================================
            ObjectModelHelpers.CreateFileInTempProjectDirectory(relativePathToClassLibDir + "Class1.cs", @"
                namespace ClassLibrary1
                {
	                public class LongPathBug
	                {
	                }
                }
                ");


            // Build the ConsoleApp project.
            ObjectModelHelpers.BuildTempProjectFileExpectSuccess(relativePathToConsoleAppDir + "ConsoleApp.csproj");

            ObjectModelHelpers.AssertFileExistsInTempProjectDirectory(relativePathToConsoleAppDir + @"bin\Debug\ConsoleApp.exe");
        }

        /// <summary>
        /// There is a C# project that has a P2P ref to a J# project.  The C# project supports Debug/Release|AnyCPU.
        /// The J# project supports Debug/Release|x86.  There is a solution configuration defined call Debug/Release|Mixed Platforms
        /// which contains the appropriate project configurations.
        /// </summary>
        [Test]
        //[Ignore("Need J# to be in the v3.5 folder")]
        public void SolutionConfigurationWithDifferentProjectConfigurations()
        {
            ObjectModelHelpers.DeleteTempProjectDirectory();

            // ==================================================================
            // SOLUTION1.SLN
            // ==================================================================
            ObjectModelHelpers.CreateFileInTempProjectDirectory("Solution1.sln", 
                @"Microsoft Visual Studio Solution File, Format Version 9.00
                 Visual Studio 2005
                Project(`{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}`) = `CSharpClassLib`, `CSharpClassLib\CSharpClassLib.csproj`, `{9FB32A10-FA44-4DD3-ABA8-5215CF599BD6}`
                EndProject
                Project(`{E6FDF86B-F3D1-11D4-8576-0002A516ECE8}`) = `JSharpClassLib`, `JSharpClassLib\JSharpClassLib.vjsproj`, `{DFE7D1F5-B0E8-4EB8-BC1B-0274C2747078}`
                EndProject
                Global
	                GlobalSection(SolutionConfigurationPlatforms) = preSolution
		                Debug|Any CPU = Debug|Any CPU
		                Debug|Mixed Platforms = Debug|Mixed Platforms
		                Debug|x86 = Debug|x86
		                Release|Any CPU = Release|Any CPU
		                Release|Mixed Platforms = Release|Mixed Platforms
		                Release|x86 = Release|x86
	                EndGlobalSection
	                GlobalSection(ProjectConfigurationPlatforms) = postSolution
		                {9FB32A10-FA44-4DD3-ABA8-5215CF599BD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		                {9FB32A10-FA44-4DD3-ABA8-5215CF599BD6}.Debug|Any CPU.Build.0 = Debug|Any CPU
		                {9FB32A10-FA44-4DD3-ABA8-5215CF599BD6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
		                {9FB32A10-FA44-4DD3-ABA8-5215CF599BD6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
		                {9FB32A10-FA44-4DD3-ABA8-5215CF599BD6}.Debug|x86.ActiveCfg = Debug|Any CPU
		                {9FB32A10-FA44-4DD3-ABA8-5215CF599BD6}.Release|Any CPU.ActiveCfg = Release|Any CPU
		                {9FB32A10-FA44-4DD3-ABA8-5215CF599BD6}.Release|Any CPU.Build.0 = Release|Any CPU
		                {9FB32A10-FA44-4DD3-ABA8-5215CF599BD6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
		                {9FB32A10-FA44-4DD3-ABA8-5215CF599BD6}.Release|Mixed Platforms.Build.0 = Release|Any CPU
		                {9FB32A10-FA44-4DD3-ABA8-5215CF599BD6}.Release|x86.ActiveCfg = Release|Any CPU
		                {DFE7D1F5-B0E8-4EB8-BC1B-0274C2747078}.Debug|Any CPU.ActiveCfg = Debug|x86
		                {DFE7D1F5-B0E8-4EB8-BC1B-0274C2747078}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
		                {DFE7D1F5-B0E8-4EB8-BC1B-0274C2747078}.Debug|Mixed Platforms.Build.0 = Debug|x86
		                {DFE7D1F5-B0E8-4EB8-BC1B-0274C2747078}.Debug|x86.ActiveCfg = Debug|x86
		                {DFE7D1F5-B0E8-4EB8-BC1B-0274C2747078}.Debug|x86.Build.0 = Debug|x86
		                {DFE7D1F5-B0E8-4EB8-BC1B-0274C2747078}.Release|Any CPU.ActiveCfg = Release|x86
		                {DFE7D1F5-B0E8-4EB8-BC1B-0274C2747078}.Release|Mixed Platforms.ActiveCfg = Release|x86
		                {DFE7D1F5-B0E8-4EB8-BC1B-0274C2747078}.Release|Mixed Platforms.Build.0 = Release|x86
		                {DFE7D1F5-B0E8-4EB8-BC1B-0274C2747078}.Release|x86.ActiveCfg = Release|x86
		                {DFE7D1F5-B0E8-4EB8-BC1B-0274C2747078}.Release|x86.Build.0 = Release|x86
	                EndGlobalSection
	                GlobalSection(SolutionProperties) = preSolution
		                HideSolutionNode = FALSE
	                EndGlobalSection
                EndGlobal
                ");

            // ==================================================================
            // CSHARPCLASSLIB.CSPROJ
            // ==================================================================
            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"CSharpClassLib\CSharpClassLib.csproj", @"
                <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                  <PropertyGroup>
                    <Configuration Condition=` '$(Configuration)' == '' `>Debug</Configuration>
                    <Platform Condition=` '$(Platform)' == '' `>AnyCPU</Platform>
                    <ProductVersion>8.0.50627</ProductVersion>
                    <SchemaVersion>2.0</SchemaVersion>
                    <ProjectGuid>{9FB32A10-FA44-4DD3-ABA8-5215CF599BD6}</ProjectGuid>
                    <OutputType>Library</OutputType>
                    <AppDesignerFolder>Properties</AppDesignerFolder>
                    <RootNamespace>CSharpClassLib</RootNamespace>
                    <AssemblyName>CSharpClassLib</AssemblyName>
                  </PropertyGroup>
                  <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' `>
                    <DebugSymbols>true</DebugSymbols>
                    <DebugType>full</DebugType>
                    <Optimize>false</Optimize>
                    <OutputPath>bin\Debug\</OutputPath>
                    <DefineConstants>DEBUG;TRACE</DefineConstants>
                    <ErrorReport>prompt</ErrorReport>
                    <WarningLevel>4</WarningLevel>
                  </PropertyGroup>
                  <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Release|AnyCPU' `>
                    <DebugType>pdbonly</DebugType>
                    <Optimize>true</Optimize>
                    <OutputPath>bin\Release\</OutputPath>
                    <DefineConstants>TRACE</DefineConstants>
                    <ErrorReport>prompt</ErrorReport>
                    <WarningLevel>4</WarningLevel>
                  </PropertyGroup>
                  <ItemGroup>
                    <Reference Include=`System` />
                    <Reference Include=`System.Data` />
                    <Reference Include=`System.Xml` />
                  </ItemGroup>
                  <ItemGroup>
                    <Compile Include=`Class1.cs` />
                  </ItemGroup>
                  <ItemGroup>
                    <ProjectReference Include=`..\JSharpClassLib\JSharpClassLib.vjsproj`>
                      <Project>{DFE7D1F5-B0E8-4EB8-BC1B-0274C2747078}</Project>
                      <Name>JSharpClassLib</Name>
                    </ProjectReference>
                  </ItemGroup>
                  <ItemGroup>
                    <Folder Include=`Properties\` />
                  </ItemGroup>
                  <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
                  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
                       Other similar extension points exist, see Microsoft.Common.targets.
                  <Target Name=`BeforeBuild`>
                  </Target>
                  <Target Name=`AfterBuild`>
                  </Target>
                  -->
                </Project>
                ");

            // ==================================================================
            // CLASS1.CS
            // ==================================================================
            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"CSharpClassLib\Class1.cs", @"
                using System;
                using System.Collections.Generic;
                using System.Text;

                namespace CSharpClassLib
                {
	                public class Class1
	                {
		                JSharpClassLib.Class1 myjsharpclass = new JSharpClassLib.Class1();
	                }
                }
                ");

            // ==================================================================
            // JSHARPCLASSLIB.VJSPROJ
            // ==================================================================
            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"JSharpClassLib\JSharpClassLib.vjsproj", @"
                <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                  <PropertyGroup>
                    <Configuration Condition=` '$(Configuration)' == '' `>Debug</Configuration>
                    <Platform Condition=` '$(Platform)' == '' `>x86</Platform>
                    <ProductVersion>8.0.50627</ProductVersion>
                    <SchemaVersion>2.0</SchemaVersion>
                    <ProjectGuid>{DFE7D1F5-B0E8-4EB8-BC1B-0274C2747078}</ProjectGuid>
                    <OutputType>Library</OutputType>
                    <RootNamespace>JSharpClassLib</RootNamespace>
                    <AssemblyName>JSharpClassLib</AssemblyName>
                    <WarningLevel>4</WarningLevel>
                  </PropertyGroup>
                  <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Debug|x86' `>
                    <DebugSymbols>true</DebugSymbols>
                    <DebugType>full</DebugType>
                    <Optimize>false</Optimize>
                    <OutputPath>bin\Debug\</OutputPath>
                    <DefineConstants>DEBUG;TRACE</DefineConstants>
                  </PropertyGroup>
                  <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Release|x86' `>
                    <DebugType>pdbonly</DebugType>
                    <Optimize>true</Optimize>
                    <OutputPath>bin\Release\</OutputPath>
                    <DefineConstants>TRACE</DefineConstants>
                  </PropertyGroup>
                  <ItemGroup>
                    <Reference Include=`System` />
                    <Reference Include=`System.Data` />
                    <Reference Include=`System.Xml` />
                  </ItemGroup>
                  <ItemGroup>
                    <Compile Include=`Class1.jsl` />
                  </ItemGroup>
                  <ItemGroup>
                    <Folder Include=`Properties\` />
                  </ItemGroup>
                  <Import Project=`$(MSBuildBinPath)\Microsoft.VisualJSharp.targets` />
                  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
                       Other similar extension points exist, see Microsoft.Common.targets.
                  <Target Name=`BeforeBuild`>
                  </Target>
                  <Target Name=`AfterBuild`>
                  </Target>
                  -->
                </Project>
                ");

            // ==================================================================
            // CLASS1.JSL
            // ==================================================================
            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"JSharpClassLib\Class1.jsl", @"
                package JSharpClassLib;


                /**
                 * Summary description for Class1
                 */
                public class Class1
                {
	                public Class1()
	                {
		                //
		                // TO DO: Add constructor logic here
		                //
	                }
                }
                ");

            // Build the .SLN
            ObjectModelHelpers.BuildTempProjectFileExpectSuccess("Solution1.sln");

            ObjectModelHelpers.AssertFileExistsInTempProjectDirectory(@"CSharpClassLib\bin\debug\CSharpClassLib.dll");
        }

        /// <summary>
        /// Tests that the .pdb file is not copied to the output directory when the
        /// SkipCopyingSymbolsToOutputDirectory property is set.
        /// </summary>
        [Test]
        public void SkipCopyingPdbFile()
        {
            // create a temp project
            Helper.CreateTempCSharpProjectWithClassLibrary();

            // build it and expect the .pdb to be in the output directory
            ObjectModelHelpers.BuildTempProjectFileWithTargetsExpectSuccess(@"ConsoleApplication\ConsoleApplication.csproj", null, null);
            ObjectModelHelpers.AssertFileExistsInTempProjectDirectory(@"ConsoleApplication\bin\Debug\ConsoleApplication.pdb");

            // set the SkipCopyingSymbolsToOutputDirectory property
            Dictionary<string, string> additionalProperties = new Dictionary<string, string> ();
            additionalProperties["SkipCopyingSymbolsToOutputDirectory"] = "true";

            // build the project again and expect the .pdb to have been removed from the output directory
            ObjectModelHelpers.BuildTempProjectFileWithTargetsExpectSuccess(@"ConsoleApplication\ConsoleApplication.csproj", null, additionalProperties);
            ObjectModelHelpers.AssertFileDoesNotExistInTempProjectDirectory(@"ConsoleApplication\bin\Debug\ConsoleApplication.pdb");

            // set the SkipCopyingSymbolsToOutputDirectory property explicitly to "false"
            additionalProperties["SkipCopyingSymbolsToOutputDirectory"]= "false";

            // build the project again and expect the .pdb to be back in the output directory
            ObjectModelHelpers.BuildTempProjectFileWithTargetsExpectSuccess(@"ConsoleApplication\ConsoleApplication.csproj", null, null);
            ObjectModelHelpers.AssertFileExistsInTempProjectDirectory(@"ConsoleApplication\bin\Debug\ConsoleApplication.pdb");
        }

        /// <summary>
        /// Tests that the .pdb file is not produced if /p:debugtype=none is set externally
        /// </summary>
        [Test]
        public void SkipProducingPdbCsharp()
        {
            // create a temp project
            Helper.CreateTempCSharpProjectWithClassLibrary();

            // build it and expect the .pdb to be in the output directory: verify /debug+ /debug:full is default for debug config
            MockLogger l = ObjectModelHelpers.BuildTempProjectFileWithTargetsExpectSuccess(@"ConsoleApplication\ConsoleApplication.csproj", null, null);
            l.AssertLogContains("/debug+");
            l.AssertLogContains("/debug:full");
            ObjectModelHelpers.AssertFileExistsInTempProjectDirectory(@"ConsoleApplication\bin\Debug\ConsoleApplication.pdb");

            // verify /debug:pdbonly is default for release config
            Dictionary<string, string> additionalProperties = new Dictionary<string, string> ();
            additionalProperties.SetProperty("Configuration", "release");
            l.ClearLog();
            l = ObjectModelHelpers.BuildTempProjectFileWithTargetsExpectSuccess(@"ConsoleApplication\ConsoleApplication.csproj", null, additionalProperties, true);
            l.AssertLogDoesntContain("/debug+");
            l.AssertLogContains("/debug:pdbonly");
            ObjectModelHelpers.AssertFileExistsInTempProjectDirectory(@"ConsoleApplication\bin\release\ConsoleApplication.pdb");

            // set the DebugSymbols=false property
            additionalProperties = new Dictionary<string, string> ();
            additionalProperties.SetProperty("DebugType", "none");

            // build the project again and expect the .pdb to have been removed from the output directory
            l = ObjectModelHelpers.BuildTempProjectFileWithTargetsExpectSuccess(@"ConsoleApplication\ConsoleApplication.csproj", null, additionalProperties, true);
            l.AssertLogDoesntContain("/debug+");
            l.AssertLogContains("/debug-");
            l.AssertLogDoesntContain("/debug:full");
            ObjectModelHelpers.AssertFileDoesNotExistInTempProjectDirectory(@"ConsoleApplication\bin\Debug\ConsoleApplication.pdb");

            // debug config again; set the DebugType property explicitly to "full"
            additionalProperties = new Dictionary<string, string>();
            additionalProperties["DebugType"] ="full";

            // build the project again and expect the .pdb to be back in the output directory
            l.ClearLog();
            l = ObjectModelHelpers.BuildTempProjectFileWithTargetsExpectSuccess(@"ConsoleApplication\ConsoleApplication.csproj", null, additionalProperties, true);
            l.AssertLogContains("/debug+");
            l.AssertLogContains("/debug:full");
            ObjectModelHelpers.AssertFileExistsInTempProjectDirectory(@"ConsoleApplication\bin\Debug\ConsoleApplication.pdb");

            // try release configuration with DebugSymbols set to true, as well
            additionalProperties = new Dictionary<string, string>();
            additionalProperties["Configuration"] = "release";
            additionalProperties["DebugSymbols"] = "true";
            l.ClearLog();
            l = ObjectModelHelpers.BuildTempProjectFileWithTargetsExpectSuccess(@"ConsoleApplication\ConsoleApplication.csproj", null, additionalProperties, true);
            l.AssertLogContains("/debug+");
            l.AssertLogContains("/debug:pdbonly");
            ObjectModelHelpers.AssertFileExistsInTempProjectDirectory(@"ConsoleApplication\bin\release\ConsoleApplication.pdb");        
        }

        /// <summary>
        /// Tests that the .pdb file is not produced if /p:debugsymbols=false is set externally
        /// </summary>
        [Test]
        public void SkipProducingPdbVB()
        {
            // create a temp project
            Helper.CreateTempVBProject();

            // build it and expect the .pdb to be in the output directory
            MockLogger l = ObjectModelHelpers.BuildTempProjectFileWithTargetsExpectSuccess(@"ConsoleApplication\ConsoleApplication.vbproj", null, null, true);
            l.AssertLogContains("/debug+");
            l.AssertLogContains("/debug:full");
            ObjectModelHelpers.AssertFileExistsInTempProjectDirectory(@"ConsoleApplication\bin\Debug\ConsoleApplication.pdb");

            //// set the DebugType=none property
            Dictionary<string, string> additionalProperties = new Dictionary<string, string> ();
            additionalProperties.SetProperty("DebugType", "none");

            // build the project again and expect the .pdb to have been removed from the output directory
            l.ClearLog();
            l = ObjectModelHelpers.BuildTempProjectFileWithTargetsExpectSuccess(@"ConsoleApplication\ConsoleApplication.vbproj", null, additionalProperties, true);
            l.AssertLogDoesntContain("/debug+");
            l.AssertLogContains("/debug-");
            l.AssertLogDoesntContain("/debug:full");
            ObjectModelHelpers.AssertFileDoesNotExistInTempProjectDirectory(@"ConsoleApplication\bin\Debug\ConsoleApplication.pdb");

            // set the DebugType property explicitly to "full"
            additionalProperties.SetProperty("DebugType", "full");

            // build the project again and expect the .pdb to be back in the output directory
            l.ClearLog();
            l = ObjectModelHelpers.BuildTempProjectFileWithTargetsExpectSuccess(@"ConsoleApplication\ConsoleApplication.vbproj", null, null, true);
            l.AssertLogContains("/debug+");
            l.AssertLogContains("/debug:full");
            ObjectModelHelpers.AssertFileExistsInTempProjectDirectory(@"ConsoleApplication\bin\Debug\ConsoleApplication.pdb");
        }
    }

    /// <summary>
    /// Helper methods for unit-tests in this file.
    /// </summary>
    internal static class Helper
    {
        /// <summary>
        /// Creates a temporary project on disk for doing unit-tests on.
        /// </summary>
        internal static void CreateTempCSharpProjectWithClassLibrary()
        {
            ObjectModelHelpers.DeleteTempProjectDirectory();

            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"ConsoleApplication\ConsoleApplication.csproj", @"
                <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                  <PropertyGroup>
                    <Configuration Condition=` '$(Configuration)' == '' `>Debug</Configuration>
                    <Platform Condition=` '$(Platform)' == '' `>AnyCPU</Platform>
                    <ProductVersion>8.0.50727</ProductVersion>
                    <SchemaVersion>2.0</SchemaVersion>
                    <ProjectGuid>{34D5E50A-464A-4098-9DB6-679D5310E7EB}</ProjectGuid>
                    <OutputType>Exe</OutputType>
                    <AppDesignerFolder>Properties</AppDesignerFolder>
                    <RootNamespace>ConsoleApplication</RootNamespace>
                    <AssemblyName>ConsoleApplication</AssemblyName>
                  </PropertyGroup>
                  <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' `>
                    <DebugSymbols>true</DebugSymbols>
                    <DebugType>full</DebugType>
                    <Optimize>false</Optimize>
                    <OutputPath>bin\Debug\</OutputPath>
                    <DefineConstants>DEBUG;TRACE</DefineConstants>
                    <ErrorReport>prompt</ErrorReport>
                    <WarningLevel>4</WarningLevel>
                  </PropertyGroup>
                  <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Release|AnyCPU' `>
                    <DebugType>pdbonly</DebugType>
                    <Optimize>true</Optimize>
                    <OutputPath>bin\Release\</OutputPath>
                    <DefineConstants>TRACE</DefineConstants>
                    <ErrorReport>prompt</ErrorReport>
                    <WarningLevel>4</WarningLevel>
                  </PropertyGroup>
                  <ItemGroup>
                    <Reference Include=`System` />
                    <Reference Include=`System.Data` />
                    <Reference Include=`System.Xml` />
                  </ItemGroup>
                  <ItemGroup>
                    <Compile Include=`Program.cs` />
                  </ItemGroup>
                  <ItemGroup>
                    <ProjectReference Include=`..\ClassLibrary\ClassLibrary.csproj`>
                      <Project>{50E656DA-C81B-43D5-B2ED-8B5DCB2398EB}</Project>
                      <Name>ClassLibrary1</Name>
                    </ProjectReference>
                  </ItemGroup>
                  <ItemGroup>
                    <Folder Include=`Properties\` />
                  </ItemGroup>
                  <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
                </Project>
                ");

            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"ConsoleApplication\Program.cs", @"
                using System;
                using System.Collections.Generic;
                using System.Text;

                namespace ConsoleApplication1
                {
                    class Program
                    {
                        static void Main(string[] args)
                        {
                        }
                    }
                }
                ");

            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"ClassLibrary\ClassLibrary.csproj", @"
                <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                  <PropertyGroup>
                    <Configuration Condition=` '$(Configuration)' == '' `>Debug</Configuration>
                    <Platform Condition=` '$(Platform)' == '' `>AnyCPU</Platform>
                    <ProductVersion>8.0.50727</ProductVersion>
                    <SchemaVersion>2.0</SchemaVersion>
                    <ProjectGuid>{50E656DA-C81B-43D5-B2ED-8B5DCB2398EB}</ProjectGuid>
                    <OutputType>Library</OutputType>
                    <AppDesignerFolder>Properties</AppDesignerFolder>
                    <RootNamespace>ClassLibrary</RootNamespace>
                    <AssemblyName>ClassLibrary</AssemblyName>
                  </PropertyGroup>
                  <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' `>
                    <DebugSymbols>true</DebugSymbols>
                    <DebugType>full</DebugType>
                    <Optimize>false</Optimize>
                    <OutputPath>bin\Debug\</OutputPath>
                    <DefineConstants>DEBUG;TRACE</DefineConstants>
                    <ErrorReport>prompt</ErrorReport>
                    <WarningLevel>4</WarningLevel>
                  </PropertyGroup>
                  <PropertyGroup Condition=` '$(Configuration)|$(Platform)' == 'Release|AnyCPU' `>
                    <DebugType>pdbonly</DebugType>
                    <Optimize>true</Optimize>
                    <OutputPath>bin\Release\</OutputPath>
                    <DefineConstants>TRACE</DefineConstants>
                    <ErrorReport>prompt</ErrorReport>
                    <WarningLevel>4</WarningLevel>
                  </PropertyGroup>
                  <ItemGroup>
                    <Reference Include=`System` />
                    <Reference Include=`System.Data` />
                    <Reference Include=`System.Xml` />
                  </ItemGroup>
                  <ItemGroup>
                    <Compile Include=`Class.cs` />
                  </ItemGroup>
                  <ItemGroup>
                    <Folder Include=`Properties\` />
                  </ItemGroup>
                  <Import Project=`$(MSBuildBinPath)\Microsoft.CSharp.targets` />
                </Project>
                ");

            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"ClassLibrary\Class.cs", @"
                using System;
                using System.Collections.Generic;
                using System.Text;

                namespace ClassLibrary1
                {
                    public class Class1
                    {
                    }
                }
                ");
        }

        /// <summary>
        /// Creates a temporary project on disk for doing unit-tests on.
        /// </summary>
        internal static void CreateTempVBProject()
        {
            ObjectModelHelpers.DeleteTempProjectDirectory();

            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"ConsoleApplication\ConsoleApplication.vbproj", @"
                <Project DefaultTargets=`Build` ToolsVersion=`4.0` xmlns=`msbuildnamespace`>
                  <PropertyGroup>
                    <Configuration Condition="" '$(Configuration)' == '' "">Debug</Configuration>
                    <Platform Condition="" '$(Platform)' == '' "">AnyCPU</Platform>
                    <ProductVersion>8.0.60512</ProductVersion>
                    <SchemaVersion>2.0</SchemaVersion>
                    <ProjectGuid>{32D53832-D685-4FF7-B093-8ADCE0CA9F20}</ProjectGuid>
                    <OutputType>Exe</OutputType>
                    <StartupObject>VBconsoleapp.Module1</StartupObject>
                    <RootNamespace>VBconsoleapp</RootNamespace>
                    <AssemblyName>ConsoleApplication</AssemblyName>
                    <FileAlignment>512</FileAlignment>
                    <MyType>Console</MyType>
                  </PropertyGroup>
                  <PropertyGroup Condition="" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "">
                    <DebugSymbols>true</DebugSymbols>
                    <DebugType>full</DebugType>
                    <DefineDebug>true</DefineDebug>
                    <DefineTrace>true</DefineTrace>
                    <OutputPath>bin\Debug\</OutputPath>
                    <DocumentationFile>VBconsoleapp.xml</DocumentationFile>
                    <NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
                  </PropertyGroup>
                  <PropertyGroup Condition="" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "">
                    <DebugType>pdbonly</DebugType>
                    <DefineDebug>false</DefineDebug>
                    <DefineTrace>true</DefineTrace>
                    <Optimize>true</Optimize>
                    <OutputPath>bin\Release\</OutputPath>
                    <DocumentationFile>VBconsoleapp.xml</DocumentationFile>
                    <NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
                  </PropertyGroup>
                  <ItemGroup>
                    <Reference Include=""System"" />
                    <Reference Include=""System.Data"" />
                    <Reference Include=""System.Deployment"" />
                    <Reference Include=""System.Drawing"" />
                    <Reference Include=""System.Windows.Forms"" />
                    <Reference Include=""System.Xml"" />
                    <Reference Include=""System.Core"">
                      <RequiredTargetFramework>3.5</RequiredTargetFramework>
                    </Reference>
                    <Reference Include=""System.Xml.Linq"">
                      <RequiredTargetFramework>3.5</RequiredTargetFramework>
                    </Reference>
                    <Reference Include=""System.Data.DataSetExtensions"">
                      <RequiredTargetFramework>3.5</RequiredTargetFramework>
                    </Reference>
                  </ItemGroup>
                  <ItemGroup>
                    <Import Include=""Microsoft.VisualBasic"" />
                    <Import Include=""System"" />
                    <Import Include=""System.Collections"" />
                    <Import Include=""System.Collections.Generic"" />
                    <Import Include=""System.Data"" />
                    <Import Include=""System.Drawing"" />
                    <Import Include=""System.Diagnostics"" />
                    <Import Include=""System.Windows.Forms"" />
                    <Import Include=""System.Linq"" />
                    <Import Include=""System.Xml.Linq"" />
                  </ItemGroup>
                  <ItemGroup>
                    <Compile Include=""Module1.vb"" />
                  </ItemGroup>
                  <Import Project=""$(MSBuildBinPath)\Microsoft.VisualBasic.targets"" />
                  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
                       Other similar extension points exist, see Microsoft.Common.targets.
                  <Target Name=""BeforeBuild"">
                  </Target>
                  <Target Name=""AfterBuild"">
                  </Target>
                  -->
            </Project>");

            ObjectModelHelpers.CreateFileInTempProjectDirectory(@"ConsoleApplication\Module1.vb", @"
                Module Module1

                    Sub Main()

                    End Sub

                End Module
                ");
        }
#endif
    }
}


<|start_filename|>src/MSBuild/OutOfProcTaskAppDomainWrapper.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using Microsoft.Build.Framework;

namespace Microsoft.Build.CommandLine
{
    /// <summary>
    /// Class for executing a task in an AppDomain
    /// </summary>
    [Serializable]
    internal class OutOfProcTaskAppDomainWrapper : OutOfProcTaskAppDomainWrapperBase
    {
        /// <summary>
        /// This is an extension of the OutOfProcTaskAppDomainWrapper that is responsible 
        /// for activating and executing the user task.
        /// This extension provides support for ICancellable Out-Of-Proc tasks.
        /// </summary>
        /// <returns>True if the task is ICancellable</returns>
        internal bool CancelTask()
        {
            // If the cancel was issued even before WrappedTask has been created then set a flag so that we can
            // skip execution
            CancelPending = true;

            // Store in a local to avoid a race
            var wrappedTask = WrappedTask;
            if (wrappedTask == null)
            {
                return true;
            }

            ICancelableTask cancelableTask = wrappedTask as ICancelableTask;
            if (cancelableTask != null)
            {
                cancelableTask.Cancel();
                return true;
            }

            return false;
        }
    }
}


<|start_filename|>src/Build/Evaluation/Preprocessor.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Microsoft.Build.Construction;
using Microsoft.Build.Shared;

namespace Microsoft.Build.Evaluation
{
    /// <summary>
    /// Creates a view of an evaluated project's XML as if it had all been loaded from
    /// a single file, instead of being assembled by pulling in imported files as it actually was.
    /// </summary>
    /// <remarks>
    /// Ideally the result would be buildable on its own, and *usually* this should be the case.
    /// Known cases where it wouldn't be buildable:
    /// -- $(MSBuildThisFile) and similar properties aren't corrected
    /// -- relative path in exists(..) conditions is relative to the imported file
    /// -- same for AssemblyFile on UsingTask
    /// Paths in item includes are relative to the importing project, though.
    /// </remarks>
    internal class Preprocessor
    {
        /// <summary>
        /// Project to preprocess
        /// </summary>
        private readonly Project _project;

        /// <summary>
        /// Table to resolve import tags
        /// </summary>
        private readonly Dictionary<XmlElement, IList<ProjectRootElement>> _importTable;

        /// <summary>
        /// Stack of file paths pushed as we follow imports
        /// </summary>
        private readonly Stack<string> _filePaths = new Stack<string>();

        /// <summary>
        /// Used to keep track of nodes that were added to the document from implicit imports which will be removed later.
        /// At the time of adding this feature, cloning is buggy so it is easier to just edit the DOM in memory.
        /// </summary>
        private List<XmlNode> _addedNodes;

        /// <summary>
        /// Table of implicit imports by document.  The list per document contains both top and bottom imports.
        /// </summary>
        private readonly Dictionary<XmlDocument, List<ResolvedImport>> _implicitImportsByProject = new Dictionary<XmlDocument, List<ResolvedImport>>();

        /// <summary>
        /// Constructor
        /// </summary>
        private Preprocessor(Project project)
        {
            _project = project;

            IList<ResolvedImport> imports = project.Imports;

            _importTable = new Dictionary<XmlElement, IList<ProjectRootElement>>(imports.Count);

            foreach (ResolvedImport entry in imports)
            {
                AddToImportTable(entry.ImportingElement.XmlElement, entry.ImportedProject);
            }
        }

        /// <summary>
        /// Returns an XmlDocument representing the evaluated project's XML as if it all had
        /// been loaded from a single file, instead of being assembled by pulling in imported files.
        /// </summary>
        internal static XmlDocument GetPreprocessedDocument(Project project)
        {
            Preprocessor preprocessor = new Preprocessor(project);

            XmlDocument result = preprocessor.Preprocess();

            return result;
        }

        /// <summary>
        /// Root of the preprocessing.
        /// </summary>
        private XmlDocument Preprocess()
        {
            XmlDocument outerDocument = _project.Xml.XmlDocument;

            CreateImplicitImportTable();

            AddImplicitImportNodes(outerDocument.DocumentElement);

            XmlDocument destinationDocument = (XmlDocument)outerDocument.CloneNode(false /* shallow */);

            _filePaths.Push(_project.FullPath);

            if (!String.IsNullOrEmpty(_project.FullPath)) // Ignore in-memory projects
            {
                destinationDocument.AppendChild(destinationDocument.CreateComment("\r\n" + new String('=', 140) + "\r\n" + _project.FullPath.Replace("--", "__") + "\r\n" + new String('=', 140) + "\r\n"));
            }

            CloneChildrenResolvingImports(outerDocument, destinationDocument);

            // Remove the nodes that were added as implicit imports
            //
            foreach (XmlNode node in _addedNodes)
            {
                node.ParentNode?.RemoveChild(node);
            }

            return destinationDocument;
        }

        private void AddToImportTable(XmlElement element, ProjectRootElement importedProject)
        {
            IList<ProjectRootElement> list;
            if (!_importTable.TryGetValue(element, out list))
            {
                list = new List<ProjectRootElement>();
                _importTable[element] = list;
            }

            list.Add(importedProject);
        }

        /// <summary>
        /// Creates a table containing implicit imports by project document.
        /// </summary>
        private void CreateImplicitImportTable()
        {
            int implicitImportCount = 0;

            // Loop through all implicit imports top and bottom
            foreach (ResolvedImport resolvedImport in _project.Imports.Where(i => i.ImportingElement.ImplicitImportLocation != ImplicitImportLocation.None))
            {
                implicitImportCount++;
                List<ResolvedImport> imports;

                // Attempt to get an existing list from the dictionary
                if (!_implicitImportsByProject.TryGetValue(resolvedImport.ImportingElement.XmlDocument, out imports))
                {
                    // Add a new list
                    _implicitImportsByProject[resolvedImport.ImportingElement.XmlDocument] = new List<ResolvedImport>();

                    // Get a pointer to the list
                    imports = _implicitImportsByProject[resolvedImport.ImportingElement.XmlDocument];
                }

                imports.Add(resolvedImport);
            }

            // Create a list to store nodes which will be added.  Optimization here is that we now know how many items are going to be added.
            _addedNodes = new List<XmlNode>(implicitImportCount);
        }


        /// <summary>
        /// Adds all implicit import nodes to the specified document.
        /// </summary>
        /// <param name="documentElement">The document element to add nodes to.</param>
        private void AddImplicitImportNodes(XmlElement documentElement)
        {
            List<ResolvedImport> implicitImports;

            // Do nothing if this project has no implicit imports
            if (!_implicitImportsByProject.TryGetValue(documentElement.OwnerDocument, out implicitImports))
            {
                return;
            }

            // Top implicit imports need to be added in the correct order by adding the first one at the top and each one after the first
            // one.  This variable keeps track of the last import that was added.
            XmlNode lastImplicitImportAdded = null;

            // Add the implicit top imports
            //
            foreach (ResolvedImport import in implicitImports.Where(i => i.ImportingElement.ImplicitImportLocation == ImplicitImportLocation.Top))
            {
                XmlElement xmlElement = (XmlElement)documentElement.OwnerDocument.ImportNode(import.ImportingElement.XmlElement, false);
                if (lastImplicitImportAdded == null)
                {
                    if (documentElement.FirstChild == null)
                    {
                        documentElement.AppendChild(xmlElement);
                    }
                    else
                    {
                        documentElement.InsertBefore(xmlElement, documentElement.FirstChild);
                    }

                    lastImplicitImportAdded = xmlElement;
                }
                else
                {
                    documentElement.InsertAfter(xmlElement, lastImplicitImportAdded);
                }
                _addedNodes.Add(xmlElement);
                AddToImportTable(xmlElement, import.ImportedProject);
            }

            // Add the implicit bottom imports
            //
            foreach (var import in implicitImports.Where(i => i.ImportingElement.ImplicitImportLocation == ImplicitImportLocation.Bottom))
            {
                XmlElement xmlElement = (XmlElement)documentElement.InsertAfter(documentElement.OwnerDocument.ImportNode(import.ImportingElement.XmlElement, false), documentElement.LastChild);

                _addedNodes.Add(xmlElement);

                AddToImportTable(xmlElement, import.ImportedProject);
            }
        }

        /// <summary>
        /// Recursively called method that clones source nodes into nodes in the destination
        /// document.
        /// </summary>
        private void CloneChildrenResolvingImports(XmlNode source, XmlNode destination)
        {
            XmlDocument sourceDocument = source.OwnerDocument ?? (XmlDocument)source;
            XmlDocument destinationDocument = destination.OwnerDocument ?? (XmlDocument)destination;

            foreach (XmlNode child in source.ChildNodes)
            {
                // Only one of <?xml version="1.0" encoding="utf-16"?> and we got it automatically already
                if (child.NodeType == XmlNodeType.XmlDeclaration)
                {
                    continue;
                }

                // If this is not the first <Project> tag
                if (
                    child.NodeType == XmlNodeType.Element &&
                    sourceDocument.DocumentElement == child &&                                      // This is the root element, not some random element named 'Project'
                    destinationDocument.DocumentElement != null &&                                  // Skip <Project> tag from the outer project
                    String.Equals(XMakeElements.project, child.Name, StringComparison.Ordinal)
                   )
                {
                    // But suffix any InitialTargets attribute
                    string outerInitialTargets = destinationDocument.DocumentElement.GetAttribute(XMakeAttributes.initialTargets).Trim();
                    string innerInitialTargets = ((XmlElement)child).GetAttribute(XMakeAttributes.initialTargets).Trim();

                    if (innerInitialTargets.Length > 0)
                    {
                        if (outerInitialTargets.Length > 0)
                        {
                            outerInitialTargets += ";";
                        }

                        destinationDocument.DocumentElement.SetAttribute(XMakeAttributes.initialTargets, outerInitialTargets + innerInitialTargets);
                    }

                    // Also gather any DefaultTargets value if none has been encountered already; put it on the outer <Project> tag
                    string outerDefaultTargets = destinationDocument.DocumentElement.GetAttribute(XMakeAttributes.defaultTargets).Trim();

                    if (outerDefaultTargets.Length == 0)
                    {
                        string innerDefaultTargets = ((XmlElement)child).GetAttribute(XMakeAttributes.defaultTargets).Trim();

                        if (innerDefaultTargets.Trim().Length > 0)
                        {
                            destinationDocument.DocumentElement.SetAttribute(XMakeAttributes.defaultTargets, innerDefaultTargets);
                        }
                    }

                    // Add any implicit imports for an imported document
                    AddImplicitImportNodes(child.OwnerDocument.DocumentElement);

                    CloneChildrenResolvingImports(child, destination);
                    continue;
                }

                // Resolve <Import> to 0-n documents and walk into them
                if (child.NodeType == XmlNodeType.Element && String.Equals(XMakeElements.import, child.Name, StringComparison.Ordinal))
                {
                    // To display what the <Import> tag looked like
                    string importCondition = ((XmlElement)child).GetAttribute(XMakeAttributes.condition);
                    string condition = importCondition.Length > 0 ? $" Condition=\"{importCondition}\"" : String.Empty;
                    string importProject = ((XmlElement)child).GetAttribute(XMakeAttributes.project).Replace("--", "__");
                    string importSdk = ((XmlElement)child).GetAttribute(XMakeAttributes.sdk);
                    string sdk = importSdk.Length > 0 ? $" {XMakeAttributes.sdk}=\"{importSdk}\"" : String.Empty;

                    // Get the Sdk attribute of the Project element if specified
                    string projectSdk = source.NodeType == XmlNodeType.Element && String.Equals(XMakeElements.project, source.Name, StringComparison.Ordinal) ? ((XmlElement) source).GetAttribute(XMakeAttributes.sdk) : String.Empty;

                    IList<ProjectRootElement> resolvedList;
                    if (!_importTable.TryGetValue((XmlElement)child, out resolvedList))
                    {
                        // Import didn't resolve to anything; just display as a comment and move on
                        string closedImportTag =
                            $"<Import Project=\"{importProject}\"{sdk}{condition} />";
                        destination.AppendChild(destinationDocument.CreateComment(closedImportTag));

                        continue;
                    }

                    for (int i = 0; i < resolvedList.Count; i++)
                    {
                        ProjectRootElement resolved = resolvedList[i];
                        XmlDocument innerDocument = resolved.XmlDocument;

                        string importTag =
                            $"  <Import Project=\"{importProject}\"{sdk}{condition}>";

                        if (!String.IsNullOrWhiteSpace(importSdk) && projectSdk.IndexOf(importSdk, StringComparison.OrdinalIgnoreCase) >= 0)
                        {
                            importTag +=
                                $"\r\n  This import was added implicitly because the {XMakeElements.project} element's {XMakeAttributes.sdk} attribute specified \"{importSdk}\".";
                        }

                        destination.AppendChild(destinationDocument.CreateComment(
                            $"\r\n{new String('=', 140)}\r\n{importTag}\r\n\r\n{resolved.FullPath.Replace("--", "__")}\r\n{new String('=', 140)}\r\n"));

                        _filePaths.Push(resolved.FullPath);
                        CloneChildrenResolvingImports(innerDocument, destination);
                        _filePaths.Pop();

                        if (i < resolvedList.Count - 1)
                        {
                            destination.AppendChild(destinationDocument.CreateComment("\r\n" + new String('=', 140) + "\r\n  </Import>\r\n" + new String('=', 140) + "\r\n"));
                        }
                        else
                        {
                            destination.AppendChild(destinationDocument.CreateComment("\r\n" + new String('=', 140) + "\r\n  </Import>\r\n\r\n" + _filePaths.Peek()?.Replace("--", "__") + "\r\n" + new String('=', 140) + "\r\n"));
                        }
                    }

                    continue;
                }

                // Skip over <ImportGroup> into its children
                if (child.NodeType == XmlNodeType.Element && String.Equals(XMakeElements.importGroup, child.Name, StringComparison.Ordinal))
                {
                    // To display what the <ImportGroup> tag looked like
                    string importGroupCondition = ((XmlElement)child).GetAttribute(XMakeAttributes.condition);
                    string importGroupTag = "<ImportGroup" + ((importGroupCondition.Length > 0) ? " Condition=\"" + importGroupCondition + "\"" : String.Empty) + ">";
                    destination.AppendChild(destinationDocument.CreateComment(importGroupTag));

                    CloneChildrenResolvingImports(child, destination);

                    destination.AppendChild(destinationDocument.CreateComment("</" + XMakeElements.importGroup + ">"));

                    continue;
                }

                // Node doesn't need special treatment, clone and append
                XmlNode clone = destinationDocument.ImportNode(child, false /* shallow */); // ImportNode does a clone but unlike CloneNode it works across XmlDocuments

                if (clone.NodeType == XmlNodeType.Element && String.Equals(XMakeElements.project, child.Name, StringComparison.Ordinal) && clone.Attributes?[XMakeAttributes.sdk] != null)
                {
                    clone.Attributes.Remove(clone.Attributes[XMakeAttributes.sdk]);
                }

                destination.AppendChild(clone);

                CloneChildrenResolvingImports(child, clone);
            }
        }
    }
}


<|start_filename|>src/Tasks/XamlTaskFactory/TaskParser.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Xaml;
using System.IO;
using Microsoft.Build.Shared;
using Microsoft.Build.Shared.FileSystem;
using XamlTypes = Microsoft.Build.Framework.XamlTypes;

namespace Microsoft.Build.Tasks.Xaml
{
    /// <summary>
    /// The TaskParser class takes an xml file and parses the parameters for a task.
    /// </summary>
    internal class TaskParser
    {
        /// <summary>
        /// The ordered list of how the switches get emitted.
        /// </summary>
        private readonly List<string> _switchOrderList = new List<string>();

        #region Properties

        /// <summary>
        /// The name of the task
        /// </summary>
        public string GeneratedTaskName { get; set; }

        /// <summary>
        /// The base type of the class
        /// </summary>
        public string BaseClass { get; } = "DataDrivenToolTask";

        /// <summary>
        /// The namespace of the class
        /// </summary>
        public string Namespace { get; } = "XamlTaskNamespace";

        /// <summary>
        /// Namespace for the resources
        /// </summary>
        public string ResourceNamespace { get; }

        /// <summary>
        /// The name of the executable
        /// </summary>
        public string ToolName { get; private set; }

        /// <summary>
        /// The default prefix for each switch
        /// </summary>
        public string DefaultPrefix { get; private set; } = String.Empty;

        /// <summary>
        /// All of the parameters that were parsed
        /// </summary>
        public LinkedList<Property> Properties { get; } = new LinkedList<Property>();

        /// <summary>
        /// All of the parameters that have a default value
        /// </summary>
        public LinkedList<Property> DefaultSet { get; } = new LinkedList<Property>();

        /// <summary>
        /// All of the properties that serve as fallbacks for unset properties
        /// </summary>
        public Dictionary<string, string> FallbackSet { get; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

        /// <summary>
        /// The ordered list of properties
        /// </summary>
        public IEnumerable<string> SwitchOrderList => _switchOrderList;

        /// <summary>
        /// Returns the log of errors
        /// </summary>
        public LinkedList<string> ErrorLog { get; } = new LinkedList<string>();

        #endregion

        /// <summary>
        /// Parse the specified string, either as a file path or actual XML content.
        /// </summary>
        public bool Parse(string contentOrFile, string desiredRule)
        {
            ErrorUtilities.VerifyThrowArgumentLength(contentOrFile, nameof(contentOrFile));
            ErrorUtilities.VerifyThrowArgumentLength(desiredRule, nameof(desiredRule));

            bool parseSuccessful = ParseAsContentOrFile(contentOrFile, desiredRule);
            if (!parseSuccessful)
            {
                var parseErrors = new StringBuilder();
                parseErrors.AppendLine();
                foreach (string error in ErrorLog)
                {
                    parseErrors.AppendLine(error);
                }

                throw new ArgumentException(ResourceUtilities.FormatResourceStringStripCodeAndKeyword("Xaml.RuleParseFailed", parseErrors.ToString()));
            }

            return parseSuccessful;
        }

        private bool ParseAsContentOrFile(string contentOrFile, string desiredRule)
        {
            // On Windows:
            // - xml string will be an invalid file path, so, Path.GetFullPath will
            //   return null
            // - xml string cannot be a rooted path ("C:\\<abc />")
            //
            // On Unix:
            // - xml string is a valid path, this is not a definite check as Path.GetFullPath
            //   will return !null in most cases
            // - xml string cannot be a rooted path ("/foo/<abc />")

            bool isRootedPath = false;
            string maybeFullPath = null;
            try
            {
                isRootedPath = Path.IsPathRooted(contentOrFile);
                if (!isRootedPath)
                    maybeFullPath = Path.GetFullPath(contentOrFile);
            }
            catch (Exception e)
            {
                if (ExceptionHandling.IsCriticalException(e))
                {
                    throw;
                }

                // We will get an exception if the contents are not a path (for instance, they are actual XML.)
            }

            if (isRootedPath)
            {
                // valid *absolute* file path

                if (!FileSystems.Default.FileExists(contentOrFile))
                    throw new ArgumentException(ResourceUtilities.FormatResourceStringStripCodeAndKeyword("Xaml.RuleFileNotFound", contentOrFile));

                return ParseXamlDocument(new StreamReader(contentOrFile), desiredRule);
            }

            // On Windows, xml content string is not a valid path, so, maybeFullPath == null
            // On Unix, xml content string would be a valid path, so, maybeFullPath != null
            if (maybeFullPath == null)
                // Unable to convert to a path, parse as XML
                return ParseXamlDocument(new StringReader(contentOrFile), desiredRule);

            if (FileSystems.Default.FileExists(maybeFullPath))
                // file found, parse as a file
                return ParseXamlDocument(new StreamReader(maybeFullPath), desiredRule);

            // @maybeFullPath is either:
            //  - a non-existent fullpath
            //  - or xml content with the current dir prepended (like "/foo/bar/<abc .. />"),
            //    but not on Windows
            //
            // On Windows, this means that @contentOrFile is really a non-existant file name
            if (NativeMethodsShared.IsWindows)
                throw new ArgumentException(ResourceUtilities.FormatResourceStringStripCodeAndKeyword("Xaml.RuleFileNotFound", maybeFullPath));
            else // On !Windows, try parsing as XML
                return ParseXamlDocument(new StringReader(contentOrFile), desiredRule);
        }

        /// <summary>
        /// Parse a Xaml document from a TextReader
        /// </summary>
        internal bool ParseXamlDocument(TextReader reader, string desiredRule)
        {
            ErrorUtilities.VerifyThrowArgumentNull(reader, nameof(reader));
            ErrorUtilities.VerifyThrowArgumentLength(desiredRule, nameof(desiredRule));

            object rootObject = XamlServices.Load(reader);
            if (rootObject != null)
            {
                XamlTypes.ProjectSchemaDefinitions schemas = rootObject as XamlTypes.ProjectSchemaDefinitions;
                if (schemas != null)
                {
                    foreach (XamlTypes.IProjectSchemaNode node in schemas.Nodes)
                    {
                        XamlTypes.Rule rule = node as XamlTypes.Rule;
                        if (rule != null)
                        {
                            if (String.Equals(rule.Name, desiredRule, StringComparison.OrdinalIgnoreCase))
                            {
                                return ParseXamlDocument(rule);
                            }
                        }
                    }

                    throw new XamlParseException(ResourceUtilities.FormatResourceStringStripCodeAndKeyword("Xaml.RuleNotFound", desiredRule));
                }
                else
                {
                    throw new XamlParseException(ResourceUtilities.GetResourceString("Xaml.InvalidRootObject"));
                }
            }

            return false;
        }

        /// <summary>
        /// Parse a Xaml document from a rule
        /// </summary>
        internal bool ParseXamlDocument(XamlTypes.Rule rule)
        {
            if (rule == null)
            {
                return false;
            }

            DefaultPrefix = rule.SwitchPrefix;

            ToolName = rule.ToolName;
            GeneratedTaskName = rule.Name;

            // Dictionary of property name strings to property objects. If a property is in the argument list of the current property then we want to make sure
            // that the argument property is a dependency of the current property.

            // As properties are parsed they are added to this dictionary so that after we can find the property instances from the names quickly.
            var argumentDependencyLookup = new Dictionary<string, Property>(StringComparer.OrdinalIgnoreCase);

            // baseClass = attribute.InnerText;
            // namespaceValue = attribute.InnerText;
            // resourceNamespaceValue = attribute.InnerText;
            foreach (XamlTypes.BaseProperty property in rule.Properties)
            {
                if (!ParseParameterGroupOrParameter(property, Properties, null, argumentDependencyLookup /*Add to the dictionary properties as they are parsed*/))
                {
                    return false;
                }
            }

            // Go through each property and their arguments to set up the correct dependency mappings.
            foreach (Property property in Properties)
            {
                // Get the arguments on the property itself
                List<Argument> arguments = property.Arguments;

                // Find all of the properties in arguments list.
                foreach (Argument argument in arguments)
                {
                    if (argumentDependencyLookup.TryGetValue(argument.Parameter, out Property argumentProperty))
                    {
                        property.DependentArgumentProperties.AddLast(argumentProperty);
                    }
                }

                // Properties may be enumeration types, this would mean they have sub property values which themselves can have arguments.
                List<Value> values = property.Values;

                // Find all of the properties for the aruments in sub property.
                foreach (Value value in values)
                {
                    List<Argument> valueArguments = value.Arguments;
                    foreach (Argument argument in valueArguments)
                    {
                        if (argumentDependencyLookup.TryGetValue(argument.Parameter, out Property argumentProperty))
                        {
                            // If the property contains a value sub property that has a argument then we will declare that the original property has the same dependenecy.
                            property.DependentArgumentProperties.AddLast(argumentProperty);
                        }
                    }
                }
            }

            return true;
        }

        /// <summary>
        /// Reads in the nodes of the xml file one by one and builds the data structure of all existing properties
        /// </summary>
        private bool ParseParameterGroupOrParameter(XamlTypes.BaseProperty baseProperty, LinkedList<Property> propertyList, Property property, Dictionary<string, Property> argumentDependencyLookup)
        {
            // node is a property
            if (!ParseParameter(baseProperty, propertyList, property, argumentDependencyLookup))
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// Fills in the property data structure
        /// </summary>
        private bool ParseParameter(XamlTypes.BaseProperty baseProperty, LinkedList<Property> propertyList, Property property, Dictionary<string, Property> argumentDependencyLookup)
        {
            Property propertyToAdd = ObtainAttributes(baseProperty, property);

            if (String.IsNullOrEmpty(propertyToAdd.Name))
            {
                propertyToAdd.Name = "AlwaysAppend";
            }

            // generate the list of parameters in order
            if (!_switchOrderList.Contains(propertyToAdd.Name))
            {
                _switchOrderList.Add(propertyToAdd.Name);
            }
            else
            {
                throw new XamlParseException(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("Xaml.DuplicatePropertyName", propertyToAdd.Name));
            }

            // Inherit the Prefix from the Tool
            if (String.IsNullOrEmpty(propertyToAdd.Prefix))
            {
                propertyToAdd.Prefix = DefaultPrefix;
            }

            // If the property is an enum type, parse that.
            XamlTypes.EnumProperty enumProperty = baseProperty as XamlTypes.EnumProperty;
            if (enumProperty != null)
            {
                foreach (XamlTypes.EnumValue enumValue in enumProperty.AdmissibleValues)
                {
                    var value = new Value
                    {
                        Name = enumValue.Name,
                        SwitchName = enumValue.Switch
                    };

                    if (value.SwitchName == null)
                    {
                        value.SwitchName = String.Empty;
                    }

                    value.DisplayName = enumValue.DisplayName;
                    value.Description = enumValue.Description;
                    value.Prefix = enumValue.SwitchPrefix;
                    if (String.IsNullOrEmpty(value.Prefix))
                    {
                        value.Prefix = enumProperty.SwitchPrefix;
                    }

                    if (String.IsNullOrEmpty(value.Prefix))
                    {
                        value.Prefix = DefaultPrefix;
                    }

                    if (enumValue.Arguments.Count > 0)
                    {
                        value.Arguments = new List<Argument>();
                        foreach (XamlTypes.Argument argument in enumValue.Arguments)
                        {
                            var arg = new Argument
                            {
                                Parameter = argument.Property,
                                Separator = argument.Separator,
                                Required = argument.IsRequired
                            };
                            value.Arguments.Add(arg);
                        }
                    }

                    if (value.Prefix == null)
                    {
                        value.Prefix = propertyToAdd.Prefix;
                    }

                    propertyToAdd.Values.Add(value);
                }
            }

            // build the dependencies and the values for a parameter
            foreach (XamlTypes.Argument argument in baseProperty.Arguments)
            {
                // To refactor into a separate func
                if (propertyToAdd.Arguments == null)
                {
                    propertyToAdd.Arguments = new List<Argument>();
                }

                var arg = new Argument
                {
                    Parameter = argument.Property,
                    Separator = argument.Separator,
                    Required = argument.IsRequired
                };
                propertyToAdd.Arguments.Add(arg);
            }

            if (argumentDependencyLookup?.ContainsKey(propertyToAdd.Name) == false)
            {
                argumentDependencyLookup.Add(propertyToAdd.Name, propertyToAdd);
            }

            // We've read any enumerated values and any dependencies, so we just 
            // have to add the property
            propertyList.AddLast(propertyToAdd);
            return true;
        }

        /// <summary>
        /// Gets all the attributes assigned in the xml file for this parameter or all of the nested switches for 
        /// this parameter group
        /// </summary>
        private static Property ObtainAttributes(XamlTypes.BaseProperty baseProperty, Property parameterGroup)
        {
            Property parameter;
            if (parameterGroup != null)
            {
                parameter = parameterGroup.Clone();
            }
            else
            {
                parameter = new Property();
            }

            XamlTypes.BoolProperty boolProperty = baseProperty as XamlTypes.BoolProperty;
            XamlTypes.DynamicEnumProperty dynamicEnumProperty = baseProperty as XamlTypes.DynamicEnumProperty;
            XamlTypes.EnumProperty enumProperty = baseProperty as XamlTypes.EnumProperty;
            XamlTypes.IntProperty intProperty = baseProperty as XamlTypes.IntProperty;
            XamlTypes.StringProperty stringProperty = baseProperty as XamlTypes.StringProperty;
            XamlTypes.StringListProperty stringListProperty = baseProperty as XamlTypes.StringListProperty;

            parameter.IncludeInCommandLine = baseProperty.IncludeInCommandLine;

            if (baseProperty.Name != null)
            {
                parameter.Name = baseProperty.Name;
            }

            if (boolProperty != null && !String.IsNullOrEmpty(boolProperty.ReverseSwitch))
            {
                parameter.Reversible = "true";
            }

            // Determine the type for this property.
            if (boolProperty != null)
            {
                parameter.Type = PropertyType.Boolean;
            }
            else if (enumProperty != null)
            {
                parameter.Type = PropertyType.String;
            }
            else if (dynamicEnumProperty != null)
            {
                parameter.Type = PropertyType.String;
            }
            else if (intProperty != null)
            {
                parameter.Type = PropertyType.Integer;
            }
            else if (stringProperty != null)
            {
                parameter.Type = PropertyType.String;
            }
            else if (stringListProperty != null)
            {
                parameter.Type = PropertyType.StringArray;
            }

            // We might need to override this type based on the data source, if it specifies a source type of 'Item'.
            if (baseProperty.DataSource != null)
            {
                if (!String.IsNullOrEmpty(baseProperty.DataSource.SourceType))
                {
                    if (baseProperty.DataSource.SourceType.Equals("Item", StringComparison.OrdinalIgnoreCase))
                    {
                        parameter.Type = PropertyType.ItemArray;
                    }
                }
            }

            if (intProperty != null)
            {
                parameter.Max = intProperty.MaxValue?.ToString();
                parameter.Min = intProperty.MinValue?.ToString();
            }

            if (boolProperty != null)
            {
                parameter.ReverseSwitchName = boolProperty.ReverseSwitch;
            }

            if (baseProperty.Switch != null)
            {
                parameter.SwitchName = baseProperty.Switch;
            }

            if (stringListProperty != null)
            {
                parameter.Separator = stringListProperty.Separator;
            }

            if (baseProperty.Default != null)
            {
                parameter.DefaultValue = baseProperty.Default;
            }

            parameter.Required = baseProperty.IsRequired.ToString().ToLower(CultureInfo.InvariantCulture);

            if (baseProperty.Category != null)
            {
                parameter.Category = baseProperty.Category;
            }

            if (baseProperty.DisplayName != null)
            {
                parameter.DisplayName = baseProperty.DisplayName;
            }

            if (baseProperty.Description != null)
            {
                parameter.Description = baseProperty.Description;
            }

            if (baseProperty.SwitchPrefix != null)
            {
                parameter.Prefix = baseProperty.SwitchPrefix;
            }

            return parameter;
        }
    }
}


<|start_filename|>src/Build/ObjectModelRemoting/DefinitionObjectsLinks/ProjectMetadataLink.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;

namespace Microsoft.Build.ObjectModelRemoting
{
    /// <summary>
    /// External projects support.
    /// Allow for creating a local representation to external object of type <see cref="ProjectMetadata"/>
    /// </summary>
    public abstract class ProjectMetadataLink
    {
        /// <summary>
        /// MSBuild object that this meta data belong to.
        /// Can be either <see cref="ProjectItem"/>, or <see cref="ProjectItemDefinition"/>
        /// Not a public property on original ProjectMetadata object, but int is needed to create a local proxy object.
        /// </summary>
        public abstract object Parent { get; }

        /// <summary>
        /// Access to remote <see cref="ProjectMetadata.Xml"/>.
        /// </summary>
        public abstract ProjectMetadataElement Xml { get; }

        /// <summary>
        /// Access to remote <see cref="ProjectMetadata.EvaluatedValueEscaped"/>.
        /// </summary>
        public abstract string EvaluatedValueEscaped { get; }

        /// <summary>
        /// Access to remote <see cref="ProjectMetadata.Predecessor"/>.
        /// </summary>
        public abstract ProjectMetadata Predecessor { get; }

        /// <summary>
        /// Helper utility for External projects provider implementation to get access of the parent object.
        /// At this point this is internal property for <see cref="ProjectMetadata"/>.
        /// </summary>
        public static object GetParent(ProjectMetadata metadata)
        {
            return metadata?.Parent;
        }

        /// <summary>
        /// Helper utility for External projects provider implementation to get access of the EvaluatedValueEscaped
        /// </summary>
        public static string GetEvaluatedValueEscaped(ProjectMetadata metadata)
        {
            return metadata.EvaluatedValueEscaped;
        }
    }
}


<|start_filename|>src/Build.OM.UnitTests/ObjectModelRemoting/Helpers/ViewValidation.construction.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.Build.UnitTests.OM.ObjectModelRemoting
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.Build.Construction;
    using Microsoft.Build.ObjectModelRemoting;
    using Microsoft.Build.Evaluation;
    using Xunit;
    using System.Collections;

    internal class ElementLinkPair<T> : LinkPair<T>
        where T : ProjectElement
    {
        public ProjectXmlPair PRE { get; protected set; }

        public ElementLinkPair(ProjectXmlPair pre, T view, T real) : base(view, real) { this.PRE = pre; }

        // the PRE.CreateXX(), AppendChild, way.
        public ElementLinkPair<CT> AppendNewChaildWithVerify<CT>(ObjectType where, string id, Func<ProjectRootElement, string, CT> adder, Func<CT, string, bool> matcher)
            where CT : ProjectElement
        {
            var appendWhere = this.Get(where) as ProjectElementContainer;
            Assert.NotNull(appendWhere);

            var c1Where = adder(this.PRE.Get(where), id);
            Assert.NotNull(c1Where);
            appendWhere.AppendChild(c1Where);

            var c1 = this.QuerySingleChildrenWithValidation<CT>((t) => matcher(t, id));
            Assert.Same(c1Where, c1.Get(where));

            return c1;
        }

        public ElementLinkPair<CT> AppendNewNamedChaildWithVerify<CT>(ObjectType where, string name, Func<ProjectRootElement, string, CT> adder)
            where CT : ProjectElement
            => AppendNewChaildWithVerify(where, name, adder, (c, n) => string.Equals(c.ElementName, n));

        public ElementLinkPair<CT> AppendNewLabeledChaildWithVerify<CT>(ObjectType where, string label, Func<ProjectRootElement, string, CT> adder)
            where CT : ProjectElement
            => AppendNewChaildWithVerify(where, label,
                (t, l) =>
                {
                    var ct = adder(t, l);
                    Assert.NotNull(ct);
                    ct.Label = l;
                    return ct;
                },
                (c, l) => string.Equals(c.Label, l));

        // if the element has a dedicated "addX" way.
        public ElementLinkPair<CT> AddNewChaildWithVerify<CT>(ObjectType where, string id, Func<T, string, CT> adder, Func<CT, string, bool> matcher)
            where CT : ProjectElement
        {
            var c1Where = adder(this.Get(where), id);
            Assert.NotNull(c1Where);

            var c1 = this.QuerySingleChildrenWithValidation<CT>((t) => matcher(t, id));
            Assert.Same(c1Where, c1.Get(where));

            return c1;
        }

        public ElementLinkPair<CT> AddNewNamedChaildWithVerify<CT>(ObjectType where, string name, Func<T, string, CT> adder)
            where CT : ProjectElement
            => AddNewChaildWithVerify(where, name, adder, (c, n) => string.Equals(c.ElementName, n));

        public ElementLinkPair<CT> AddNewLabeledChaildWithVerify<CT>(ObjectType where, string label, Func<T, string, CT> adder)
            where CT : ProjectElement
            => AddNewChaildWithVerify(where, label,
                (t, l)=>
                {
                    var ct = adder(t, l);
                    Assert.NotNull(ct);
                    ct.Label = l;
                    return ct;
                },
                (c, l) => string.Equals(c.Label, l));

        public void Append2NewChildrenWithVerify<CT>(string id, Func<ProjectRootElement, string, CT> adder, Func<CT, string, bool> matcher, out ElementLinkPair<CT> c1, out ElementLinkPair<CT> c2)
            where CT : ProjectElement
        {
            c1 = AppendNewChaildWithVerify(ObjectType.View, id.Ver(1), adder, matcher);
            c2 = AppendNewChaildWithVerify(ObjectType.Real, id.Ver(2), adder, matcher);
        }

        public void Append2NewNamedChildrenWithVerify<CT>(string name, Func<ProjectRootElement, string, CT> adder, out ElementLinkPair<CT> c1, out ElementLinkPair<CT> c2)
            where CT : ProjectElement
        {
            c1 = AppendNewNamedChaildWithVerify(ObjectType.View, name.Ver(1), adder);
            c2 = AppendNewNamedChaildWithVerify(ObjectType.Real, name.Ver(2), adder);
        }

        public void Append2NewLabeledChildrenWithVerify<CT>(string label, Func<ProjectRootElement, string, CT> adder, out ElementLinkPair<CT> c1, out ElementLinkPair<CT> c2)
            where CT : ProjectElement
        {
            c1 = AppendNewLabeledChaildWithVerify(ObjectType.View, label.Ver(1), adder);
            c2 = AppendNewLabeledChaildWithVerify(ObjectType.Real, label.Ver(2), adder);
        }

        public void Add2NewChildrenWithVerify<CT>(string id, Func<T, string, CT> adder, Func<CT, string, bool> matcher, out ElementLinkPair<CT> c1, out ElementLinkPair<CT> c2)
            where CT : ProjectElement
        {
            c1 = AddNewChaildWithVerify(ObjectType.View, id.Ver(1), adder, matcher);
            c2 = AddNewChaildWithVerify(ObjectType.Real, id.Ver(2), adder, matcher);
        }

        public void Add2NewNamedChildrenWithVerify<CT>(string name, Func<T, string, CT> adder, out ElementLinkPair<CT> c1, out ElementLinkPair<CT> c2)
            where CT : ProjectElement
        {
            c1 = AddNewNamedChaildWithVerify(ObjectType.View, name.Ver(1), adder);
            c2 = AddNewNamedChaildWithVerify(ObjectType.Real, name.Ver(2), adder);
        }

        public void Add2NewLabeledChildrenWithVerify<CT>(string label, Func<T, string, CT> adder, out ElementLinkPair<CT> c1, out ElementLinkPair<CT> c2)
            where CT : ProjectElement
        {
            c1 = AddNewLabeledChaildWithVerify(ObjectType.View, label.Ver(1), adder);
            c2 = AddNewLabeledChaildWithVerify(ObjectType.Real, label.Ver(2), adder);
        }


        public ICollection<ElementLinkPair<CT>> QueryChildrenWithValidation<CT>(Func<CT, bool> matcher, int expectedCount)
            where CT : ProjectElement
        {
            var result = QueryChildrenWithValidation(matcher);
            Assert.Equal(expectedCount, result.Count);
            return result;
        }

        public ICollection<ElementLinkPair<CT>> QueryChildrenWithValidation<CT>(Func<T, IEnumerable> getter, Func<CT, bool> matcher, int expectedCount)
            where CT : ProjectElement
        {
            var result = QueryChildrenWithValidation(getter, matcher);
            Assert.Equal(expectedCount, result.Count);
            return result;
        }

        public ICollection<ElementLinkPair<CT>> QueryChildrenWithValidation<CT>(Func<T,IEnumerable> getter,  Func<CT, bool> matcher)
            where CT : ProjectElement
        {
            var viewResult = new List<CT>();
            var realResult = new List<CT>();
            var finalResult = new List<ElementLinkPair<CT>>();

            foreach (var v in getter(this.View))
            {
                if (v is CT vt)
                {
                    if (matcher(vt))
                    {
                        viewResult.Add(vt);
                    }
                }
            }

            foreach (var r in getter(this.Real))
            {
                if (r is CT rt)
                {
                    if (matcher(rt))
                    {
                        realResult.Add(rt);
                    }
                }
            }
            // slow form view VerifyFindType, since we dont know the T.
            ViewValidation.Verify(viewResult, realResult);

            for (int i = 0; i < viewResult.Count; i++)
            {
                finalResult.Add(new ElementLinkPair<CT>(this.PRE, viewResult[i], realResult[i]));
            }

            return finalResult;
        }

        public ICollection<ElementLinkPair<CT>> QueryChildrenWithValidation<CT>(Func<CT, bool> matcher)
            where CT : ProjectElement
        {
            Assert.True(this.View is ProjectElementContainer);
            Assert.True(this.Real is ProjectElementContainer);

            return QueryChildrenWithValidation((t) => (t as ProjectElementContainer).AllChildren, matcher);
        }

        public ElementLinkPair<CT> QuerySingleChildrenWithValidation<CT>(Func<CT, bool> matcher)
            where CT : ProjectElement
        {
            var result = QueryChildrenWithValidation(matcher, 1);
            return result.FirstOrDefault();
        }

        public ElementLinkPair<CT> QuerySingleChildrenWithValidation<CT>(Func<T, IEnumerable> getter, Func<CT, bool> matcher)
            where CT : ProjectElement
        {
            var result = QueryChildrenWithValidation(getter, matcher, 1);
            return result.FirstOrDefault();
        }
    }

    internal class ProjectXmlPair : ElementLinkPair<ProjectRootElement>
    {
        ProjectPair Project { get; }
        public ProjectXmlPair(ProjectPair pair) : base(null, pair.View.Xml, pair.Real.Xml) { this.Project = pair; this.PRE = this; }
        public ProjectXmlPair(ProjectRootElement viewXml, ProjectRootElement realXml) : base(null, viewXml, realXml) { this.PRE = this; }

        public ElementLinkPair<CT> CreateWithVerify<CT>(Func<ProjectRootElement, CT> creator)
            where CT : ProjectElement
        {
            var view = creator(this.View);
            Assert.NotNull(view);
            var real = creator(this.Real);
            Assert.NotNull(real);
            ViewValidation.VerifyFindType(view, real);
            return new ElementLinkPair<CT>(this, view, real);
        }

        public ElementLinkPair<CT> CreateFromView<CT>(CT view)
            where CT : ProjectElement
            => CreateFromView(view, this);
        public static ElementLinkPair<CT> CreateFromView<CT>(CT view, ProjectXmlPair pre = null)
            where CT : ProjectElement
        {
            var real = ViewValidation.GetRealObject(view);
            return new ElementLinkPair<CT>(pre, view, real);
        }
    }


    internal static partial class ViewValidation
    {
        public static string Ver(this string str, int ver) => $"{str}_{ver}";
        public static string Ver(this string str, int ver, int subver) => $"{str}_{ver}_{subver}";

        public static void VerifySameLocationWithException(Func<ElementLocation> expectedGetter, Func<ElementLocation> actualGetter, ValidationContext context = null)
        {
            Assert.Equal(GetWithExceptionCheck(expectedGetter, out var expected), GetWithExceptionCheck(actualGetter, out var actual));
            VerifySameLocation(expected, actual, context);
        }

        public static void VerifySameLocation(ElementLocation expected, ElementLocation actual, ValidationContext context = null)
        {
            if (object.ReferenceEquals(expected, actual)) return;

            if (context?.ValidateLocation != null)
            {
                context.ValidateLocation(expected, actual);
                return;
            }

            Assert.NotNull(expected);
            Assert.NotNull(actual);

            Assert.Equal(expected.File, actual.File);
            Assert.Equal(expected.Line, actual.Line);
            Assert.Equal(expected.Column, actual.Column);
        }

        public static bool IsLinkedObject(object obj)
        {
            return LinkedObjectsFactory.GetLink(obj) != null;
        }

        private static bool dbgIgnoreLinked = false; 
        public static void VerifyNotLinked(object obj)
        {
            if (dbgIgnoreLinked) return;
            Assert.True(obj == null || !IsLinkedObject(obj));
        }

        // note this is a cheat, it relies on Mock implementation knowledge and that we are in the same process.
        public static T GetRealObject<T>(T view)
            where T : class
        {
            if (view == null) return null;
            if (!IsLinkedObject(view)) return view;

            var link = LinkedObjectsFactory.GetLink(view) as ILinkMock;
            Assert.NotNull(link);
            var remoter = link.Remoter as IRemoterSource;
            Assert.NotNull(remoter);
            var real = remoter.RealObject as T;
            Assert.NotNull(real);
            VerifyFindType(view, real);
            return real;
        }

        public static void VerifyLinked(object obj)
        {
            if (dbgIgnoreLinked) return;
            Assert.True(obj == null || IsLinkedObject(obj));
        }


        public static void VerifyNotNull(object obj, bool linked)
        {
            Assert.NotNull(obj);
            if (dbgIgnoreLinked) return;
            Assert.Equal(linked, IsLinkedObject(obj));
        }

        public static void VerifyNotLinkedNotNull(object obj)
        {
            Assert.NotNull(obj);
            if (dbgIgnoreLinked) return;
            Assert.True(!IsLinkedObject(obj));
        }

        public static void VerifyLinkedNotNull(object obj)
        {
            Assert.NotNull(obj);
            if (dbgIgnoreLinked) return;
            Assert.True(IsLinkedObject(obj));
        }

        public static bool GetWithExceptionCheck<T>(Func<T> getter, out T result)
        {
            try
            {
                result = getter();
                return true;
            }
            catch
            {
                result = default(T);
                return false;
            }
        }

        public static void ValidateEqualWithException<T>(Func<T> viewGetter, Func<T> realGetter, ValidationContext context = null)
        {
            bool viewOk = GetWithExceptionCheck(viewGetter, out T viewValue);
            bool realOk = GetWithExceptionCheck(realGetter, out T realValue);
            Assert.Equal(realOk, viewOk);
            Assert.Equal(realValue, viewValue);
        }


        private static void VerifyProjectElementViewInternal(ProjectElement viewXml, ProjectElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;

            VerifyLinkedNotNull(viewXml);
            VerifyNotLinkedNotNull(realXml);

            Assert.Equal(realXml.OuterElement, viewXml.OuterElement);

            VerifySameLocation(realXml.LabelLocation, viewXml.LabelLocation, context);

            VerifySameLocationWithException(()=>realXml.ConditionLocation, ()=>viewXml.ConditionLocation, context);

            VerifyNotLinked(realXml.ContainingProject);
            VerifyLinked(viewXml.ContainingProject);

            VerifyNotLinked(realXml.NextSibling);
            VerifyLinked(viewXml.NextSibling);

            VerifyNotLinked(realXml.PreviousSibling);
            VerifyLinked(viewXml.PreviousSibling);

            // skip AllParents, parent validation should cover it.
            VerifySameLocation(realXml.Location, viewXml.Location, context);

            Assert.Equal(realXml.ElementName, viewXml.ElementName);
            Assert.Equal(realXml.Label, viewXml.Label);

            ValidateEqualWithException(() => viewXml.Condition, () => realXml.Condition);

            VerifyNotLinked(realXml.Parent);
            VerifyLinked(viewXml.Parent);
        }


        private static void VerifyProjectElementContainerView(ProjectElementContainer viewXml, ProjectElementContainer realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElementViewInternal(viewXml, realXml, context);

            Assert.Equal(realXml.Count, viewXml.Count);

            VerifyNotLinked(realXml.FirstChild);
            VerifyLinked(viewXml.FirstChild);

            VerifyNotLinked(realXml.LastChild);
            VerifyLinked(viewXml.LastChild);

            var realChild = realXml.FirstChild;
            var viewChild = viewXml.FirstChild;

            while (realChild != null )
            {
                Assert.NotNull(viewChild);
                Assert.Same(realChild.Parent, realXml);

                if (!object.ReferenceEquals(viewChild.Parent, viewXml))
                {
                    var lm = LinkedObjectsFactory.GetLink(viewXml) as ILinkMock;
                    lm.Linker.ValidateNoDuplicates();
                }

                Assert.Same(viewChild.Parent, viewXml);

                if (realChild is ProjectElementContainer realChildContainer)
                {
                    Assert.True(viewChild is ProjectElementContainer);

                    VerifyProjectElementContainerView((ProjectElementContainer)viewChild, realChildContainer, context);
                }
                else
                {
                    Assert.False(viewChild is ProjectElementContainer);
                    VerifyProjectElementViewInternal(viewChild, realChild, context);
                }

                realChild = realChild.NextSibling;
                viewChild = viewChild.NextSibling;
            }

            Assert.Null(viewChild);
        }

        public static void VerifyProjectCollectionLinks(this ProjectCollectionLinker linker, string path, int expectedLocal, int expectedLinks)
            => VerifyProjectCollectionLinks(linker.Collection, path, expectedLocal, expectedLinks);

        public static void VerifyProjectCollectionLinks(this ProjectCollection collection, string path, int expectedLocal, int expectedLinks)
            => VerifyProjectCollectionLinks(collection.GetLoadedProjects(path), expectedLocal, expectedLinks);

        public static void VerifyProjectCollectionLinks(IEnumerable<Project> projects, int expectedLocal, int expectedLinks)
        {
            HashSet<Project> remotes = new HashSet<Project>();
            int actualLocal = 0;
            int actualLinks = 0;
            foreach (var prj in projects)
            {
                Assert.NotNull(prj);
                if (IsLinkedObject(prj))
                {
                    Assert.DoesNotContain(prj, remotes);
                    actualLinks++;
                    remotes.Add(prj);
                }
                else
                {
                    actualLocal++;
                }
            }

            Assert.Equal(expectedLocal, actualLocal);
            Assert.Equal(expectedLinks, actualLinks);
        }


        public static void VerifyProjectElement(ProjectElement viewXml, ProjectElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;

            if (viewXml is ProjectElementContainer viewContainer)
            {
                Assert.True(realXml is ProjectElementContainer);
                VerifyProjectElementContainerView(viewContainer, (ProjectElementContainer)realXml, context);
            }
            else
            {
                Assert.False(realXml is ProjectElementContainer);
                VerifyProjectElementViewInternal(viewXml, realXml, context);
            }
        }

        public static void Verify(ProjectRootElement viewXml, ProjectRootElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);

            Assert.Equal(realXml.FullPath, viewXml.FullPath);
            Assert.Equal(realXml.DirectoryPath, viewXml.DirectoryPath);
            Assert.Equal(realXml.Encoding, viewXml.Encoding);
            Assert.Equal(realXml.DefaultTargets, viewXml.DefaultTargets);
            Assert.Equal(realXml.InitialTargets, viewXml.InitialTargets);
            Assert.Equal(realXml.Sdk, viewXml.Sdk);
            Assert.Equal(realXml.TreatAsLocalProperty, viewXml.TreatAsLocalProperty);
            Assert.Equal(realXml.ToolsVersion, viewXml.ToolsVersion);
            Assert.Equal(realXml.HasUnsavedChanges, viewXml.HasUnsavedChanges);
            Assert.Equal(realXml.PreserveFormatting, viewXml.PreserveFormatting);
            Assert.Equal(realXml.Version, viewXml.Version);
            Assert.Equal(realXml.TimeLastChanged, viewXml.TimeLastChanged);
            Assert.Equal(realXml.LastWriteTimeWhenRead, viewXml.LastWriteTimeWhenRead);

            ViewValidation.VerifySameLocation(realXml.ProjectFileLocation, viewXml.ProjectFileLocation, context);
            ViewValidation.VerifySameLocation(realXml.ToolsVersionLocation, viewXml.ToolsVersionLocation, context);
            ViewValidation.VerifySameLocation(realXml.DefaultTargetsLocation, viewXml.DefaultTargetsLocation, context);
            ViewValidation.VerifySameLocation(realXml.InitialTargetsLocation, viewXml.InitialTargetsLocation, context);
            ViewValidation.VerifySameLocation(realXml.SdkLocation, viewXml.SdkLocation, context);
            ViewValidation.VerifySameLocation(realXml.TreatAsLocalPropertyLocation, viewXml.TreatAsLocalPropertyLocation, context);

            ViewValidation.Verify(viewXml.ChooseElements, realXml.ChooseElements, Verify, context);
            ViewValidation.Verify(viewXml.ItemDefinitionGroups, realXml.ItemDefinitionGroups, Verify, context);
            ViewValidation.Verify(viewXml.ItemDefinitions, realXml.ItemDefinitions, Verify, context);
            ViewValidation.Verify(viewXml.ItemGroups, realXml.ItemGroups, Verify, context);
            ViewValidation.Verify(viewXml.Items, realXml.Items, Verify, context);
            ViewValidation.Verify(viewXml.ImportGroups, realXml.ImportGroups, Verify, context);
            ViewValidation.Verify(viewXml.Imports, realXml.Imports, Verify, context);
            ViewValidation.Verify(viewXml.PropertyGroups, realXml.PropertyGroups, Verify, context);
            ViewValidation.Verify(viewXml.Properties, realXml.Properties, Verify, context);
            ViewValidation.Verify(viewXml.Targets, realXml.Targets, Verify, context);
            ViewValidation.Verify(viewXml.UsingTasks, realXml.UsingTasks, Verify, context);
            ViewValidation.Verify(viewXml.ItemGroupsReversed, realXml.ItemGroupsReversed, Verify, context);
            ViewValidation.Verify(viewXml.ItemDefinitionGroupsReversed, realXml.ItemDefinitionGroupsReversed, Verify, context);
            ViewValidation.Verify(viewXml.ImportGroupsReversed, realXml.ImportGroupsReversed, Verify, context);
            ViewValidation.Verify(viewXml.PropertyGroupsReversed, realXml.PropertyGroupsReversed, Verify, context);
        }

        public static void Verify(ProjectChooseElement viewXml, ProjectChooseElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);


            Verify(viewXml.WhenElements, realXml.WhenElements, Verify, context);
            Verify(viewXml.OtherwiseElement, realXml.OtherwiseElement, context);
        }

        public static void Verify(ProjectWhenElement viewXml, ProjectWhenElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);


            Verify(viewXml.ChooseElements, realXml.ChooseElements, context);
            Verify(viewXml.ItemGroups, realXml.ItemGroups, context);
            Verify(viewXml.PropertyGroups, realXml.PropertyGroups, context);
        }

        public static void Verify(ProjectOtherwiseElement viewXml, ProjectOtherwiseElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);


            Verify(viewXml.ChooseElements, realXml.ChooseElements, context);
            Verify(viewXml.ItemGroups, realXml.ItemGroups, context);
            Verify(viewXml.PropertyGroups, realXml.PropertyGroups, context);
        }

        public static void Verify(ProjectExtensionsElement viewXml, ProjectExtensionsElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);

            Assert.Equal(realXml.Content, viewXml.Content);
        }

        public static void Verify(ProjectMetadataElement viewXml, ProjectMetadataElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);

            Assert.Equal(realXml.Name, viewXml.Name);
            Assert.Equal(realXml.Value, viewXml.Value);
            Assert.Equal(realXml.ExpressedAsAttribute, viewXml.ExpressedAsAttribute);
        }

        public static void Verify(ProjectTaskElement viewXml, ProjectTaskElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);

            Assert.Equal(realXml.Name, viewXml.Name);

            Assert.Equal(realXml.ContinueOnError, viewXml.ContinueOnError);
            ViewValidation.VerifySameLocation(realXml.ContinueOnErrorLocation, viewXml.ContinueOnErrorLocation, context);
            Assert.Equal(realXml.MSBuildRuntime, viewXml.MSBuildRuntime);
            ViewValidation.VerifySameLocation(realXml.MSBuildRuntimeLocation, viewXml.MSBuildRuntimeLocation, context);

            Assert.Equal(realXml.MSBuildArchitecture, viewXml.MSBuildArchitecture);
            ViewValidation.VerifySameLocation(realXml.MSBuildArchitectureLocation, viewXml.MSBuildArchitectureLocation, context);

            ViewValidation.Verify(viewXml.Outputs, realXml.Outputs, ViewValidation.Verify, context);

            var realParams = realXml.Parameters;
            var viewParams = viewXml.Parameters;
            if (realParams == null)
            {
                Assert.Null(viewParams);
            }
            else
            {
                Assert.NotNull(viewParams);

                Assert.Equal(realParams.Count, viewParams.Count);
                foreach (var k in realParams.Keys)
                {
                    Assert.True(viewParams.ContainsKey(k));
                    Assert.Equal(realParams[k], viewParams[k]);
                }
            }

            var realParamsLoc = realXml.ParameterLocations;
            var viewParamsLoc = viewXml.ParameterLocations;
            if (realParamsLoc == null)
            {
                Assert.Null(viewParamsLoc);
            }
            else
            {
                Assert.NotNull(viewParamsLoc);

                var realPLocList = realParamsLoc.ToList();
                var viewPLocList = viewParamsLoc.ToList();

                Assert.Equal(realPLocList.Count, viewPLocList.Count);
                for (int li = 0; li < realPLocList.Count; li++)
                {
                    var rkvp = realPLocList[li];
                    var vkvp = viewPLocList[li];

                    Assert.Equal(rkvp.Key, vkvp.Key);
                    ViewValidation.VerifySameLocation(rkvp.Value, vkvp.Value, context);
                }
            }
        }

        public static void Verify(ProjectOutputElement viewXml, ProjectOutputElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);

            Assert.Equal(realXml.TaskParameter, viewXml.TaskParameter);
            VerifySameLocation(realXml.TaskParameterLocation, viewXml.TaskParameterLocation, context);
            Assert.Equal(realXml.IsOutputItem, viewXml.IsOutputItem);
            Assert.Equal(realXml.IsOutputProperty, viewXml.IsOutputProperty);
            Assert.Equal(realXml.ItemType, viewXml.ItemType);
            Assert.Equal(realXml.PropertyName, viewXml.PropertyName);
            VerifySameLocation(realXml.PropertyNameLocation, viewXml.PropertyNameLocation, context);
        }

        public static void Verify(ProjectUsingTaskBodyElement viewXml, ProjectUsingTaskBodyElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;

            VerifyProjectElement(viewXml, realXml, context);

            Assert.Equal(realXml.TaskBody, viewXml.TaskBody);
            Assert.Equal(realXml.Evaluate, viewXml.Evaluate);
            VerifySameLocation(realXml.EvaluateLocation, viewXml.EvaluateLocation, context);
        }

        public static void Verify(ProjectUsingTaskParameterElement viewXml, ProjectUsingTaskParameterElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;

            VerifyProjectElement(viewXml, realXml, context);

            Assert.Equal(realXml.Name, viewXml.Name);
            Assert.Equal(realXml.ParameterType, viewXml.ParameterType);
            VerifySameLocation(realXml.ParameterTypeLocation, viewXml.ParameterTypeLocation, context);
            Assert.Equal(realXml.Output, viewXml.Output);
            VerifySameLocation(realXml.OutputLocation, viewXml.OutputLocation, context);
            Assert.Equal(realXml.Required, viewXml.Required);
            VerifySameLocation(realXml.RequiredLocation, viewXml.RequiredLocation, context);
        }

        public static void Verify(UsingTaskParameterGroupElement viewXml, UsingTaskParameterGroupElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;

            VerifyProjectElement(viewXml, realXml, context);

            Verify(viewXml.Parameters, realXml.Parameters, Verify, context);
        }

        public static void Verify(ProjectUsingTaskElement viewXml, ProjectUsingTaskElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);


            Assert.Equal(realXml.AssemblyFile, viewXml.AssemblyFile);
            ViewValidation.VerifySameLocation(realXml.AssemblyFileLocation, viewXml.AssemblyFileLocation, context);

            Assert.Equal(realXml.AssemblyName, viewXml.AssemblyName);
            ViewValidation.VerifySameLocation(realXml.AssemblyNameLocation, viewXml.AssemblyNameLocation, context);

            Assert.Equal(realXml.TaskName, viewXml.TaskName);
            ViewValidation.VerifySameLocation(realXml.TaskNameLocation, viewXml.TaskNameLocation, context);

            Assert.Equal(realXml.TaskFactory, viewXml.TaskFactory);
            ViewValidation.VerifySameLocation(realXml.TaskFactoryLocation, viewXml.TaskFactoryLocation, context);

            Assert.Equal(realXml.Runtime, viewXml.Runtime);
            ViewValidation.VerifySameLocation(realXml.RuntimeLocation, viewXml.RuntimeLocation, context);

            Assert.Equal(realXml.Architecture, viewXml.Architecture);
            ViewValidation.VerifySameLocation(realXml.ArchitectureLocation, viewXml.ArchitectureLocation, context);

            ViewValidation.Verify(viewXml.TaskBody, realXml.TaskBody, context);
            ViewValidation.Verify(viewXml.ParameterGroup, realXml.ParameterGroup, context);
        }

        public static void Verify(ProjectTargetElement viewXml, ProjectTargetElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);


            Assert.Equal(realXml.Name, viewXml.Name);
            ViewValidation.VerifySameLocation(realXml.NameLocation, viewXml.NameLocation, context);
            Assert.Equal(realXml.Inputs, viewXml.Inputs);
            ViewValidation.VerifySameLocation(realXml.InputsLocation, viewXml.InputsLocation, context);
            Assert.Equal(realXml.Outputs, viewXml.Outputs);
            ViewValidation.VerifySameLocation(realXml.OutputsLocation, viewXml.OutputsLocation, context);
            Assert.Equal(realXml.KeepDuplicateOutputs, viewXml.KeepDuplicateOutputs);
            ViewValidation.VerifySameLocation(realXml.KeepDuplicateOutputsLocation, viewXml.KeepDuplicateOutputsLocation, context);
            Assert.Equal(realXml.DependsOnTargets, viewXml.DependsOnTargets);
            ViewValidation.VerifySameLocation(realXml.DependsOnTargetsLocation, viewXml.DependsOnTargetsLocation, context);
            Assert.Equal(realXml.BeforeTargets, viewXml.BeforeTargets);
            ViewValidation.VerifySameLocation(realXml.BeforeTargetsLocation, viewXml.BeforeTargetsLocation, context);
            Assert.Equal(realXml.AfterTargets, viewXml.AfterTargets);
            ViewValidation.VerifySameLocation(realXml.AfterTargetsLocation, viewXml.AfterTargetsLocation, context);
            Assert.Equal(realXml.Returns, viewXml.Returns);
            ViewValidation.VerifySameLocation(realXml.ReturnsLocation, viewXml.ReturnsLocation, context);

            ViewValidation.Verify(viewXml.ItemGroups, realXml.ItemGroups, ViewValidation.Verify, context);
            ViewValidation.Verify(viewXml.PropertyGroups, realXml.PropertyGroups, ViewValidation.Verify, context);
            ViewValidation.Verify(viewXml.OnErrors, realXml.OnErrors, ViewValidation.Verify, context);
            ViewValidation.Verify(viewXml.Tasks, realXml.Tasks, ViewValidation.Verify, context);
        }

        public static void Verify(ProjectImportElement viewXml, ProjectImportElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);


            Assert.Equal(realXml.Project, viewXml.Project);
            ViewValidation.VerifySameLocation(realXml.ProjectLocation, viewXml.ProjectLocation, context);

            // mostly test the remoting infrastructure. Sdk Imports are not really covered by simple samples for now.
            // Todo: add mock SDK import closure to SdtGroup?
            Assert.Equal(realXml.Sdk, viewXml.Sdk);
            Assert.Equal(realXml.Version, viewXml.Version);
            Assert.Equal(realXml.MinimumVersion, viewXml.MinimumVersion);
            ViewValidation.VerifySameLocation(realXml.SdkLocation, viewXml.SdkLocation, context);
            Assert.Equal(realXml.ImplicitImportLocation, viewXml.ImplicitImportLocation);
            ViewValidation.VerifyProjectElement(viewXml.OriginalElement, realXml.OriginalElement, context);
        }

        public static void Verify(ProjectImportGroupElement viewXml, ProjectImportGroupElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);

            ViewValidation.Verify(viewXml.Imports, realXml.Imports, ViewValidation.Verify, context);
        }

        public static void Verify(ProjectItemDefinitionElement viewXml, ProjectItemDefinitionElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);

            Assert.Equal(realXml.ItemType, viewXml.ItemType);
            ViewValidation.Verify(viewXml.Metadata, realXml.Metadata, ViewValidation.Verify, context);
        }

        public static void Verify(ProjectItemDefinitionGroupElement viewXml, ProjectItemDefinitionGroupElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);

            ViewValidation.Verify(viewXml.ItemDefinitions, realXml.ItemDefinitions, ViewValidation.Verify, context);
        }

        public static void Verify(ProjectItemElement viewXml, ProjectItemElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);

            Assert.Equal(realXml.ItemType, viewXml.ItemType);
            Assert.Equal(realXml.Include, viewXml.Include);
            Assert.Equal(realXml.Exclude, viewXml.Exclude);
            Assert.Equal(realXml.Remove, viewXml.Remove);
            Assert.Equal(realXml.Update, viewXml.Update);
            Assert.Equal(realXml.KeepMetadata, viewXml.KeepMetadata);
            Assert.Equal(realXml.RemoveMetadata, viewXml.RemoveMetadata);
            Assert.Equal(realXml.KeepDuplicates, viewXml.KeepDuplicates);
            Assert.Equal(realXml.HasMetadata, viewXml.HasMetadata);

           Verify(viewXml.Metadata, realXml.Metadata, ViewValidation.Verify, context);

           VerifySameLocation(realXml.IncludeLocation, viewXml.IncludeLocation, context);
           VerifySameLocation(realXml.ExcludeLocation, viewXml.ExcludeLocation, context);
           VerifySameLocation(realXml.RemoveLocation, viewXml.RemoveLocation, context);
           VerifySameLocation(realXml.UpdateLocation, viewXml.UpdateLocation, context);
           VerifySameLocation(realXml.KeepMetadataLocation, viewXml.KeepMetadataLocation, context);
           VerifySameLocation(realXml.RemoveMetadataLocation, viewXml.RemoveMetadataLocation, context);
           VerifySameLocation(realXml.KeepDuplicatesLocation, viewXml.KeepDuplicatesLocation, context);
        }

        public static void Verify(ProjectItemGroupElement viewXml, ProjectItemGroupElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);

            Verify(viewXml.Items, realXml.Items, Verify, context);
        }

        public static void Verify(ProjectPropertyElement viewXml, ProjectPropertyElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);

            Assert.Equal(realXml.Name, viewXml.Name);
            Assert.Equal(realXml.Value, viewXml.Value);
        }

        public static void Verify(ProjectPropertyGroupElement viewXml, ProjectPropertyGroupElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);
            Verify(viewXml.Properties, realXml.Properties, Verify, context);
            Verify(viewXml.PropertiesReversed, realXml.PropertiesReversed, Verify, context);
        }

        public static void Verify(ProjectSdkElement viewXml, ProjectSdkElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);
            Assert.Equal(realXml.Name, viewXml.Name);
            Assert.Equal(realXml.Version, viewXml.Version);
            Assert.Equal(realXml.MinimumVersion, viewXml.MinimumVersion);
        }

        public static void Verify(ProjectOnErrorElement viewXml, ProjectOnErrorElement realXml, ValidationContext context = null)
        {
            if (viewXml == null && realXml == null) return;
            VerifyProjectElement(viewXml, realXml, context);

            Assert.Equal(realXml.ExecuteTargetsAttribute, viewXml.ExecuteTargetsAttribute);
            VerifySameLocation(realXml.ExecuteTargetsLocation, viewXml.ExecuteTargetsLocation);
        }
    }
}


<|start_filename|>src/Build/BackEnd/Components/Logging/BuildEventArgTransportSink.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Generic;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;

namespace Microsoft.Build.BackEnd.Logging
{
    /// <summary>
    /// Delegate to a method which will transport the packet accross the wire.
    /// </summary>
    /// <param name="packetToSend">A node packet to send accross the wire</param>
    internal delegate void SendDataDelegate(INodePacket packetToSend);

    /// <summary>
    /// This class will consume the BuildEventArgs forwarded by the EventRedirectorToSink class.
    /// The sink will then create a packet and then pass this along to the transport layer to be
    /// sent back to the build manager.
    /// </summary>
    internal class BuildEventArgTransportSink : IBuildEventSink
    {
        #region Data
        /// <summary>
        /// Delegate to a method which accepts a INodePacket and send the packet to where it needs to go
        /// </summary>
        private SendDataDelegate _sendDataDelegate;
        #endregion

        #region Constructor

        /// <summary>
        /// Create the sink which will consume a buildEventArg
        /// Create a INodePacket and send it to the transport component
        /// </summary>
        /// <param name="sendData">A delegate which takes an INodePacket and sends the packet to where it needs to go</param>
        /// <exception cref="InternalErrorException">Send data delegate is null</exception>
        internal BuildEventArgTransportSink(SendDataDelegate sendData)
        {
            ErrorUtilities.VerifyThrow(sendData != null, "sendData delegate is null");
            _sendDataDelegate = sendData;
        }

        #endregion

        #region Properties
        /// <summary>
        /// Provide a friendly name for the sink to make it easier to differentiate during 
        /// debugging and display
        /// </summary>
        public string Name
        {
            get;
            set;
        }

        /// <summary>
        /// Has the sink logged the BuildStartedEvent. This is important to know because we only want to log the build started event once
        /// </summary>
        public bool HaveLoggedBuildStartedEvent
        {
            get;
            set;
        }

        /// <summary>
        /// Has the sink logged the BuildFinishedEvent. This is important to know because we only want to log the build finished event once
        /// </summary>
        public bool HaveLoggedBuildFinishedEvent
        {
            get;
            set;
        }

        /// <summary>
        /// This property is ignored by this event sink and relies on the receiver to treat warnings as errors.
        /// </summary>
        public ISet<string> WarningsAsErrors
        {
            get;
            set;
        }

        /// <summary>
        /// This property is ignored by this event sink and relies on the receiver to treat warnings as errors.
        /// </summary>
        public IDictionary<int, ISet<string>> WarningsAsErrorsByProject
        {
            get;
            set;
        }

        /// <summary>
        /// This property is ignored by this event sink and relies on the receiver to treat warnings as low importance messages.
        /// </summary>
        public ISet<string> WarningsAsMessages
        {
            get;
            set;
        }

        /// <summary>
        /// This property is ignored by this event sink and relies on the receiver to treat warnings as low importance messages.
        /// </summary>
        public IDictionary<int, ISet<string>> WarningsAsMessagesByProject
        {
            get;
            set;
        }


        /// <summary>
        /// This property is ignored by this event sink and relies on the receiver to keep track of whether or not any errors have been logged.
        /// </summary>
        public ISet<int> BuildSubmissionIdsThatHaveLoggedErrors { get; } = null;
        #endregion
        #region IBuildEventSink Methods

        /// <summary>
        /// This method should not be used since we need the sinkID
        /// </summary>
        public void Consume(BuildEventArgs buildEvent)
        {
            ErrorUtilities.VerifyThrow(false, "Do not use this method for the transport sink");
        }

        /// <summary>
        /// Consumes the buildEventArg and creates a logMessagePacket
        /// </summary>
        /// <param name="buildEvent">Build event to package into a INodePacket</param>
        /// <param name="sinkId">The sink identifier.</param>
        /// <exception cref="InternalErrorException">buildEvent is null</exception>
        public void Consume(BuildEventArgs buildEvent, int sinkId)
        {
            ErrorUtilities.VerifyThrow(buildEvent != null, "buildEvent is null");
            if (buildEvent is BuildStartedEventArgs)
            {
                HaveLoggedBuildStartedEvent = true;
                return;
            }
            else if (buildEvent is BuildFinishedEventArgs)
            {
                HaveLoggedBuildFinishedEvent = true;
                return;
            }

            LogMessagePacket logPacket = new LogMessagePacket(new KeyValuePair<int, BuildEventArgs>(sinkId, buildEvent));
            _sendDataDelegate(logPacket);
        }

        /// <summary>
        /// Dispose of any resources the sink is holding onto.
        /// </summary>
        public void ShutDown()
        {
            _sendDataDelegate = null;
        }
        #endregion
    }
}


<|start_filename|>src/Tasks.UnitTests/RemoveDuplicates_Tests.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Build.Tasks;
using Microsoft.Build.Utilities;
using Xunit;

namespace Microsoft.Build.UnitTests
{
    sealed public class RemoveDuplicates_Tests
    {
        /// <summary>
        /// Pass one item in, get the same item back.
        /// </summary>
        [Fact]
        public void OneItemNop()
        {
            var t = new RemoveDuplicates();
            t.BuildEngine = new MockEngine();

            t.Inputs = new[] { new TaskItem("MyFile.txt") };

            bool success = t.Execute();
            Assert.True(success);
            Assert.Single(t.Filtered);
            Assert.Equal("MyFile.txt", t.Filtered[0].ItemSpec);
            Assert.False(t.HadAnyDuplicates);
        }

        /// <summary>
        /// Pass in two of the same items.
        /// </summary>
        [Fact]
        public void TwoItemsTheSame()
        {
            var t = new RemoveDuplicates();
            t.BuildEngine = new MockEngine();

            t.Inputs = new[] { new TaskItem("MyFile.txt"), new TaskItem("MyFile.txt") };

            bool success = t.Execute();
            Assert.True(success);
            Assert.Single(t.Filtered);
            Assert.Equal("MyFile.txt", t.Filtered[0].ItemSpec);
            Assert.True(t.HadAnyDuplicates);
        }

        /// <summary>
        /// Item order preserved
        /// </summary>
        [Fact]
        public void OrderPreservedNoDups()
        {
            var t = new RemoveDuplicates();
            t.BuildEngine = new MockEngine();

            // intentionally not sorted to catch an invalid implementation that sorts before
            // de-duping.
            t.Inputs = new[]
            {
                new TaskItem("MyFile2.txt"),
                new TaskItem("MyFile1.txt"),
                new TaskItem("MyFile3.txt")
            };

            bool success = t.Execute();
            Assert.True(success);
            Assert.Equal(3, t.Filtered.Length);
            Assert.Equal("MyFile2.txt", t.Filtered[0].ItemSpec);
            Assert.Equal("MyFile1.txt", t.Filtered[1].ItemSpec);
            Assert.Equal("MyFile3.txt", t.Filtered[2].ItemSpec);
        }

        /// <summary>
        /// Item order preserved, keeping the first items seen when there are duplicates.
        /// </summary>
        [Fact]
        public void OrderPreservedDups()
        {
            var t = new RemoveDuplicates();
            t.BuildEngine = new MockEngine();

            t.Inputs = new[]
            {
                new TaskItem("MyFile2.txt"),
                new TaskItem("MyFile1.txt"),
                new TaskItem("MyFile2.txt"),
                new TaskItem("MyFile3.txt"),
                new TaskItem("MyFile1.txt")
            };

            bool success = t.Execute();
            Assert.True(success);
            Assert.Equal(3, t.Filtered.Length);
            Assert.Equal("MyFile2.txt", t.Filtered[0].ItemSpec);
            Assert.Equal("MyFile1.txt", t.Filtered[1].ItemSpec);
            Assert.Equal("MyFile3.txt", t.Filtered[2].ItemSpec);
        }

        /// <summary>
        /// Pass in two items that are different.
        /// </summary>
        [Fact]
        public void TwoItemsDifferent()
        {
            var t = new RemoveDuplicates();
            t.BuildEngine = new MockEngine();

            t.Inputs = new[] { new TaskItem("MyFile1.txt"), new TaskItem("MyFile2.txt") };

            bool success = t.Execute();
            Assert.True(success);
            Assert.Equal(2, t.Filtered.Length);
            Assert.Equal("MyFile1.txt", t.Filtered[0].ItemSpec);
            Assert.Equal("MyFile2.txt", t.Filtered[1].ItemSpec);
            Assert.False(t.HadAnyDuplicates);
        }

        /// <summary>
        /// Case should not matter.
        /// </summary>
        [Fact]
        public void CaseInsensitive()
        {
            var t = new RemoveDuplicates();
            t.BuildEngine = new MockEngine();

            t.Inputs = new[] { new TaskItem("MyFile.txt"), new TaskItem("MyFIle.tXt") };

            bool success = t.Execute();
            Assert.True(success);
            Assert.Single(t.Filtered);
            Assert.Equal("MyFile.txt", t.Filtered[0].ItemSpec);
            Assert.True(t.HadAnyDuplicates);
        }

        /// <summary>
        /// No inputs should result in zero-length outputs.
        /// </summary>
        [Fact]
        public void MissingInputs()
        {
            var t = new RemoveDuplicates();
            t.BuildEngine = new MockEngine();
            bool success = t.Execute();

            Assert.True(success);
            Assert.Empty(t.Filtered);
            Assert.False(t.HadAnyDuplicates);
        }
    }
}


<|start_filename|>src/Tasks.UnitTests/ResolveNonMSBuildProjectOutput_Tests.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections;
using System.IO;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.Build.Tasks;
using Xunit;
using Xunit.Abstractions;

namespace Microsoft.Build.UnitTests
{
    sealed public class ResolveNonMSBuildProjectOutput_Tests
    {
        private const string attributeProject = "Project";

        private readonly ITestOutputHelper _output;

        public ResolveNonMSBuildProjectOutput_Tests(ITestOutputHelper output)
        {
            _output = output;
        }

        static internal ITaskItem CreateReferenceItem(string itemSpec, string projectGuid, string package, string name)
        {
            TaskItem reference = new TaskItem(itemSpec);

            if (projectGuid != null)
                reference.SetMetadata(attributeProject, projectGuid);
            if (package != null)
                reference.SetMetadata("Package", package);
            if (name != null)
                reference.SetMetadata("Name", name);

            return reference;
        }

        private void TestVerifyReferenceAttributesHelper(string itemSpec, string projectGuid, string package, string name,
            bool expectedResult, string expectedMissingAttribute)
        {
            ITaskItem reference = CreateReferenceItem(itemSpec, projectGuid, package, name);

            ResolveNonMSBuildProjectOutput rvpo = new ResolveNonMSBuildProjectOutput();
            string missingAttr;
            bool result = rvpo.VerifyReferenceAttributes(reference, out missingAttr);

            string message = string.Format("Reference \"{0}\" [project \"{1}\", package \"{2}\", name \"{3}\"], " +
                "expected result \"{4}\", actual result \"{5}\", expected missing attr \"{6}\", actual missing attr \"{7}\".",
                itemSpec, projectGuid, package, name, expectedResult, result,
                expectedMissingAttribute, missingAttr);

            Assert.Equal(result, expectedResult);
            if (!result)
            {
                Assert.Equal(missingAttr, expectedMissingAttribute);
            }
            else
            {
                Assert.Null(missingAttr);
            }
        }

        [Fact]
        public void TestVerifyReferenceAttributes()
        {
            // a correct reference
            TestVerifyReferenceAttributesHelper("proj1.csproj", "{CFF438C3-51D1-4E61-BECD-D7D3A6193DF7}", "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", "CSDep",
                true, null);

            // incorrect project guid - should not work
            TestVerifyReferenceAttributesHelper("proj1.csproj", "{invalid guid}", "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", "CSDep",
                false, "Project");
        }

        static internal string CreatePregeneratedPathDoc(IDictionary projectOutputs)
        {
            string xmlString = "<VSIDEResolvedNonMSBuildProjectOutputs>";

            foreach (DictionaryEntry entry in projectOutputs)
            {
                xmlString += string.Format("<ProjectRef Project=\"{0}\">{1}</ProjectRef>", entry.Key, entry.Value);
            }

            xmlString += "</VSIDEResolvedNonMSBuildProjectOutputs>";

            return xmlString;
        }

        private void TestResolveHelper(string itemSpec, string projectGuid, string package, string name,
            Hashtable pregenOutputs, bool expectedResult, string expectedPath)
        {
            ITaskItem reference = CreateReferenceItem(itemSpec, projectGuid, package, name);
            string xmlString = CreatePregeneratedPathDoc(pregenOutputs);
            ITaskItem resolvedPath;

            ResolveNonMSBuildProjectOutput rvpo = new ResolveNonMSBuildProjectOutput();
            rvpo.CacheProjectElementsFromXml(xmlString);
            bool result = rvpo.ResolveProject(reference, out resolvedPath);

            string message = string.Format("Reference \"{0}\" [project \"{1}\", package \"{2}\", name \"{3}\"] Pregen Xml string : \"{4}\"" +
                "expected result \"{5}\", actual result \"{6}\", expected path \"{7}\", actual path \"{8}\".",
                itemSpec, projectGuid, package, name, xmlString, expectedResult, result, expectedPath, resolvedPath);

            Assert.Equal(result, expectedResult);
            if (result)
            {
                Assert.Equal(resolvedPath.ItemSpec, expectedPath);
            }
            else
            {
                Assert.Null(resolvedPath);
            }
        }

        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestResolve()
        {
            // empty pre-generated string
            Hashtable projectOutputs = new Hashtable();
            TestResolveHelper("MCDep1.vcproj", "{2F6BBCC3-7111-4116-A68B-34CFC76F37C5}", "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}", "MCDep1",
                projectOutputs, false, null);

            // non matching project in string
            projectOutputs = new Hashtable();
            projectOutputs.Add("{11111111-1111-1111-1111-111111111111}", Path.Combine("obj", "wrong.dll"));
            TestResolveHelper("MCDep1.vcproj", "{2F6BBCC3-7111-4116-A68B-34CFC76F37C5}", "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}", "MCDep1",
                projectOutputs, false, null);

            // matching project in string
            projectOutputs = new Hashtable();
            projectOutputs.Add("{2F6BBCC3-7111-4116-A68B-34CFC76F37C5}", Path.Combine("obj", "correct.dll"));
            TestResolveHelper("MCDep1.vcproj", "{2F6BBCC3-7111-4116-A68B-34CFC76F37C5}", "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}", "MCDep1",
                projectOutputs, true, Path.Combine("obj", "correct.dll"));

            // multiple non matching projects in string
            projectOutputs = new Hashtable();
            projectOutputs.Add("{11111111-1111-1111-1111-111111111111}", Path.Combine("obj", "wrong.dll"));
            projectOutputs.Add("{11111111-1111-1111-1111-111111111112}", Path.Combine("obj", "wrong2.dll"));
            projectOutputs.Add("{11111111-1111-1111-1111-111111111113}", Path.Combine("obj", "wrong3.dll"));
            TestResolveHelper("MCDep1.vcproj", "{2F6BBCC3-7111-4116-A68B-34CFC76F37C5}", "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}", "MCDep1",
                projectOutputs, false, null);

            // multiple non matching projects in string, one matching
            projectOutputs = new Hashtable();
            projectOutputs.Add("{11111111-1111-1111-1111-111111111111}", Path.Combine("obj", "wrong.dll"));
            projectOutputs.Add("{11111111-1111-1111-1111-111111111112}", Path.Combine("obj", "wrong2.dll"));
            projectOutputs.Add("{11111111-1111-1111-1111-111111111113}", Path.Combine("obj", "wrong3.dll"));
            projectOutputs.Add("{2F6BBCC3-7111-4116-A68B-34CFC76F37C5}", Path.Combine("obj", "correct.dll"));
            TestResolveHelper("MCDep1.vcproj", "{2F6BBCC3-7111-4116-A68B-34CFC76F37C5}", "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}", "MCDep1",
                projectOutputs, true, Path.Combine("obj", "correct.dll"));
        }

        private void TestUnresolvedReferencesHelper(ArrayList projectRefs, Hashtable pregenOutputs,
            out Hashtable unresolvedOutputs, out Hashtable resolvedOutputs)
        {
            TestUnresolvedReferencesHelper(projectRefs, pregenOutputs, null, out unresolvedOutputs, out resolvedOutputs);
        }

        private void TestUnresolvedReferencesHelper(ArrayList projectRefs, Hashtable pregenOutputs, Func<string, bool> isManaged,
            out Hashtable unresolvedOutputs, out Hashtable resolvedOutputs)
        {
            ResolveNonMSBuildProjectOutput.GetAssemblyNameDelegate pretendGetAssemblyName = path =>
            {
                if (isManaged != null && isManaged(path))
                {
                    return null; // just don't throw an exception
                }
                else
                {
                    throw new BadImageFormatException(); // the hint that the caller takes for an unmanaged binary.
                }
            };

            string xmlString = CreatePregeneratedPathDoc(pregenOutputs);

            MockEngine engine = new MockEngine(_output);
            ResolveNonMSBuildProjectOutput rvpo = new ResolveNonMSBuildProjectOutput();
            rvpo.GetAssemblyName = pretendGetAssemblyName;
            rvpo.BuildEngine = engine;
            rvpo.PreresolvedProjectOutputs = xmlString;
            rvpo.ProjectReferences = (ITaskItem[])projectRefs.ToArray(typeof(ITaskItem));

            bool result = rvpo.Execute();
            unresolvedOutputs = new Hashtable();

            for (int i = 0; i < rvpo.UnresolvedProjectReferences.Length; i++)
            {
                unresolvedOutputs[rvpo.UnresolvedProjectReferences[i].ItemSpec] = rvpo.UnresolvedProjectReferences[i];
            }

            resolvedOutputs = new Hashtable();
            for (int i = 0; i < rvpo.ResolvedOutputPaths.Length; i++)
            {
                resolvedOutputs[rvpo.ResolvedOutputPaths[i].ItemSpec] = rvpo.ResolvedOutputPaths[i];
            }
        }

        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestManagedCheck()
        {
            Hashtable unresolvedOutputs = null;
            Hashtable resolvedOutputs = null;
            Hashtable projectOutputs = null;
            ArrayList projectRefs = new ArrayList();
            projectRefs.Add(CreateReferenceItem("MCDep1.vcproj", "{2F6BBCC3-7111-4116-A68B-000000000000}",
                "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}", "MCDep1"));
            projectRefs.Add(CreateReferenceItem("MCDep2.vcproj", "{2F6BBCC3-7111-4116-A68B-34CFC76F37C5}",
                "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}", "MCDep2"));

            // 1. multiple project refs, none resolvable
            projectOutputs = new Hashtable();
            projectOutputs.Add("{2F6BBCC3-7111-4116-A68B-000000000000}", Path.Combine("obj", "managed.dll"));
            projectOutputs.Add("{2F6BBCC3-7111-4116-A68B-34CFC76F37C5}", Path.Combine("obj", "unmanaged.dll"));

            TestUnresolvedReferencesHelper(projectRefs, projectOutputs, path => (path == Path.Combine("obj", "managed.dll")), out unresolvedOutputs, out resolvedOutputs);

            Assert.NotNull(resolvedOutputs);
            Assert.True(resolvedOutputs.Contains(Path.Combine("obj", "managed.dll")));
            Assert.True(resolvedOutputs.Contains(Path.Combine("obj", "unmanaged.dll")));
            Assert.Equal("true", ((ITaskItem)resolvedOutputs[Path.Combine("obj", "managed.dll")]).GetMetadata("ManagedAssembly"));
            Assert.NotEqual("true", ((ITaskItem)resolvedOutputs[Path.Combine("obj", "unmanaged.dll")]).GetMetadata("ManagedAssembly"));
        }

        /// <summary>
        /// Verifies that the UnresolvedProjectReferences output parameter is populated correctly.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestUnresolvedReferences()
        {
            ArrayList projectRefs = new ArrayList();
            projectRefs.Add(CreateReferenceItem("MCDep1.vcproj", "{2F6BBCC3-7111-4116-A68B-000000000000}",
                "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}", "MCDep1"));
            projectRefs.Add(CreateReferenceItem("MCDep2.vcproj", "{2F6BBCC3-7111-4116-A68B-34CFC76F37C5}",
                "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}", "MCDep2"));

            // 1. multiple project refs, none resolvable
            Hashtable projectOutputs = new Hashtable();
            projectOutputs.Add("{11111111-1111-1111-1111-111111111111}", Path.Combine("obj", "wrong.dll"));
            projectOutputs.Add("{11111111-1111-1111-1111-111111111112}", Path.Combine("obj", "wrong2.dll"));
            projectOutputs.Add("{11111111-1111-1111-1111-111111111113}", Path.Combine("obj", "wrong3.dll"));

            Hashtable unresolvedOutputs;
            Hashtable resolvedOutputs;
            TestUnresolvedReferencesHelper(projectRefs, projectOutputs, out unresolvedOutputs, out resolvedOutputs);

            Assert.Empty(resolvedOutputs); // "No resolved refs expected for case 1"
            Assert.Equal(2, unresolvedOutputs.Count); // "Two unresolved refs expected for case 1"
            Assert.Equal(unresolvedOutputs["MCDep1.vcproj"], projectRefs[0]);
            Assert.Equal(unresolvedOutputs["MCDep2.vcproj"], projectRefs[1]);

            // 2. multiple project refs, one resolvable
            projectOutputs = new Hashtable();
            projectOutputs.Add("{11111111-1111-1111-1111-111111111111}", Path.Combine("obj", "wrong.dll"));
            projectOutputs.Add("{11111111-1111-1111-1111-111111111112}", Path.Combine("obj", "wrong2.dll"));
            projectOutputs.Add("{11111111-1111-1111-1111-111111111113}", Path.Combine("obj", "wrong3.dll"));
            projectOutputs.Add("{2F6BBCC3-7111-4116-A68B-34CFC76F37C5}", Path.Combine("obj", "correct.dll"));

            TestUnresolvedReferencesHelper(projectRefs, projectOutputs, out unresolvedOutputs, out resolvedOutputs);

            Assert.Single(resolvedOutputs); // "One resolved ref expected for case 2"
            Assert.True(resolvedOutputs.ContainsKey(Path.Combine("obj", "correct.dll")));
            Assert.Single(unresolvedOutputs); // "One unresolved ref expected for case 2"
            Assert.Equal(unresolvedOutputs["MCDep1.vcproj"], projectRefs[0]);

            // 3. multiple project refs, all resolvable
            projectOutputs = new Hashtable();
            projectOutputs.Add("{11111111-1111-1111-1111-111111111111}", Path.Combine("obj", "wrong.dll"));
            projectOutputs.Add("{11111111-1111-1111-1111-111111111112}", Path.Combine("obj", "wrong2.dll"));
            projectOutputs.Add("{11111111-1111-1111-1111-111111111113}", Path.Combine("obj", "wrong3.dll"));
            projectOutputs.Add("{2F6BBCC3-7111-4116-A68B-34CFC76F37C5}", Path.Combine("obj", "correct.dll"));
            projectOutputs.Add("{2F6BBCC3-7111-4116-A68B-000000000000}", Path.Combine("obj", "correct2.dll"));

            TestUnresolvedReferencesHelper(projectRefs, projectOutputs, out unresolvedOutputs, out resolvedOutputs);

            Assert.Equal(2, resolvedOutputs.Count); // "Two resolved refs expected for case 3"
            Assert.True(resolvedOutputs.ContainsKey(Path.Combine("obj", "correct.dll")));
            Assert.True(resolvedOutputs.ContainsKey(Path.Combine("obj", "correct2.dll")));
            Assert.Empty(unresolvedOutputs); // "No unresolved refs expected for case 3"

            // 4. multiple project refs, all failed to resolve
            projectOutputs = new Hashtable();
            projectOutputs.Add("{11111111-1111-1111-1111-111111111111}", Path.Combine("obj", "wrong.dll"));
            projectOutputs.Add("{11111111-1111-1111-1111-111111111112}", Path.Combine("obj", "wrong2.dll"));
            projectOutputs.Add("{11111111-1111-1111-1111-111111111113}", Path.Combine("obj", "wrong3.dll"));
            projectOutputs.Add("{2F6BBCC3-7111-4116-A68B-34CFC76F37C5}", @"");
            projectOutputs.Add("{2F6BBCC3-7111-4116-A68B-000000000000}", @"");

            TestUnresolvedReferencesHelper(projectRefs, projectOutputs, out unresolvedOutputs, out resolvedOutputs);

            Assert.Empty(resolvedOutputs); // "No resolved refs expected for case 4"
            Assert.Empty(unresolvedOutputs); // "No unresolved refs expected for case 4"

            // 5. multiple project refs, one resolvable, one failed to resolve
            projectOutputs = new Hashtable();
            projectOutputs.Add("{11111111-1111-1111-1111-111111111111}", Path.Combine("obj", "wrong.dll"));
            projectOutputs.Add("{11111111-1111-1111-1111-111111111112}", Path.Combine("obj", "wrong2.dll"));
            projectOutputs.Add("{11111111-1111-1111-1111-111111111113}", Path.Combine("obj", "wrong3.dll"));
            projectOutputs.Add("{2F6BBCC3-7111-4116-A68B-34CFC76F37C5}", Path.Combine("obj", "correct.dll"));
            projectOutputs.Add("{2F6BBCC3-7111-4116-A68B-000000000000}", @"");

            TestUnresolvedReferencesHelper(projectRefs, projectOutputs, out unresolvedOutputs, out resolvedOutputs);

            Assert.Single(resolvedOutputs); // "One resolved ref expected for case 5"
            Assert.True(resolvedOutputs.ContainsKey(Path.Combine("obj", "correct.dll")));
            Assert.Empty(unresolvedOutputs); // "No unresolved refs expected for case 5"

            // 6. multiple project refs, one unresolvable, one failed to resolve
            projectOutputs = new Hashtable();
            projectOutputs.Add("{11111111-1111-1111-1111-111111111111}", Path.Combine("obj", "wrong.dll"));
            projectOutputs.Add("{11111111-1111-1111-1111-111111111112}", Path.Combine("obj", "wrong2.dll"));
            projectOutputs.Add("{11111111-1111-1111-1111-111111111113}", Path.Combine("obj", "wrong3.dll"));
            projectOutputs.Add("{2F6BBCC3-7111-4116-A68B-000000000000}", @"");

            TestUnresolvedReferencesHelper(projectRefs, projectOutputs, out unresolvedOutputs, out resolvedOutputs);

            Assert.Empty(resolvedOutputs); // "No resolved refs expected for case 6"
            Assert.Single(unresolvedOutputs); // "One unresolved ref expected for case 6"
            Assert.Equal(unresolvedOutputs["MCDep2.vcproj"], projectRefs[1]);
        }

        [Fact]
        public void TestVerifyProjectReferenceItem()
        {
            ResolveNonMSBuildProjectOutput rvpo = new ResolveNonMSBuildProjectOutput();

            ITaskItem[] taskItems = new ITaskItem[1];
            // bad GUID - this reference is invalid
            taskItems[0] = new TaskItem("projectReference");
            taskItems[0].SetMetadata(attributeProject, "{invalid guid}");

            MockEngine engine = new MockEngine(_output);
            rvpo.BuildEngine = engine;
            Assert.True(rvpo.VerifyProjectReferenceItems(taskItems, false /* treat problems as warnings */));
            Assert.Equal(1, engine.Warnings);
            Assert.Equal(0, engine.Errors);
            engine.AssertLogContains("MSB3107");

            engine = new MockEngine(_output);
            rvpo.BuildEngine = engine;
            Assert.False(rvpo.VerifyProjectReferenceItems(taskItems, true /* treat problems as errors */));
            Assert.Equal(0, engine.Warnings);
            Assert.Equal(1, engine.Errors);
            engine.AssertLogContains("MSB3107");
        }
    }
}


<|start_filename|>src/Framework/XamlTypes/Category.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.ComponentModel;

namespace Microsoft.Build.Framework.XamlTypes
{
    /// <summary>
    /// Represents a category to which a <see cref="BaseProperty"/> can belong to.
    /// </summary>
    /// <remarks> 
    /// Those who manually 
    /// instantiate this class should remember to call <see cref="BeginInit"/> before setting the first
    /// property and <see cref="EndInit"/> after setting the last property of the object.
    /// </remarks>
    /// <comment>
    /// This partial class contains all properties which are public and hence settable in XAML. Those properties that
    /// are internal are defined in another partial class below.
    /// </comment>
    public sealed partial class Category : CategorySchema, ISupportInitialize
    {
        #region Fields

        /// <summary>
        /// See DisplayName property.
        /// </summary>
        private string _displayName;

        #endregion

        #region Properties

        /// <summary>
        /// The name of this <see cref="Category"/>. 
        /// </summary>
        /// <remarks>
        /// This field is mandatory and culture invariant.
        /// This field cannot be set to the empty string.
        /// </remarks>
        public string Name
        {
            get;
            set;
        }

        /// <summary>
        /// The name that could be used by a prospective UI client to display this <see cref="Category"/>. 
        /// </summary>
        /// <remarks>
        /// This field is optional and is culture sensitive. When this property is not set, it is assigned the same 
        /// value as the <see cref="Name"/> property (and hence, would not be localized).
        /// </remarks>
        [Localizable(true)]
        public string DisplayName
        {
            get
            {
                return _displayName ?? Name;
            }

            set
            {
                _displayName = value;
            }
        }

        /// <summary>
        /// Description of this <see cref="Category"/>. 
        /// </summary>
        /// <remarks>
        /// This field is optional and is culture sensitive.
        /// </remarks>
        [Localizable(true)]
        public string Description
        {
            get;
            set;
        }

        /// <summary>
        /// Subtype of this <see cref="Category"/>. Is either <c>Grid</c> (default) or <c>CommandLine</c>.
        /// </summary>
        /// <remarks>
        /// It helps the UI display this category in an appropriate form. E.g. non command line category
        /// properties are normally displayed in the form of a property grid.
        /// </remarks>
        public string Subtype
        {
            get;
            set;
        }

        /// <summary>
        /// Help information for this <see cref="Category"/>. 
        /// </summary>
        /// <remarks>
        /// Maybe used to specify a help URL. This field
        /// is optional and is culture sensitive.
        /// </remarks>
        [Localizable(true)]
        public string HelpString
        {
            get;
            set;
        }

        #endregion
    }

    /// <summary>
    /// Represents a category to which a <see cref="BaseProperty"/> can belong to.
    /// </summary>
    /// <remarks> 
    /// Those who manually 
    /// instantiate this class should remember to call <see cref="BeginInit"/> before setting the first
    /// property and <see cref="EndInit"/> after setting the last property of the object.
    /// </remarks>
    /// <comment>
    /// This partial class contains members that are auto-generated, internal, etc. Whereas the
    /// other partial class contains public properties that can be set in XAML.
    /// </comment>
    public sealed partial class Category : CategorySchema, ISupportInitialize
    {
        // This partial class contains members that are auto-generated, internal, etc.
        #region Constructor

        /// <summary>
        /// Default constructor. Called during deserialization.
        /// </summary>
        public Category()
        {
            Subtype = "Grid";
        }

        #endregion // Constructor

        #region ISupportInitialize Members

        /// <summary>
        /// See ISupportInitialize.
        /// </summary>
        public void BeginInit()
        {
        }

        /// <summary>
        /// See ISupportInitialize.
        /// </summary>
        public void EndInit()
        {
        }

        #endregion
    }
}


<|start_filename|>src/Tasks/ManifestUtil/Constants.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;

namespace Microsoft.Build.Tasks.Deployment.ManifestUtilities
{
    internal static class Constants
    {
        public const string CLRPlatformAssemblyName = "Microsoft.Windows.CommonLanguageRuntime";
        public const string DeployFileExtension = ".deploy";
        public const string OSVersion_Win9X = "4.10.0.0";
        public const string OSVersion_WinXP = "5.1.2600.0";
        public static readonly Version EntryPointMinimumImageVersion = new Version("2.0.0.0");
        public const string TargetFrameworkVersion20 = "v2.0";
        public const string TargetFrameworkVersion30 = "v3.0";
        public const string TargetFrameworkVersion35 = "v3.5";
        public const string TargetFrameworkVersion40 = "v4.0";
        public static readonly string[] NET30AssemblyIdentity = { "WindowsBase", "3.0.0.0", "31bf3856ad364e35", "neutral", "msil" };
        public static readonly string[] NET35AssemblyIdentity = { "System.Core", "3.5.0.0", "b77a5c561934e089", "neutral", "msil" };
        public static readonly string[] NET35SP1AssemblyIdentity = { "System.Data.Entity", "3.5.0.0", "b77a5c561934e089", "neutral", "msil" };
        public static readonly string[] NET35ClientAssemblyIdentity = { "Sentinel.v3.5Client", "3.5.0.0", "b03f5f7f11d50a3a", "neutral", "msil" };
        public const string UACAsInvoker = "asInvoker";
        public const string UACUIAccess = "false";
        public const int MaxFileAssociationsCount = 8;
        public const int MaxFileAssociationExtensionLength = 24;
        public const string ClientFrameworkSubset = "Client";
        public const string DotNetFrameworkIdentifier = ".NETFramework";
        public const string DotNetCoreIdentifier = ".NETCore";
        public const string DotNetCoreAppIdentifier = ".NETCoreApp";
        public const string AppHostExe = "apphost.exe";
        public const string SingleFileHostExe = "singlefilehost.exe";
    }
}


<|start_filename|>src/Tasks/ToolTaskExtension.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections;
using Microsoft.Build.Shared;
using Microsoft.Build.Utilities;

namespace Microsoft.Build.Tasks
{
    /// <summary>
    /// A small intermediate class between ToolTask and classes using it in XMakeTasks, implementing functionality
    /// that we didn't want to expose in Utilities
    /// </summary>
    /// <remarks>
    /// This class has to be public because the tasks that derive from it are public.
    /// Ideally we would like this class to be internal, but C# does not allow a base class
    /// to be less accessible than its derived classes.
    /// </remarks>
    public abstract class ToolTaskExtension : ToolTask
    {
        #region Constructors

        /// <summary>
        /// Default constructor.
        /// </summary>
        internal ToolTaskExtension() :
            base(AssemblyResources.PrimaryResources, "MSBuild.")
        {
            _logExtension = new TaskLoggingHelperExtension(
                this,
                AssemblyResources.PrimaryResources,
                AssemblyResources.SharedResources,
                "MSBuild.");
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets an instance of a TaskLoggingHelperExtension class containing task logging methods.
        /// </summary>
        /// <value>The logging helper object.</value>
        public new TaskLoggingHelper Log => _logExtension;

        // the logging helper
        private readonly TaskLoggingHelperExtension _logExtension;

        /// <summary>
        /// Whether this ToolTaskExtension has logged any errors
        /// </summary>
        protected override bool HasLoggedErrors => Log.HasLoggedErrors || base.HasLoggedErrors;

        /// <summary>
        /// Gets the collection of parameters used by the derived task class.
        /// </summary>
        /// <value>Parameter bag.</value>
        protected internal Hashtable Bag { get; } = new Hashtable();

        /// <summary>
        /// When set to true, the response file will use new lines instead of spaces to separate arguments.
        /// </summary>
        protected virtual bool UseNewLineSeparatorInResponseFile => false;

        #endregion

        #region Methods

        /// <summary>
        /// Get a bool parameter and return a default if its not present
        /// in the hash table.
        /// </summary>
        protected internal bool GetBoolParameterWithDefault(string parameterName, bool defaultValue)
        {
            object obj = Bag[parameterName];
            return (obj == null) ? defaultValue : (bool)obj;
        }

        /// <summary>
        /// Get an int parameter and return a default if its not present
        /// in the hash table.
        /// </summary>
        protected internal int GetIntParameterWithDefault(string parameterName, int defaultValue)
        {
            object obj = Bag[parameterName];
            return (obj == null) ? defaultValue : (int)obj;
        }

        /// <summary>
        /// Returns the command line switch used by the tool executable to specify the response file
        /// Will only be called if the task returned a non empty string from GetResponseFileCommands
        /// Called after ValidateParameters, SkipTaskExecution and GetResponseFileCommands
        /// </summary>
        /// <returns></returns>
        protected override string GenerateResponseFileCommands()
        {
            var commandLineBuilder = new CommandLineBuilderExtension(quoteHyphensOnCommandLine: false, useNewLineSeparator: UseNewLineSeparatorInResponseFile);
            AddResponseFileCommands(commandLineBuilder);
            return commandLineBuilder.ToString();
        }

        /// <summary>
        /// Returns a string with those switches and other information that can't go into a response file and
        /// must go directly onto the command line.
        /// Called after ValidateParameters and SkipTaskExecution
        /// </summary>
        /// <returns></returns>
        protected override string GenerateCommandLineCommands()
        {
            var commandLineBuilder = new CommandLineBuilderExtension();
            AddCommandLineCommands(commandLineBuilder);
            return commandLineBuilder.ToString();
        }

        /// <summary>
        /// Fills the provided CommandLineBuilderExtension with those switches and other information that can go into a response file.
        /// </summary>
        protected internal virtual void AddResponseFileCommands(CommandLineBuilderExtension commandLine)
        {
        }

        /// <summary>
        /// Fills the provided CommandLineBuilderExtension with those switches and other information that can't go into a response file and
        /// must go directly onto the command line.
        /// </summary>
        /// <returns>true, if successful</returns>
        protected internal virtual void AddCommandLineCommands(CommandLineBuilderExtension commandLine)
        {
        }

        #endregion
    }
}


<|start_filename|>src/Build/ElementLocation/XmlNameTableThreadSafe.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Xml;

namespace Microsoft.Build.Construction
{
    /// <summary>
    /// XmlNameTable that is thread safe for concurrent users.
    /// </summary>
    /// <remarks>
    /// Fortunately the standard implementation has only four accessible members
    /// and all of them are virtual so we can easily add locks.
    /// </remarks>
    internal class XmlNameTableThreadSafe : NameTable
    {
        /// <summary>
        /// Synchronization object.
        /// </summary>
        private object _locker = new Object();

        /// <summary>
        /// Add a string to the table.
        /// </summary>
        public override string Add(string key)
        {
            lock (_locker)
            {
                return base.Add(key);
            }
        }

        /// <summary>
        /// Add a string to the table, passed in as
        /// an extent in a char array.
        /// </summary>
        public override string Add(char[] key, int start, int len)
        {
            lock (_locker)
            {
                return base.Add(key, start, len);
            }
        }

        /// <summary>
        /// Get a string from the table.
        /// </summary>
        public override string Get(string value)
        {
            lock (_locker)
            {
                return base.Get(value);
            }
        }

        /// <summary>
        /// Get a string from the table, passed in as
        /// an extent in a char array.
        /// </summary>
        public override string Get(char[] key, int start, int len)
        {
            lock (_locker)
            {
                return base.Get(key, start, len);
            }
        }
    }
}


<|start_filename|>src/Shared/INodeEndpoint.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Microsoft.Build.BackEnd
{
    #region Delegates
    /// <summary>
    /// Used to receive link status updates from an endpoint.
    /// </summary>
    /// <param name="endpoint">The endpoint invoking the delegate.</param>
    /// <param name="status">The current status of the link.</param>
    internal delegate void LinkStatusChangedDelegate(INodeEndpoint endpoint, LinkStatus status);

    /// <summary>
    /// Used to receive data from a node 
    /// </summary>
    /// <param name="endpoint">The endpoint invoking the delegate.</param>
    /// <param name="packet">The packet received.</param>
    internal delegate void DataReceivedDelegate(INodeEndpoint endpoint, INodePacket packet);
    #endregion

    #region Enums
    /// <summary>
    /// The connection status of a link between the NodeEndpoint on the host and the NodeEndpoint
    /// on the peer.
    /// </summary>
    internal enum LinkStatus
    {
        /// <summary>
        /// The connection has never been started.
        /// </summary>
        Inactive,

        /// <summary>
        /// The connection is active, the most recent data has been successfully sent, and the 
        /// node is responding to pings.
        /// </summary>
        Active,

        /// <summary>
        /// The connection has failed and been terminated.
        /// </summary>
        Failed,

        /// <summary>
        /// The connection could not be made/timed out.
        /// </summary>
        ConnectionFailed,
    }

    #endregion

    /// <summary>
    /// This interface represents one end of a connection between the INodeProvider and a Node.
    /// Implementations of this interface define the actual mechanism by which data is communicated.
    /// </summary>
    internal interface INodeEndpoint
    {
        #region Events

        /// <summary>
        /// Raised when the status of the node's link has changed.
        /// </summary>
        event LinkStatusChangedDelegate OnLinkStatusChanged;

        #endregion

        #region Properties

        /// <summary>
        /// The current link status for this endpoint.
        /// </summary>
        LinkStatus LinkStatus
        {
            get;
        }
        #endregion

        #region Methods
        /// <summary>
        /// Waits for the remote node to establish a connection.
        /// </summary>
        /// <param name="factory">The factory used to deserialize packets.</param>
        /// <remarks>Only one of Listen() or Connect() may be called on an endpoint.</remarks>
        void Listen(INodePacketFactory factory);

        /// <summary>
        /// Instructs the node to connect to its peer endpoint.
        /// </summary>
        /// <param name="factory">The factory used to deserialize packets.</param>
        void Connect(INodePacketFactory factory);

        /// <summary>
        /// Instructs the node to disconnect from its peer endpoint.
        /// </summary>
        void Disconnect();

        /// <summary>
        /// Sends a data packet to the node.
        /// </summary>
        /// <param name="packet">The packet to be sent.</param>
        void SendData(INodePacket packet);
        #endregion
    }
}


<|start_filename|>src/Build.UnitTests/Collections/MSBuildNameIgnoreCaseComparer_Tests.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using Microsoft.Build.Collections;
using Microsoft.Build.Shared;
using Microsoft.Build.Execution;
using Xunit;

namespace Microsoft.Build.UnitTests.OM.Collections
{
    /// <summary>
    /// Tests for MSBuildNameIgnoreCaseComparer
    /// </summary>
    public class MSBuildNameIgnoreCaseComparer_Tests
    {
        /// <summary>
        /// Verify default comparer works on the whole string
        /// </summary>
        [Fact]
        public void DefaultEquals()
        {
            Assert.True(MSBuildNameIgnoreCaseComparer.Default.Equals("FOO", "foo"));
            Assert.False(MSBuildNameIgnoreCaseComparer.Default.Equals("FOO", " FOO"));
            Assert.False(MSBuildNameIgnoreCaseComparer.Default.Equals("FOOA", "FOOB"));
            Assert.False(MSBuildNameIgnoreCaseComparer.Default.Equals("AFOO", "BFOO"));
            Assert.False(MSBuildNameIgnoreCaseComparer.Default.Equals("FOO", "FOO "));
            Assert.False(MSBuildNameIgnoreCaseComparer.Default.Equals("a", "b"));
            Assert.True(MSBuildNameIgnoreCaseComparer.Default.Equals("", ""));
            Assert.False(MSBuildNameIgnoreCaseComparer.Default.Equals("x", null));
            Assert.False(MSBuildNameIgnoreCaseComparer.Default.Equals(null, "x"));
            Assert.True(MSBuildNameIgnoreCaseComparer.Default.Equals((string)null, (string)null));
        }

        /// <summary>
        /// Compare real expressions
        /// </summary>
        [Fact]
        public void MatchProperty()
        {
            MSBuildNameIgnoreCaseComparer comparer = MSBuildNameIgnoreCaseComparer.Default;
            PropertyDictionary<ProjectPropertyInstance> dictionary = new PropertyDictionary<ProjectPropertyInstance>(comparer);

            ProjectPropertyInstance p = ProjectPropertyInstance.Create("foo", "bar");

            dictionary.Set(p);

            string s = "$(foo)";
            ProjectPropertyInstance value = dictionary.GetProperty(s, 2, 4);

            Assert.True(Object.ReferenceEquals(p, value)); // "Should have returned the same object as was inserted"

            Assert.Equal(MSBuildNameIgnoreCaseComparer.Default.GetHashCode("foo"), comparer.GetHashCode(s, 2, 3));
        }

        /// <summary>
        /// Null 
        /// </summary>
        [Fact]
        public void Null1()
        {
            Assert.False(MSBuildNameIgnoreCaseComparer.Default.Equals("x", null));
        }

        /// <summary>
        /// Null 
        /// </summary>
        [Fact]
        public void Null2()
        {
            Assert.False(MSBuildNameIgnoreCaseComparer.Default.Equals(null, "x"));
        }

        /// <summary>
        /// Invalid start 
        /// </summary>
        [Fact]
        public void InvalidValue2()
        {
            Assert.Throws<InternalErrorException>(() =>
            {
                MSBuildNameIgnoreCaseComparer.Default.Equals("x", "y", -1, 0);
            }
           );
        }
        /// <summary>
        /// Invalid small end 
        /// </summary>
        [Fact]
        public void InvalidValue4()
        {
            Assert.Throws<InternalErrorException>(() =>
            {
                MSBuildNameIgnoreCaseComparer.Default.Equals("x", "y", 0, -1);
            }
           );
        }
        /// <summary>
        /// Invalid large end 
        /// </summary>
        [Fact]
        public void InvalidValue5()
        {
            Assert.Throws<InternalErrorException>(() =>
            {
                MSBuildNameIgnoreCaseComparer.Default.Equals("x", "y", 0, 2);
            }
           );
        }
        /// <summary>
        /// End past the end of other string
        /// </summary>
        [Fact]
        public void EqualsEndPastEnd1()
        {
            Assert.True(MSBuildNameIgnoreCaseComparer.Default.Equals("bbb", "abbbaaa", 1, 3));
        }

        /// <summary>
        /// Same values means one char
        /// </summary>
        [Fact]
        public void EqualsSameStartEnd1()
        {
            Assert.True(MSBuildNameIgnoreCaseComparer.Default.Equals("A", "babbbb", 1, 1));
        }

        /// <summary>
        /// Same values means one char
        /// </summary>
        [Fact]
        public void EqualsSameStartEnd2()
        {
            Assert.True(MSBuildNameIgnoreCaseComparer.Default.Equals("b", "aabaa", 2, 1));
        }

        /// <summary>
        /// Same values means one char
        /// </summary>
        [Fact]
        public void EqualsSameStartEnd3()
        {
            Assert.True(MSBuildNameIgnoreCaseComparer.Default.Equals("a", "ab", 0, 1));
        }

        /// <summary>
        /// Start at 0
        /// </summary>
        [Fact]
        public void EqualsStartZero()
        {
            Assert.True(MSBuildNameIgnoreCaseComparer.Default.Equals("aab", "aabaa", 0, 3));
        }

        /// <summary>
        /// Default get hash code
        /// </summary>
        [Fact]
        public void DefaultGetHashcode()
        {
            Assert.True(0 == MSBuildNameIgnoreCaseComparer.Default.GetHashCode((string)null));

            MSBuildNameIgnoreCaseComparer.Default.GetHashCode(""); // doesn't throw            
            Assert.Equal(MSBuildNameIgnoreCaseComparer.Default.GetHashCode("aBc"), MSBuildNameIgnoreCaseComparer.Default.GetHashCode("AbC"));
        }

        /// <summary>
        /// Indexed get hashcode
        /// </summary>
        [Fact]
        public void IndexedGetHashcode1()
        {
            MSBuildNameIgnoreCaseComparer comparer = MSBuildNameIgnoreCaseComparer.Default;

            comparer.GetHashCode(""); // does not crash

            Assert.True(0 == comparer.GetHashCode((string)null));
            Assert.Equal(comparer.GetHashCode("aBc"), comparer.GetHashCode("AbC"));
            Assert.Equal(comparer.GetHashCode("xyz", 0, 1), comparer.GetHashCode("x"));
        }

        /// <summary>
        /// Indexed get hashcode
        /// </summary>
        [Fact]
        public void IndexedGetHashcode2()
        {
            MSBuildNameIgnoreCaseComparer comparer = MSBuildNameIgnoreCaseComparer.Default;

            Assert.Equal(comparer.GetHashCode("xyz", 1, 2), comparer.GetHashCode("YZ"));
        }

        /// <summary>
        /// Indexed get hashcode
        /// </summary>
        [Fact]
        public void IndexedGetHashcode3()
        {
            MSBuildNameIgnoreCaseComparer comparer = MSBuildNameIgnoreCaseComparer.Default;

            Assert.Equal(comparer.GetHashCode("abcd", 0, 3), comparer.GetHashCode("abc"));
        }
    }
}


<|start_filename|>src/Build.OM.UnitTests/ObjectModelRemoting/RemoteProjectsProviderMock/ConstructionLinkMocks/ProjectElemetExportHelper.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Microsoft.Build.UnitTests.OM.ObjectModelRemoting
{
    using System;
    using System.Collections.Generic;
    using Microsoft.Build.Construction;


    /// <summary>
    /// We need to know the actual type of ProjectElements in order to do a proper remoting.
    /// Unless we do some explicit ProjectElement.GetXMLType() thing we need to use heuristic.
    ///
    /// Most of the types has a single implementation, but few has a wrapper classes. They are also internal for MSbuild.
    /// </summary>
    internal static class ProjectElemetExportHelper
    {
        delegate MockProjectElementLinkRemoter ExporterFactory(ProjectCollectionLinker exporter, ProjectElement xml);
        private class ElementInfo
        {
            public static ElementInfo New<T, RMock>()
                where RMock : MockProjectElementLinkRemoter, new()
            {
                return new ElementInfo(typeof(T), IsOfType<T>, Export<RMock>);
            }

            public ElementInfo(Type type, Func<ProjectElement, bool> checker, ExporterFactory factory)
            {
                this.CanonicalType = type;
                this.Checker = checker;
                this.ExportFactory = factory;
            }


            public ElementInfo(Func<ProjectElement, bool> checker, ExporterFactory factory)
            {
                this.Checker = checker;
                this.ExportFactory = factory;
            }

            public Type CanonicalType { get; }
            public Func<ProjectElement, bool> Checker { get; }
            public ExporterFactory ExportFactory { get; }
        }

        private static List<ElementInfo> canonicalTypes = new List<ElementInfo>()
        {
            ElementInfo.New<ProjectRootElement               , MockProjectRootElementLinkRemoter>(),
            ElementInfo.New<ProjectChooseElement             , MockProjectChooseElementLinkRemoter>(),
            ElementInfo.New<ProjectExtensionsElement         , MockProjectExtensionsElementLinkRemoter>(),
            ElementInfo.New<ProjectImportElement             , MockProjectImportElementLinkRemoter>(),
            ElementInfo.New<ProjectImportGroupElement        , MockProjectImportGroupElementLinkRemoter>(),
            ElementInfo.New<ProjectItemDefinitionGroupElement, MockProjectItemDefinitionGroupElementLinkRemoter>(),
            ElementInfo.New<ProjectItemElement               , MockProjectItemElementLinkRemoter>(),
            ElementInfo.New<ProjectItemGroupElement          , MockProjectItemGroupElementLinkRemoter>(),
            ElementInfo.New<ProjectMetadataElement           , MockProjectMetadataElementLinkRemoter>(),
            ElementInfo.New<ProjectOnErrorElement            , MockProjectOnErrorElementLinkRemoter>(),
            ElementInfo.New<ProjectOtherwiseElement          , MockProjectOtherwiseElementLinkRemoter>(),
            ElementInfo.New<ProjectOutputElement             , MockProjectOutputElementLinkRemoter>(),
            ElementInfo.New<ProjectPropertyElement           , MockProjectPropertyElementLinkRemoter>(),
            ElementInfo.New<ProjectPropertyGroupElement      , MockProjectPropertyGroupElementLinkRemoter>(),
            ElementInfo.New<ProjectSdkElement                , MockProjectSdkElementLinkRemoter>(),
            ElementInfo.New<ProjectTargetElement             , MockProjectTargetElementLinkRemoter>(),
            ElementInfo.New<ProjectTaskElement               , MockProjectTaskElementLinkRemoter>(),
            ElementInfo.New<ProjectUsingTaskBodyElement      , MockProjectUsingTaskBodyElementLinkRemoter>(),
            ElementInfo.New<ProjectItemDefinitionElement     , MockProjectItemDefinitionElementLinkRemoter>(),
            ElementInfo.New<ProjectUsingTaskElement          , MockProjectUsingTaskElementLinkRemoter>(),
            ElementInfo.New<ProjectUsingTaskParameterElement , MockProjectUsingTaskParameterElementLinkRemoter>(),
            ElementInfo.New<ProjectWhenElement               , MockProjectWhenElementLinkRemoter>(),
            ElementInfo.New<UsingTaskParameterGroupElement   , MockUsingTaskParameterGroupElementLinkRemoter>(),
        };

        private static MockProjectElementLinkRemoter Export<RMock>(ProjectCollectionLinker exporter, ProjectElement xml)
            where RMock : MockProjectElementLinkRemoter, new()
        {
            return exporter.Export<ProjectElement, RMock>(xml);
        }

        private static bool IsOfType<T> (ProjectElement xml) { return xml is T; }

        private static Dictionary<Type, ExporterFactory> knownTypes = new Dictionary<Type, ExporterFactory>();

        static ProjectElemetExportHelper()
        {
            foreach (var v in canonicalTypes)
            {
                knownTypes.Add(v.CanonicalType, v.ExportFactory);
            }
        }


        private static MockProjectElementLinkRemoter NotImplemented(ProjectCollectionLinker exporter, ProjectElement xml)
        {
            throw new NotImplementedException();
        }

        public static MockProjectElementLinkRemoter ExportElement(this ProjectCollectionLinker exporter, ProjectElement xml)
        {
            if (xml == null)
            {
                return null;
            }

            var implType = xml.GetType();
            if (knownTypes.TryGetValue(implType, out var factory))
            {
                return factory(exporter, xml);
            }

            factory = NotImplemented;

            foreach (var t in canonicalTypes)
            {
                if (t.Checker(xml))
                {
                    factory = t.ExportFactory;
                    break;
                }
            }

            lock (knownTypes)
            {
                var newKnown = new Dictionary<Type, ExporterFactory>(knownTypes);
                newKnown[implType] = factory;
                knownTypes = newKnown;
            }

            return factory(exporter, xml);
        }
    }
}


<|start_filename|>src/Shared/LanguageParser/CSharptokenEnumerator.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.IO;
using System.Diagnostics;

namespace Microsoft.Build.Shared.LanguageParser
{
    /*
    * Class:   CSharpTokenEnumerator
    *
    * Given C# sources, enumerate over all tokens.
    *
    */
    sealed internal class CSharpTokenEnumerator : TokenEnumerator
    {
        // Reader over the sources.
        private CSharpTokenCharReader _reader = null;

        /*
        * Method:  TokenEnumerator
        * 
        * Construct
        */
        internal CSharpTokenEnumerator(Stream binaryStream, bool forceANSI)
        {
            _reader = new CSharpTokenCharReader(binaryStream, forceANSI);
        }

        /*
        * Method:  FindNextToken
        * 
        * Find the next token. Return 'true' if one was found. False, otherwise.
        */
        override internal bool FindNextToken()
        {
            int startPosition = _reader.Position;

            // Dealing with whitespace?
            if (_reader.SinkMultipleWhiteSpace())
            {
                current = new WhitespaceToken();
                return true;
            }
            // Check for one-line comment
            else if (_reader.Sink("//"))
            {
                // Looks like a one-line comment. Follow it to the End-of-line
                _reader.SinkToEndOfLine();

                current = new CommentToken();
                return true;
            }
            // Check for multi-line comment
            else if (_reader.Sink("/*"))
            {
                _reader.SinkUntil("*/");

                // Was the ending */ found?
                if (_reader.EndOfLines)
                {
                    // No. There was a /* without a */. Return this a syntax error token.
                    current = new CSharpTokenizer.EndOfFileInsideCommentToken();
                    return true;
                }

                current = new CommentToken();
                return true;
            }
            // Handle chars
            else if (_reader.Sink("\'"))
            {
                while (_reader.CurrentCharacter != '\'')
                {
                    if (_reader.Sink("\\"))
                    {
                        /* reader.Skip the escape sequence. 
                            This isn't exactly right. We should detect:
                            
                            simple-escape-sequence: one of 
                            \' \" \\ \0 \a \b \f \n \r \t \v 
                            
                            hexadecimal-escape-sequence: 
                            \x   hex-digit   hex-digit[opt]   hex-digit[opt]  hex-digit[opt]                                
                        */
                    }

                    _reader.SinkCharacter();
                }

                if (_reader.SinkCharacter() != '\'')
                {
                    Debug.Assert(false, "Code defect in tokenizer: Should have yielded a closing tick.");
                }
                current = new CSharpTokenizer.CharLiteralToken();
                return true;
            }
            // Check for verbatim string
            else if (_reader.Sink("@\""))
            {
                do
                {
                    // Inside a verbatim string "" is treated as a special character
                    while (_reader.Sink("\"\""))
                    {
                    }
                }
                while (!_reader.EndOfLines && _reader.SinkCharacter() != '\"');

                // Can't end a file inside a string 
                if (_reader.EndOfLines)
                {
                    current = new EndOfFileInsideStringToken();
                    return true;
                }

                // reader.Skip the ending quote.
                current = new StringLiteralToken();
                current.InnerText = _reader.GetCurrentMatchedString(startPosition).Substring(1);
                return true;
            }
            // Check for a quoted string.
            else if (_reader.Sink("\""))
            {
                while (_reader.CurrentCharacter == '\\' || _reader.MatchRegularStringLiteral())
                {
                    // See if we have an escape sequence.
                    if (_reader.SinkCharacter() == '\\')
                    {
                        // This is probably an escape character.
                        if (_reader.SinkStringEscape())
                        {
                            // This isn't nearly right. We just do barely enough to make a string
                            // with an embedded escape sequence return _some_ string whose start and 
                            // end match the real bounds of the string.
                        }
                        else
                        {
                            // This is a compiler error. 
                            _reader.SinkCharacter();
                            current = new CSharpTokenizer.UnrecognizedStringEscapeToken();
                            return true;
                        }
                    }
                }

                // Is it a newline?
                if (TokenChar.IsNewLine(_reader.CurrentCharacter))
                {
                    current = new CSharpTokenizer.NewlineInsideStringToken();
                    return true;
                }

                // Create the token.
                if (_reader.SinkCharacter() != '\"')
                {
                    Debug.Assert(false, "Defect in tokenizer: Should have yielded a terminating quote.");
                }
                current = new StringLiteralToken();
                return true;
            }
            // Identifier or keyword?
            else if
            (
                // From 2.4.2 Identifiers: A '@' can be used to prefix an identifier so that a keyword can be used as an identifier.
                _reader.CurrentCharacter == '@' ||
                _reader.MatchNextIdentifierStart()
            )
            {
                if (_reader.CurrentCharacter == '@')
                {
                    _reader.SinkCharacter();
                }

                // Now, the next character must be an identifier start.
                if (!_reader.SinkIdentifierStart())
                {
                    current = new ExpectedIdentifierToken();
                    return true;
                }

                // Sink the rest of the identifier.                     
                while (_reader.SinkIdentifierPart())
                {
                }
                string identifierOrKeyword = _reader.GetCurrentMatchedString(startPosition);

                switch (identifierOrKeyword)
                {
                    default:

                        if (Array.IndexOf(s_keywordList, identifierOrKeyword) >= 0)
                        {
                            current = new KeywordToken();
                            return true;
                        }

                        // If the identifier starts with '@' then we need to strip it off.
                        // The '@' is for escaping so that we can have an identifier called
                        // the same thing as a reserved keyword (i.e. class, if, foreach, etc)
                        string identifier = _reader.GetCurrentMatchedString(startPosition);
                        if (identifier.StartsWith("@", StringComparison.Ordinal))
                        {
                            identifier = identifier.Substring(1);
                        }

                        // Create the token.
                        current = new IdentifierToken();
                        current.InnerText = identifier;
                        return true;
                    case "false":
                    case "true":
                        current = new BooleanLiteralToken();
                        return true;
                    case "null":
                        current = new CSharpTokenizer.NullLiteralToken();
                        return true;
                }
            }
            // Open scope
            else if (_reader.Sink("{"))
            {
                current = new CSharpTokenizer.OpenScopeToken();
                return true;
            }
            // Close scope
            else if (_reader.Sink("}"))
            {
                current = new CSharpTokenizer.CloseScopeToken();
                return true;
            }
            // Hexidecimal integer literal
            else if (_reader.SinkIgnoreCase("0x"))
            {
                // Sink the hex digits.
                if (!_reader.SinkMultipleHexDigits())
                {
                    current = new ExpectedValidHexDigitToken();
                    return true;
                }

                // Skip the L, U, l, u, ul, etc.                    
                _reader.SinkLongIntegerSuffix();

                current = new HexIntegerLiteralToken();
                return true;
            }
            // Decimal integer literal
            else if (_reader.SinkMultipleDecimalDigits())
            {
                // reader.Skip the L, U, l, u, ul, etc.                    
                _reader.SinkLongIntegerSuffix();

                current = new DecimalIntegerLiteralToken();
                return true;
            }
            // Check for single-digit operators and punctuators
            else if (_reader.SinkOperatorOrPunctuator())
            {
                current = new OperatorOrPunctuatorToken();
                return true;
            }
            // Preprocessor line
            else if (_reader.CurrentCharacter == '#')
            {
                if (_reader.Sink("#if"))
                {
                    current = new OpenConditionalDirectiveToken();
                }
                else if (_reader.Sink("#endif"))
                {
                    current = new CloseConditionalDirectiveToken();
                }
                else
                {
                    current = new PreprocessorToken();
                }

                _reader.SinkToEndOfLine();

                return true;
            }

            // We didn't recognize the token, so this is a syntax error. 
            _reader.SinkCharacter();
            current = new UnrecognizedToken();
            return true;
        }

        private static readonly string[] s_keywordList =
                                              { "abstract",  "as",  "base",  "bool",  "break",
                                                "byte",  "case",  "catch",  "char",  "checked",
                                                "class",  "const",  "continue",  "decimal",  "default",
                                                "delegate",  "do",  "double",  "else",  "enum",
                                                "event",  "explicit",  "extern",  "finally",  "fixed",
                                                "float",  "for",  "foreach",  "goto",  "if",
                                                "implicit",  "in",  "int",  "interface",  "internal",
                                                "is",  "lock",  "long",  "namespace",  "new",
                                                "object",  "operator",  "out",  "override",  "params",
                                                "private",  "protected",  "public",  "readonly",
                                                "ref",  "return",  "sbyte",  "sealed",  "short",
                                                "sizeof",  "stackalloc",  "static",  "string",
                                                "struct",  "switch",  "this",  "throw",  "try",
                                                "typeof",  "uint",  "ulong",  "unchecked",  "unsafe",
                                                "ushort",  "using",  "virtual",  "void",  "volatile",
                                                "while" };


        /*
        * Method:  Reader
        * 
        * Return the token char reader.
        */
        override internal TokenCharReader Reader
        {
            get
            {
                return _reader;
            }
        }
    }
}


<|start_filename|>src/Tasks.UnitTests/AssemblyDependency/AssemblyFoldersFromConfig_Tests.cs<|end_filename|>
﻿using System.IO;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using Microsoft.Build.UnitTests;
using Microsoft.Build.UnitTests.ResolveAssemblyReference_Tests;
using Microsoft.Build.Utilities;
using Shouldly;
using Xunit;
using Xunit.Abstractions;

namespace Microsoft.Build.Tasks.UnitTests.AssemblyDependency
{
    public class AssemblyFoldersFromConfig_Tests : ResolveAssemblyReferenceTestFixture
    {
        public AssemblyFoldersFromConfig_Tests(ITestOutputHelper output) : base(output)
        {
            s_existentFiles.AddRange(new[]
            {
                Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder1", "assemblyfromconfig1.dll"),
                Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder2", "assemblyfromconfig2.dll"),
                Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder3_x86", "assemblyfromconfig3_x86.dll"),

                Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder_x86", "assemblyfromconfig_common.dll"),
                Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder_x64", "assemblyfromconfig_common.dll"),
                Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder5010x64", "v5assembly.dll"),
                Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder501000x86", "v5assembly.dll")
            });
        }
        
        [Fact]
        public void AssemblyFoldersFromConfigTest()
        {
            var assemblyConfig = Path.GetTempFileName();
            File.WriteAllText(assemblyConfig, TestFile);

            var moniker = "{AssemblyFoldersFromConfig:" + assemblyConfig + ",v4.5}";

            try
            {
                ResolveAssemblyReference t = new ResolveAssemblyReference
                {
                    BuildEngine = new MockEngine(_output),
                    Assemblies = new ITaskItem[] {new TaskItem("assemblyfromconfig2")},
                    SearchPaths = new[] {moniker}
                };
                
                Execute(t);

                Assert.Single(t.ResolvedFiles);
                Assert.Equal(Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder2", "assemblyfromconfig2.dll"), t.ResolvedFiles[0].ItemSpec);
                t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(moniker, StringCompareShould.IgnoreCase);
            }
            finally
            {
                FileUtilities.DeleteNoThrow(assemblyConfig);
            }
        }

        [Fact]
        public void AssemblyFoldersFromConfigPlatformSpecificAssemblyFirstTest()
        {
            var assemblyConfig = Path.GetTempFileName();
            File.WriteAllText(assemblyConfig, TestFile);

            var moniker = "{AssemblyFoldersFromConfig:" + assemblyConfig + ",v4.5}";

            try
            {
                ResolveAssemblyReference t = new ResolveAssemblyReference
                {
                    BuildEngine = new MockEngine(_output),
                    Assemblies = new ITaskItem[] {new TaskItem("assemblyfromconfig_common.dll")},
                    SearchPaths = new[] {moniker},
                    TargetProcessorArchitecture = "x86"
                };

                Execute(t);

                Assert.Single(t.ResolvedFiles);
                Assert.Equal(Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder_x86", "assemblyfromconfig_common.dll"), t.ResolvedFiles[0].ItemSpec);
                t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(moniker, StringCompareShould.IgnoreCase);
            }
            finally
            {
                FileUtilities.DeleteNoThrow(assemblyConfig);
            }
        }

        [Fact]
        public void AssemblyFoldersFromConfigNormalizeNetFrameworkVersion()
        {
            var assemblyConfig = Path.GetTempFileName();
            File.WriteAllText(assemblyConfig, TestFile);

            var moniker = "{AssemblyFoldersFromConfig:" + assemblyConfig + ",v5.0}";

            try
            {
                ResolveAssemblyReference t = new ResolveAssemblyReference
                {
                    BuildEngine = new MockEngine(_output),
                    Assemblies = new ITaskItem[] { new TaskItem("v5assembly.dll") },
                    SearchPaths = new[] { moniker },
                    TargetProcessorArchitecture = "x86"
                };

                Execute(t);

                Assert.Single(t.ResolvedFiles);
                Assert.Equal(Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder501000x86", "v5assembly.dll"), t.ResolvedFiles[0].ItemSpec);
                t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(moniker, StringCompareShould.IgnoreCase);

                // Try again changing only the processor architecture
                t = new ResolveAssemblyReference
                {
                    BuildEngine = new MockEngine(_output),
                    Assemblies = new ITaskItem[] { new TaskItem("v5assembly.dll") },
                    SearchPaths = new[] { moniker },
                    TargetProcessorArchitecture = "AMD64"
                };

                Execute(t);

                Assert.Single(t.ResolvedFiles);
                Assert.Equal(Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder5010x64", "v5assembly.dll"), t.ResolvedFiles[0].ItemSpec);
                t.ResolvedFiles[0].GetMetadata("ResolvedFrom").ShouldBe(moniker, StringCompareShould.IgnoreCase);
            }
            finally
            {
                FileUtilities.DeleteNoThrow(assemblyConfig);
            }
        }

        [Fact]
        public void AssemblyFoldersFromConfigFileNotFoundTest()
        {
            var assemblyConfig = Path.GetTempFileName();
            File.Delete(assemblyConfig);
            var moniker = "{AssemblyFoldersFromConfig:" + assemblyConfig + ",v4.5}";

            try
            {
                ResolveAssemblyReference t = new ResolveAssemblyReference
                {
                    BuildEngine = new MockEngine(_output),
                    Assemblies = new ITaskItem[] {new TaskItem("assemblyfromconfig_common.dll")},
                    SearchPaths = new[] {moniker},
                    TargetProcessorArchitecture = "x86"
                };


                Assert.Throws<InternalErrorException>(() => Execute(t));
            }
            finally
            {
                FileUtilities.DeleteNoThrow(assemblyConfig);
            }
        }

        [Fact]
        public void AssemblyFoldersFromConfigFileMalformed()
        {
            var assemblyConfig = Path.GetTempFileName();
            File.WriteAllText(assemblyConfig, "<<<>><>!" + TestFile);

            var moniker = "{AssemblyFoldersFromConfig:" + assemblyConfig + ",v4.5}";

            try
            {
                MockEngine engine = new MockEngine(_output);
                ResolveAssemblyReference t = new ResolveAssemblyReference
                {
                    BuildEngine = engine,
                    Assemblies = new ITaskItem[] { new TaskItem("assemblyfromconfig2") },
                    SearchPaths = new[] { moniker }
                };

                var success = Execute(t);

                Assert.False(success);
                Assert.Empty(t.ResolvedFiles);
                engine.AssertLogContains(") specified in Microsoft.Common.CurrentVersion.targets was invalid. The error was: ");
            }
            finally
            {
                FileUtilities.DeleteNoThrow(assemblyConfig);
            }
        }

        private readonly string TestFile = @"
<AssemblyFoldersConfig>
  <AssemblyFolders>
    <AssemblyFolder>
      <Name>Test Assemblies</Name>
      <FrameworkVersion>v5.0</FrameworkVersion>
      <Path>" + Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder1") + @"</Path>
    </AssemblyFolder>
    <AssemblyFolder>
      <Name>Test Assemblies2</Name>
      <FrameworkVersion>v4.5.25000</FrameworkVersion>
      <Path>" + Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder2") + @"</Path>
    </AssemblyFolder>
    <AssemblyFolder>
      <FrameworkVersion>v4.0</FrameworkVersion>
      <Path>" + Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder3") + @"</Path>
    </AssemblyFolder>
    <AssemblyFolder>
      <Name>Platform Specific</Name>
      <FrameworkVersion>v4.5.25000</FrameworkVersion>
      <Path>" + Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder_x64") + @"</Path>
      <Platform>x64</Platform>
    </AssemblyFolder>
    <AssemblyFolder>
      <FrameworkVersion>v4.5</FrameworkVersion>
      <Path>" + Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder_x86") + @"</Path>
      <Platform>x86</Platform>
    </AssemblyFolder>

    <AssemblyFolder>
      <FrameworkVersion>v5.0.1.0</FrameworkVersion>
      <Path>" + Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder5010x64") + @"</Path>
      <Platform>x64</Platform>
    </AssemblyFolder>
    <AssemblyFolder>
      <FrameworkVersion>v5.0.100.0</FrameworkVersion>
      <Path>" + Path.Combine(s_rootPathPrefix, "assemblyfromconfig", "folder501000x86") + @"</Path>
      <Platform>x86</Platform>
    </AssemblyFolder>
  </AssemblyFolders>
</AssemblyFoldersConfig>
";
    }
}


<|start_filename|>src/Tasks.UnitTests/XamlDataDrivenToolTask_Tests.cs<|end_filename|>
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.IO;
using System.Reflection;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Shared;
using Xunit;

namespace Microsoft.Build.UnitTests.XamlDataDrivenToolTask_Tests
{
    /// <summary>
    /// Test fixture for testing the DataDrivenToolTask class with a fake task generated by XamlTestHelpers.cs
    /// Tests to see if certain switches are appended.
    /// </summary>
    public class GeneratedTask
    {
        private Assembly _fakeTaskDll;

        public GeneratedTask()
        {
            _fakeTaskDll = XamlTestHelpers.SetupGeneratedCode();
        }

        /// <summary>
        /// Test to see whether all of the correct boolean switches are appended.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestDefaultFlags()
        {
            object fakeTaskInstance = CreateFakeTask();
            CheckCommandLine("/always /Cr:CT", XamlTestHelpers.GenerateCommandLine(fakeTaskInstance));
        }

        /// <summary>
        /// A test to see if all of the reversible flags are generated correctly
        /// This test case leaves the default flags the way they are
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestReversibleFlagsWithDefaults()
        {
            object fakeTaskInstance = CreateFakeTask();
            XamlTestHelpers.SetProperty(fakeTaskInstance, "BasicReversible", true);
            string expectedResult = "/always /Br /Cr:CT";
            CheckCommandLine(expectedResult, XamlTestHelpers.GenerateCommandLine(fakeTaskInstance));
        }

        /// <summary>
        /// A test to see if all of the reversible flags are generated correctly
        /// This test case explicitly sets the ComplexReversible to be false
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestReversibleFlagsWithoutDefaults()
        {
            object fakeTaskInstance = CreateFakeTask();
            XamlTestHelpers.SetProperty(fakeTaskInstance, "BasicReversible", true);
            XamlTestHelpers.SetProperty(fakeTaskInstance, "ComplexReversible", false);
            string expectedResult = "/always /Br /Cr:CF";
            CheckCommandLine(expectedResult, XamlTestHelpers.GenerateCommandLine(fakeTaskInstance));
        }

        /// <summary>
        /// Tests to make sure enums are working well.
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestBasicString()
        {
            object fakeTaskInstance = CreateFakeTask();
            XamlTestHelpers.SetProperty(fakeTaskInstance, "BasicString", "Enum1");
            string expectedResult = "/always /Bs1 /Cr:CT";
            CheckCommandLine(expectedResult, XamlTestHelpers.GenerateCommandLine(fakeTaskInstance));
        }

        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestDynamicEnum()
        {
            object fakeTaskInstance = CreateFakeTask();
            XamlTestHelpers.SetProperty(fakeTaskInstance, "BasicDynamicEnum", "MyBeforeTarget");
            string expectedResult = "/always MyBeforeTarget /Cr:CT";
            CheckCommandLine(expectedResult, XamlTestHelpers.GenerateCommandLine(fakeTaskInstance));
        }

        /// <summary>
        /// Tests the basic string array type 
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestBasicStringArray()
        {
            object fakeTaskInstance = CreateFakeTask();
            string[] fakeArray = new string[1];
            fakeArray[0] = "FakeStringArray";
            XamlTestHelpers.SetProperty(fakeTaskInstance, "BasicStringArray", new object[] { fakeArray });
            string expectedResult = "/always /BsaFakeStringArray /Cr:CT";
            CheckCommandLine(expectedResult, XamlTestHelpers.GenerateCommandLine(fakeTaskInstance));
        }

        /// <summary>
        /// Tests the basic string array type, with an array that contains multiple values. 
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestBasicStringArray_MultipleValues()
        {
            object fakeTaskInstance = CreateFakeTask();
            string[] fakeArray = new string[3];
            fakeArray[0] = "Fake";
            fakeArray[1] = "String";
            fakeArray[2] = "Array";
            XamlTestHelpers.SetProperty(fakeTaskInstance, "BasicStringArray", new object[] { fakeArray });
            string expectedResult = "/always /BsaFake /BsaString /BsaArray /Cr:CT";
            CheckCommandLine(expectedResult, XamlTestHelpers.GenerateCommandLine(fakeTaskInstance));
        }

        /// <summary>
        /// Tests to see whether the integer appears correctly on the command line
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestInteger()
        {
            object fakeTaskInstance = CreateFakeTask();
            XamlTestHelpers.SetProperty(fakeTaskInstance, "BasicInteger", 2);
            string expectedResult = "/always /Bi2 /Cr:CT";
            CheckCommandLine(expectedResult, XamlTestHelpers.GenerateCommandLine(fakeTaskInstance));
        }

        // complex tests
        /// <summary>
        /// Tests the (full) functionality of a reversible property
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestComplexReversible()
        {
            // When flag is set to false
            object fakeTaskInstance = CreateFakeTask();
            XamlTestHelpers.SetProperty(fakeTaskInstance, "ComplexReversible", false);
            string expectedResult = "/always /Cr:CF";
            CheckCommandLine(expectedResult, XamlTestHelpers.GenerateCommandLine(fakeTaskInstance));

            // When flag is set to true
            fakeTaskInstance = CreateFakeTask();
            XamlTestHelpers.SetProperty(fakeTaskInstance, "ComplexReversible", true);
            expectedResult = "/always /Cr:CT";
            CheckCommandLine(expectedResult, XamlTestHelpers.GenerateCommandLine(fakeTaskInstance));
        }

        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestComplexString()
        {
            // check to see that the resulting value is good
            object fakeTaskInstance = CreateFakeTask();
            XamlTestHelpers.SetProperty(fakeTaskInstance, "ComplexString", "LegalValue1");
            string expectedResult = "/always /Cr:CT /Lv1";
            CheckCommandLine(expectedResult, XamlTestHelpers.GenerateCommandLine(fakeTaskInstance));
        }

        /// <summary>
        /// Tests the functionality of a string type property
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestComplexStringArray()
        {
            object fakeTaskInstance = CreateFakeTask();
            string[] fakeArray = new string[] { "FakeFile1", "FakeFile2", "FakeFile3" };
            XamlTestHelpers.SetProperty(fakeTaskInstance, "ComplexStringArray", new object[] { fakeArray });
            string expectedResult = "/always /Cr:CT /CsaFakeFile1;FakeFile2;FakeFile3";
            CheckCommandLine(expectedResult, XamlTestHelpers.GenerateCommandLine(fakeTaskInstance));
        }

        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestComplexIntegerLessThanMin()
        {
            Assert.Throws<InvalidOperationException>(() =>
            {
                object fakeTaskInstance = CreateFakeTask();
                XamlTestHelpers.SetProperty(fakeTaskInstance, "ComplexInteger", 2);
            }
           );
        }

        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestComplexIntegerGreaterThanMax()
        {
            Assert.Throws<InvalidOperationException>(() =>
            {
                object fakeTaskInstance = CreateFakeTask();
                XamlTestHelpers.SetProperty(fakeTaskInstance, "ComplexInteger", 256);
                string expectedResult = "/always /Ci256 /Cr:CT";
                CheckCommandLine(expectedResult, XamlTestHelpers.GenerateCommandLine(fakeTaskInstance));
            }
           );
        }
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void TestComplexIntegerWithinRange()
        {
            object fakeTaskInstance = CreateFakeTask();
            XamlTestHelpers.SetProperty(fakeTaskInstance, "ComplexInteger", 128);
            string expectedResult = "/always /Cr:CT /Ci128";
            CheckCommandLine(expectedResult, XamlTestHelpers.GenerateCommandLine(fakeTaskInstance));
        }

        /// <summary>
        /// This method checks the generated command line against the expected command line
        /// </summary>
        /// <param name="expected"></param>
        /// <param name="actual"></param>
        /// <returns>true if the two are the same, false if they are different</returns>
        private void CheckCommandLine(string expected, string actual)
        {
            Assert.Equal(expected, actual);
        }

        /// <summary>
        /// XamlTaskFactory does not, in and of itself, support the idea of "always" switches or default values.  At least 
        /// for Dev10, the workaround is to create a property as usual, and then specify the required values in the .props 
        /// file.  Since these unit tests are just testing the task itself, this method serves as our ".props file".  
        /// </summary>
        public object CreateFakeTask()
        {
            object fakeTaskInstance = _fakeTaskDll.CreateInstance("XamlTaskNamespace.FakeTask");

            XamlTestHelpers.SetProperty(fakeTaskInstance, "Always", true);
            XamlTestHelpers.SetProperty(fakeTaskInstance, "ComplexReversible", true);

            return fakeTaskInstance;
        }
    }

    /// <summary>
    /// Tests for XamlDataDrivenToolTask / XamlTaskFactory in the context of a project file.  
    /// </summary>
    public class ProjectFileTests
    {
        /// <summary>
        /// Tests that when a call to a XamlDataDrivenTask fails, the commandline is reported in the error message. 
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void CommandLineErrorsReportFullCommandlineAmpersandTemp()
        {
            string projectFile = @"
                      <Project ToolsVersion=`msbuilddefaulttoolsversion` DefaultTargets=`XamlTaskFactory` xmlns=`http://schemas.microsoft.com/developer/msbuild/2003`>
                        <UsingTask TaskName=`TestTask` TaskFactory=`XamlTaskFactory` AssemblyName=`Microsoft.Build.Tasks.v4.0, Version=4.0.0.0, Culture=neutral, PublicKeyToken=<KEY>`>
                          <Task>
                            <![CDATA[
                              <ProjectSchemaDefinitions xmlns=`clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework` xmlns:x=`http://schemas.microsoft.com/winfx/2006/xaml` xmlns:sys=`clr-namespace:System;assembly=mscorlib` xmlns:impl=`clr-namespace:Microsoft.VisualStudio.Project.Contracts.Implementation;assembly=Microsoft.VisualStudio.Project.Contracts.Implementation`>
                                <Rule Name=`TestTask` ToolName=`findstr.exe`>
                                  <StringProperty Name=`test` />
                                </Rule>
                              </ProjectSchemaDefinitions>
                            ]]>
                          </Task>
                        </UsingTask>
                        <Target Name=`XamlTaskFactory`>
                          <TestTask CommandLineTemplate='findstr'/>
                        </Target>
                      </Project>";


            string directoryWithAmpersand = "xaml&datadriven";
            string newTmp = Path.Combine(Path.GetTempPath(), directoryWithAmpersand);
            string oldTmp = Environment.GetEnvironmentVariable("TMP");

            try
            {
                Directory.CreateDirectory(newTmp);
                Environment.SetEnvironmentVariable("TMP", newTmp);
                Project p = ObjectModelHelpers.CreateInMemoryProject(projectFile);
                MockLogger logger = new MockLogger();

                bool success = p.Build(logger);
                Assert.False(success);
                logger.AssertLogContains("FINDSTR");

                // Should not be logging ToolTask.ToolCommandFailed, should be logging Xaml.CommandFailed
                logger.AssertLogDoesntContain("MSB6006");
                logger.AssertLogContains("MSB3721");
            }
            finally
            {
                Environment.SetEnvironmentVariable("TMP", oldTmp);
                ObjectModelHelpers.DeleteDirectory(newTmp);
                if (Directory.Exists(newTmp)) FileUtilities.DeleteWithoutTrailingBackslash(newTmp);
            }
        }


        /// <summary>
        /// Tests that when a call to a XamlDataDrivenTask fails, the commandline is reported in the error message. 
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void CommandLineErrorsReportFullCommandline()
        {
            string projectFile = @"
                      <Project ToolsVersion=`msbuilddefaulttoolsversion` DefaultTargets=`XamlTaskFactory` xmlns=`http://schemas.microsoft.com/developer/msbuild/2003`>
                        <UsingTask TaskName=`TestTask` TaskFactory=`XamlTaskFactory` AssemblyName=`Microsoft.Build.Tasks.v4.0, Version=4.0.0.0, Culture=neutral, PublicKeyToken=<KEY>`>
                          <Task>
                            <![CDATA[
                              <ProjectSchemaDefinitions xmlns=`clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework` xmlns:x=`http://schemas.microsoft.com/winfx/2006/xaml` xmlns:sys=`clr-namespace:System;assembly=mscorlib` xmlns:impl=`clr-namespace:Microsoft.VisualStudio.Project.Contracts.Implementation;assembly=Microsoft.VisualStudio.Project.Contracts.Implementation`>
                                <Rule Name=`TestTask` ToolName=`echoparameters.exe`>
                                  <StringProperty Name=`test` />
                                </Rule>
                              </ProjectSchemaDefinitions>
                            ]]>
                          </Task>
                        </UsingTask>
                        <Target Name=`XamlTaskFactory`>
                          <TestTask CommandLineTemplate=`where /x` />
                        </Target>
                      </Project>";

            Project p = ObjectModelHelpers.CreateInMemoryProject(projectFile);
            MockLogger logger = new MockLogger();

            bool success = p.Build(logger);

            Assert.False(success); // "Build should have failed"

            // Should not be logging ToolTask.ToolCommandFailed, should be logging Xaml.CommandFailed
            logger.AssertLogDoesntContain("MSB6006");
            logger.AssertLogContains("MSB3721");
        }

        /// <summary>
        /// Tests that when a call to a XamlDataDrivenTask fails, the commandline is reported in the error message. 
        /// </summary>
        [Fact]
        [Trait("Category", "mono-osx-failing")]
        public void SquareBracketEscaping()
        {
            string projectFile = @"
                      <Project ToolsVersion=`msbuilddefaulttoolsversion` DefaultTargets=`XamlTaskFactory` xmlns=`http://schemas.microsoft.com/developer/msbuild/2003`>
                        <UsingTask TaskName=`TestTask` TaskFactory=`XamlTaskFactory` AssemblyName=`Microsoft.Build.Tasks.v4.0, Version=4.0.0.0, Culture=neutral, PublicKeyToken=<KEY>`>
                          <Task>
                            <![CDATA[
                              <ProjectSchemaDefinitions xmlns=`clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework` xmlns:x=`http://schemas.microsoft.com/winfx/2006/xaml` xmlns:sys=`clr-namespace:System;assembly=mscorlib` xmlns:impl=`clr-namespace:Microsoft.VisualStudio.Project.Contracts.Implementation;assembly=Microsoft.VisualStudio.Project.Contracts.Implementation`>
                                <Rule Name=`TestTask` ToolName=`echoparameters.exe`>
                                  <StringProperty Name=`test` />
                                </Rule>
                              </ProjectSchemaDefinitions>
                            ]]>
                          </Task>
                        </UsingTask>
                        <Target Name=`XamlTaskFactory`>
                          <TestTask CommandLineTemplate=`echo  1) [test]            end` test=`value` />
                          <TestTask CommandLineTemplate=`echo  2) [[[test]           end` test=`value` />
                          <TestTask CommandLineTemplate=`echo  3) [ [test]          end` test=`value` />
                          <TestTask CommandLineTemplate=`echo  4) [ [test] [test]    end` test=`value` />
                          <TestTask CommandLineTemplate=`echo  5) [test]]           end` test=`value` />
                          <TestTask CommandLineTemplate=`echo  6) [[test]]          end` test=`value` />
                          <TestTask CommandLineTemplate=`echo  7) [[[test]]          end` test=`value` />
                          <TestTask CommandLineTemplate=`echo  8) [notaproperty]   end` test=`value` />
                          <TestTask CommandLineTemplate=`echo  9) [[[notaproperty]  end` test=`value` />
                          <TestTask CommandLineTemplate=`echo 10) [ [notaproperty] end` test=`value` />
                          <TestTask CommandLineTemplate=`echo 11) [ [nap] [nap]    end` test=`value` />
                          <TestTask CommandLineTemplate=`echo 12) [notaproperty]]  end` test=`value` />
                          <TestTask CommandLineTemplate=`echo 13) [[notaproperty]]  end` test=`value` />
                          <TestTask CommandLineTemplate=`echo 14) [[[notaproperty]] end` test=`value` />
                        </Target>
                      </Project>";

            Project p = ObjectModelHelpers.CreateInMemoryProject(projectFile);
            MockLogger logger = new MockLogger();

            bool success = p.Build(logger);

            Assert.True(success); // "Build should have succeeded"

            logger.AssertLogContains("echo  1) value            end");
            logger.AssertLogContains("echo  2) [value           end");
            logger.AssertLogContains("echo  3) [ value          end");
            logger.AssertLogContains("echo  4) [ value value    end");
            logger.AssertLogContains("echo  5) value]           end");
            logger.AssertLogContains("echo  6) [test]]          end");
            logger.AssertLogContains("echo  7) [value]          end");
            logger.AssertLogContains("echo  8) [notaproperty]   end");
            logger.AssertLogContains("echo  9) [[notaproperty]  end");
            logger.AssertLogContains("echo 10) [ [notaproperty] end");
            logger.AssertLogContains("echo 11) [ [nap] [nap]    end");
            logger.AssertLogContains("echo 12) [notaproperty]]  end");
            logger.AssertLogContains("echo 13) [notaproperty]]  end");
            logger.AssertLogContains("echo 14) [[notaproperty]] end");
        }
    }
}


<|start_filename|>src/Shared/AssemblyFolders/AssemblyFoldersEx.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if FEATURE_WIN32_REGISTRY

using System;
using System.Collections;
using System.Collections.Generic;
using Microsoft.Build.Tasks;
using Microsoft.Build.Utilities;
using Microsoft.Win32;
using ProcessorArchitecture = System.Reflection.ProcessorArchitecture;

namespace Microsoft.Build.Shared
{
    /// <summary>
    /// Implements the rules for finding component directories using the AssemblyFoldersEx scheme.
    ///
    /// This is the normal schema:
    ///
    ///  [HKLM | HKCU]\SOFTWARE\MICROSOFT\.NetFramework\ 
    ///    v1.0.3705 
    ///      AssemblyFoldersEx 
    ///          Infragistics.GridControl.1.0:  
    ///              @Default = c:\program files\infragistics\grid control\1.0\bin 
    ///              @Description = Infragistics Grid Control for .NET version 1.0 
    ///              9466 
    ///                  @Default = c:\program files\infragistics\grid control\1.0sp1\bin 
    ///                  @Description = SP1 for Infragistics Grid Control for .NET version 1.0 
    ///
    /// 
    /// The root registry path is the following:
    ///
    ///     [HKLM | HKCU]\{AssemblyFoldersBase}\{RuntimeVersion}\{AssemblyFoldersSuffix}
    ///
    /// Where:
    ///
    ///     {AssemblyFoldersBase} = Software\Microsoft\[.NetFramework | .NetCompactFramework]
    ///     {RuntimeVersion} = the runtime version property from the project file
    ///     {AssemblyFoldersSuffix} = [ PocketPC | SmartPhone | WindowsCE]\AssemblyFoldersEx
    ///
    /// </summary>
    internal class AssemblyFoldersEx : IEnumerable<AssemblyFoldersExInfo>
    {
        /// <summary>
        /// The list of directory names found from the registry.
        /// </summary>
        private List<AssemblyFoldersExInfo> _directoryNames = new List<AssemblyFoldersExInfo>();

        /// <summary>
        /// Set of unique paths to directories found from the registry
        /// </summary>
        private HashSet<string> _uniqueDirectoryPaths = new HashSet<string>();

        /// <summary>
        /// Construct.
        /// </summary>
        /// <param name="registryKeyRoot">Like Software\Microsoft\[.NetFramework | .NetCompactFramework]</param>
        /// <param name="targetRuntimeVersion">The runtime version property from the project file.</param>
        /// <param name="registryKeySuffix">Like [ PocketPC | SmartPhone | WindowsCE]\AssemblyFoldersEx</param>
        /// <param name="osVersion">Operating system version</param>
        /// <param name="platform">Current platform</param>
        /// <param name="getRegistrySubKeyNames">Used to find registry subkey names.</param>
        /// <param name="getRegistrySubKeyDefaultValue">Used to find registry key default values.</param>
        /// <param name="targetProcessorArchitecture">Architecture to seek.</param>
        /// <param name="openBaseKey">Key object to open.</param>
        internal AssemblyFoldersEx
        (
            string registryKeyRoot,
            string targetRuntimeVersion,
            string registryKeySuffix,
            string osVersion,
            string platform,
            GetRegistrySubKeyNames getRegistrySubKeyNames,
            GetRegistrySubKeyDefaultValue getRegistrySubKeyDefaultValue,
            ProcessorArchitecture targetProcessorArchitecture,
            OpenBaseKey openBaseKey
        )
        {
            // No extensions are supported, except on Windows
            if (!NativeMethodsShared.IsWindows)
            {
                return;
            }

            bool is64bitOS = EnvironmentUtilities.Is64BitOperatingSystem;
            bool targeting64bit = targetProcessorArchitecture == ProcessorArchitecture.Amd64 || targetProcessorArchitecture == ProcessorArchitecture.IA64;

            // The registry lookup should be as follows:
            /* 64 bit OS:
            *            Targeting 64 bit:
            *                First, look in 64 bit registry location
            *                Second, look in 32 bit registry location
            *            Targeting X86 or MSIL:
            *                First,  look in the 32 bit hive 
            *                Second, look in 64 bit hive
            *
            *  32 bit OS:           
            *        32 bit process:
            *            Targeting 64 bit, or X86, or MSIL:
            *                Look in the default registry which is the 32 bit hive
            */

            // Under WOW64 the HKEY_CURRENT_USER\SOFTWARE key is shared. This means the values are the same in the 64 bit and 32 bit views. This means we only need to get one view of this key.
            FindDirectories(RegistryView.Default, RegistryHive.CurrentUser, registryKeyRoot, targetRuntimeVersion, registryKeySuffix, osVersion, platform, getRegistrySubKeyNames, getRegistrySubKeyDefaultValue, openBaseKey);

            if (is64bitOS)
            {
                // Under WOW64 the HKEY_LOCAL_MACHINE\SOFTWARE key is redirected. This means the values can be different in the 64 bit and 32 bit views. This means we only need to get look at both keys.

                if (targeting64bit)
                {
                    FindDirectories(RegistryView.Registry64, RegistryHive.LocalMachine, registryKeyRoot, targetRuntimeVersion, registryKeySuffix, osVersion, platform, getRegistrySubKeyNames, getRegistrySubKeyDefaultValue, openBaseKey);
                    FindDirectories(RegistryView.Registry32, RegistryHive.LocalMachine, registryKeyRoot, targetRuntimeVersion, registryKeySuffix, osVersion, platform, getRegistrySubKeyNames, getRegistrySubKeyDefaultValue, openBaseKey);
                }
                else
                {
                    FindDirectories(RegistryView.Registry32, RegistryHive.LocalMachine, registryKeyRoot, targetRuntimeVersion, registryKeySuffix, osVersion, platform, getRegistrySubKeyNames, getRegistrySubKeyDefaultValue, openBaseKey);
                    FindDirectories(RegistryView.Registry64, RegistryHive.LocalMachine, registryKeyRoot, targetRuntimeVersion, registryKeySuffix, osVersion, platform, getRegistrySubKeyNames, getRegistrySubKeyDefaultValue, openBaseKey);
                }
            }
            else
            {
                FindDirectories(RegistryView.Default, RegistryHive.LocalMachine, registryKeyRoot, targetRuntimeVersion, registryKeySuffix, osVersion, platform, getRegistrySubKeyNames, getRegistrySubKeyDefaultValue, openBaseKey);
            }
        }

        /// <summary>
        /// Finds directories for a specific registry key.
        /// </summary>
        /// <param name="view">The registry view to examine.</param>
        /// <param name="hive">The registry hive to examine.</param>
        /// <param name="registryKeyRoot">Like Software\Microsoft\[.NetFramework | .NetCompactFramework]</param>
        /// <param name="targetRuntimeVersion">The runtime version property from the project file.</param>
        /// <param name="registryKeySuffix">Like [ PocketPC | SmartPhone | WindowsCE]\AssemblyFoldersEx</param>
        /// <param name="osVersion">Operating system version</param>
        /// <param name="platform">Current platform</param>
        /// <param name="getRegistrySubKeyNames">Used to find registry subkey names.</param>
        /// <param name="getRegistrySubKeyDefaultValue">Used to find registry key default values.</param>
        /// <param name="openBaseKey">Key object to open.</param>
        private void FindDirectories
        (
            RegistryView view,
            RegistryHive hive,
            string registryKeyRoot,
            string targetRuntimeVersion,
            string registryKeySuffix,
            string osVersion,
            string platform,
            GetRegistrySubKeyNames getRegistrySubKeyNames,
            GetRegistrySubKeyDefaultValue getRegistrySubKeyDefaultValue,
            OpenBaseKey openBaseKey
        )
        {
            // Open the hive for a given view
            using (RegistryKey baseKey = openBaseKey(hive, view))
            {
                IEnumerable<string> versions = getRegistrySubKeyNames(baseKey, registryKeyRoot);

                // No versions found.
                if (versions == null)
                {
                    return;
                }

                List<ExtensionFoldersRegistryKey> versionStrings = GatherVersionStrings(targetRuntimeVersion, versions);

                // Loop the versions, looking for component keys.
                List<ExtensionFoldersRegistryKey> componentKeys = new List<ExtensionFoldersRegistryKey>();

                foreach (ExtensionFoldersRegistryKey versionString in versionStrings)
                {
                    // Make like SOFTWARE\MICROSOFT\.NetFramework\v2.0.x86chk\AssemblyFoldersEx
                    string fullVersionKey = registryKeyRoot + @"\" + versionString.RegistryKey + @"\" + registryKeySuffix;
                    IEnumerable<string> components = getRegistrySubKeyNames(baseKey, fullVersionKey);

                    if (components != null)
                    {
                        // Sort the components in reverse alphabetical order so values with higher alphabetical names are earlier in the array.
                        // This is to try and get newer versioned components based on the fact they should have higher versioned names.
                        List<string> sortedComponents = new List<string>();

                        foreach (string component in components)
                        {
                            sortedComponents.Add(component);
                        }

                        // The reason we sort here rather than on the component keys is that we do not want to sort using the FullVersionKey
                        // the versions have already been sorted (with things that look like raw drops being tacked onto the bottom of the list after sorting)
                        // By sorting the versions again we will get these raw drop numbers possibly being somewhere other than at the bottom and thereby cause the resolver
                        // to find the assembly in the wrong location.
                        sortedComponents.Sort(ReverseStringGenericComparer.Comparer);

                        foreach (string component in sortedComponents)
                        {
                            // ComponentKeys are like SOFTWARE\MICROSOFT\.NetFramework\v1.0.x86chk\AssemblyFoldersEx\Infragistics.GridControl.1.0
                            componentKeys.Add(new ExtensionFoldersRegistryKey(fullVersionKey + @"\" + component, versionString.TargetFrameworkVersion));
                        }
                    }
                }

                // Loop the component keys, looking for servicing keys.
                List<ExtensionFoldersRegistryKey> directoryKeys = new List<ExtensionFoldersRegistryKey>();

                foreach (ExtensionFoldersRegistryKey componentKey in componentKeys)
                {
                    IEnumerable<string> servicingKeys = getRegistrySubKeyNames(baseKey, componentKey.RegistryKey);

                    if (servicingKeys != null)
                    {
                        List<string> fullServicingKeys = new List<string>();

                        foreach (string servicingKey in servicingKeys)
                        {
                            // ServicingKeys are like SOFTWARE\MICROSOFT\.NetFramework\v1.0.3705\AssemblyFoldersEx\Infragistics.GridControl.1.0\9120
                            fullServicingKeys.Add(componentKey.RegistryKey + @"\" + servicingKey);
                        }

                        // Alphabetize to put them in version order.
                        fullServicingKeys.Sort(ReverseStringGenericComparer.Comparer);
                        foreach (string key in fullServicingKeys)
                        {
                            directoryKeys.Add(new ExtensionFoldersRegistryKey(key, componentKey.TargetFrameworkVersion));
                        }

                        directoryKeys.Add(componentKey);
                    }
                }

                // Now, we have a properly ordered collection of registry keys, each of which
                // should point to a default value with a file path. Get those files paths.
                foreach (ExtensionFoldersRegistryKey directoryKey in directoryKeys)
                {
                    if (!(String.IsNullOrEmpty(platform) && String.IsNullOrEmpty(osVersion)))
                    {
                        using (RegistryKey keyPlatform = baseKey.OpenSubKey(directoryKey.RegistryKey, false))
                        {
                            if (keyPlatform?.ValueCount > 0)
                            {
                                if (!string.IsNullOrEmpty(platform))
                                {
                                    string platformValue = keyPlatform.GetValue("Platform", null) as string;

                                    if (!String.IsNullOrEmpty(platformValue) && !MatchingPlatformExists(platform, platformValue))
                                    {
                                        continue;
                                    }
                                }

                                if (!string.IsNullOrEmpty(osVersion))
                                {
                                    Version ver = VersionUtilities.ConvertToVersion(osVersion);

                                    if (!IsVersionInsideRange(ver, keyPlatform))
                                    {
                                        continue;
                                    }
                                }
                            }
                        }
                    }

                    string directoryName = getRegistrySubKeyDefaultValue(baseKey, directoryKey.RegistryKey);

                    if (directoryName != null)
                    {
                        _uniqueDirectoryPaths.Add(directoryName);
                        _directoryNames.Add(new AssemblyFoldersExInfo(hive, view, directoryKey.RegistryKey, directoryName, directoryKey.TargetFrameworkVersion));
                    }
                }
            }
        }

        private bool MatchingPlatformExists(string platform, string platformValue)
        {
            bool match = false;

            if (!string.IsNullOrEmpty(platformValue))
            {
                string[] platforms = platformValue.Split(MSBuildConstants.SemicolonChar);
                foreach (string p in platforms)
                {
                    if (String.Equals(p, platform, StringComparison.OrdinalIgnoreCase))
                    {
                        match = true;
                        break;
                    }
                }
            }

            return match;
        }

        private bool IsVersionInsideRange(Version v, RegistryKey keyPlatform)
        {
            bool insideRange = true;

            if (v != null)
            {
                string minVersionAsString = keyPlatform.GetValue("MinOSVersion", null) as string;
                Version minVersion = minVersionAsString == null ? null : VersionUtilities.ConvertToVersion(minVersionAsString);
                if (minVersion != null && minVersion > v)
                {
                    // Filter keys with MinOSVersion > OSVersion
                    insideRange = false;
                }

                string maxVersionAsString = keyPlatform.GetValue("MaxOSVersion", null) as string;
                Version maxVersion = maxVersionAsString == null ? null : VersionUtilities.ConvertToVersion(maxVersionAsString);
                if (maxVersion != null && maxVersion < v)
                {
                    // Filter keys with MaxOSVersion < OSVersion
                    insideRange = false;
                }
            }

            return insideRange;
        }

        /// <summary>
        ///  The algorithm for gathering versions from the registry is as follows:
        ///     1) targetRuntimeVersion is the target framework version you are targeting
        ///     2) versions is a string list from reading the registry, this list is in what ever order the registry returns 
        ///        the keys to us in, this is usually alphabetical.
        ///     
        ///     We will go through each version string and do the following:
        ///         1) Check to see if the string is a version
        ///             If the string is not a version we will check to see if the string starts with the framework we are targeting,
        ///             if it does we will add it to a list which will be added at the end 
        ///             of the versions list, if not it gets ignored. We do this to stay compatible to what we have been doing since whidbey.
        ///             
        ///             If the string is a version
        ///                 We check to see if the version is a valid target framework version. Meaning.  It has a Maj.Minor version and may have 
        ///                 build, Build is less than or equal to 255 and there is no revision. The reason the build number needs to be less than 255 is because
        ///                 255 is the largest build number for a target framework version that visual studio 2010 supports. The build number is supposed to 
        ///                 represent a service pack on the 4.0 framework.
        ///                 
        ///                 If the string is a valid target framework version we check to see we already have a dictionary entry and if not we 
        ///                 add one. 
        ///                 If the string is not a valid target framework then we will ignore the part of the version which makes it invalid
        ///                 (either the build or the revision, or both) and see where that version would fit in the dictionary as a key and
        ///                 then put the original version string into the list for that entry.
        ///                 
        ///         Since the dictionary is sorted in reverse order to generate the list to return we do the following:
        ///         Go through the list of dictionary entries 
        ///             For each entry sort the list in reverse alphabetical order and add the entries in their internal list to the listToreturn.
        ///
        ///         This way we have a reverse sorted list of all of the version keys.
        /// </summary>
        internal static List<ExtensionFoldersRegistryKey> GatherVersionStrings(string targetRuntimeVersion, IEnumerable<string> versions)
        {
            List<string> additionalToleratedKeys = new List<string>();
            Version targetVersion = VersionUtilities.ConvertToVersion(targetRuntimeVersion);
            List<ExtensionFoldersRegistryKey> versionStrings = new List<ExtensionFoldersRegistryKey>();

            // This dictionary will contain a set of target framework versions and a list of strings read from the registry which are supposed to be treated like the 
            // target framework version stored as the key. 
            // For example:
            //  If the target framework version is 4.0  but the registry string is v4.0.2116 then we want to treat v4.0.2116 as if it was v4.0 during the sort, 
            // but when reading out of the registry
            //  we need to know the original value so we can open the correct key.
            //
            //  The reason there needs to be a list for each target framework version is that there could be multiple keys in the registry which should be treated 
            // like v4.0 for sorting.
            //  for example lets say we had the following entries in the registry:
            //       4.0.2116  and 4.0.2116.87  both of these are supposed to be treated like v4.0 because they are not valid target framework versions but 
            // are valid version numbers and should be searched when we are targeting 4.0.
            SortedDictionary<Version, List<string>> targetFrameworkVersionToRegistryVersions = new SortedDictionary<Version, List<string>>(ReverseVersionGenericComparer.Comparer);

            // Loop over versions from registry.
            foreach (string version in versions)
            {
                if ((version.Length > 0) && (String.Equals(version.Substring(0, 1), "v", StringComparison.OrdinalIgnoreCase)))
                {
                    Version candidateVersion = VersionUtilities.ConvertToVersion(version);

                    if (candidateVersion == null)
                    {
                        // If it wasn't a true version number, we may still want to tolerate it because raw drops have
                        // the form 'v2.0.x86chk'
                        if (String.Compare(version, 0, targetRuntimeVersion, 0, targetRuntimeVersion.Length, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            additionalToleratedKeys.Add(version);
                        }
                    }
                    else
                    {
                        // To be added to our dictionary our candidate version from the registry must be a valid target framework version which is less than or equal 
                        // to the target version. Therefore if the candidate version is not a valid target framework version we will pretend it is and sort it in its correct form.

                        Version replacementVersion;
                        if (candidateVersion.Build > 255)
                        {
                            // Pretend the candidate version is really Maj.Minor ignore the build and revision
                            replacementVersion = new Version(candidateVersion.Major, candidateVersion.Minor);
                        }
                        else if (candidateVersion.Revision != -1)
                        {
                            // Pretend the version is Maj.Minor.Build ignore the revision
                            replacementVersion = new Version(candidateVersion.Major, candidateVersion.Minor, candidateVersion.Build);
                        }
                        else
                        {
                            // Was not replaced just use as is since it is a good version
                            replacementVersion = candidateVersion;
                        }

                        // If the target version is null then we need to do a partial version match 
                        bool addToListDueToPartialNameMatch = false;
                        if (targetVersion == null)
                        {
                            if (String.Compare(version, 0, targetRuntimeVersion, 0, targetRuntimeVersion.Length, StringComparison.OrdinalIgnoreCase) == 0)
                            {
                                addToListDueToPartialNameMatch = true;
                            }
                        }

                        // If we have a target framework version as a version object is the version we are going to add to our dictionary in the correct range.
                        bool replacementVersionWithinRange = (targetVersion != null && targetVersion >= replacementVersion);

                        // Add the version to our dictionary if we are within the correct range or we had no target framework version but partially matched on the version string.
                        if (replacementVersion != null && (replacementVersionWithinRange || addToListDueToPartialNameMatch))
                        {
                            AddCandidateVersion(targetFrameworkVersionToRegistryVersions, version, replacementVersion);
                        }
                    }
                }
            }

            // Go through the target framework versions in reverse version order
            foreach (KeyValuePair<Version, List<string>> entry in targetFrameworkVersionToRegistryVersions)
            {
                List<string> frameworkList = entry.Value;

                // Sort the list in reverse alphabetical order since these are the version strings from the registry
                frameworkList.Sort(ReverseStringGenericComparer.Comparer);

                foreach (string s in frameworkList)
                {
                    // The string in this case already contains the v
                    versionStrings.Add(new ExtensionFoldersRegistryKey(s, entry.Key));
                }
            }

            // The additional tolerated keys are added onto the end of the versions list in what ever order they came from the 
            // registry in.
            foreach (string key in additionalToleratedKeys)
            {
                versionStrings.Add(new ExtensionFoldersRegistryKey(key, targetVersion ?? new Version(0, 0)));
            }

            return versionStrings;
        }

        /// <summary>
        /// Given a candidate version we need to add it to the dictionary of targetFrameworkToRegistry versions. This involves determining if we need to add it to
        /// an existing entry or create a new one.
        /// </summary>
        private static void AddCandidateVersion(SortedDictionary<Version, List<string>> targetFrameworkVersionToRegistryVersions, string version, Version candidateVersion)
        {
            List<string> listOfFrameworks;
            if (targetFrameworkVersionToRegistryVersions.TryGetValue(candidateVersion, out listOfFrameworks))
            {
                listOfFrameworks.Add(version);
            }
            else
            {
                // The version is not in our dictionary yet, lets add it
                // We need a new list since one has not been added yet
                listOfFrameworks = new List<string>();
                // Make sure we add ourselves to the list
                listOfFrameworks.Add(version);

                targetFrameworkVersionToRegistryVersions.Add(candidateVersion, listOfFrameworks);
            }
        }

        /// <summary>
        /// Get Enumerator
        /// </summary>
        IEnumerator<AssemblyFoldersExInfo> IEnumerable<AssemblyFoldersExInfo>.GetEnumerator()
        {
            return _directoryNames.GetEnumerator();
        }

        /// <summary>
        /// Get enumerator
        /// </summary>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable<AssemblyFoldersExInfo>)this).GetEnumerator();
        }

        internal IEnumerable<string> UniqueDirectoryPaths
        {
            get => _uniqueDirectoryPaths;
        }
    }
}
#endif


<|start_filename|>src/Build/ObjectModelRemoting/DefinitionObjectsLinks/ProjectPropertyLink.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;

namespace Microsoft.Build.ObjectModelRemoting
{
    /// <summary>
    /// External projects support.
    /// Allow for creating a local representation to external object of type <see cref="ProjectProperty"/>
    /// </summary>
    public abstract class ProjectPropertyLink
    {
        /// <summary>
        /// Access to remote <see cref="ProjectProperty.Project"/>.
        /// </summary>
        public abstract Project Project { get; }

        /// <summary>
        /// Access to remote <see cref="ProjectProperty.Xml"/>.
        /// </summary>
        public abstract ProjectPropertyElement Xml { get; }

        /// <summary>
        /// Access to remote <see cref="ProjectProperty.Name"/>.
        /// (note can not Use Xml.Name since for global properties Xml is null;
        /// </summary>
        public abstract string Name { get; }

        /// <summary>
        /// Allow implement the <see cref="ProjectProperty.EvaluatedValue"/> for remoted objects.
        /// </summary>
        public abstract string EvaluatedIncludeEscaped { get; }

        /// <summary>
        /// Access to remote <see cref="ProjectProperty.UnevaluatedValue"/>.
        /// </summary>
        public abstract string UnevaluatedValue { get; set; }

        /// <summary>
        /// Access to remote <see cref="ProjectProperty.IsEnvironmentProperty"/>.
        /// </summary>
        public abstract bool IsEnvironmentProperty { get; }

        /// <summary>
        /// Access to remote <see cref="ProjectProperty.IsGlobalProperty"/>.
        /// </summary>
        public abstract bool IsGlobalProperty { get; }

        /// <summary>
        /// Access to remote <see cref="ProjectProperty.IsReservedProperty"/>.
        /// </summary>
        public abstract bool IsReservedProperty { get; }

        /// <summary>
        /// Access to remote <see cref="ProjectProperty.Predecessor"/>.
        /// </summary>
        public abstract ProjectProperty Predecessor { get; }

        /// <summary>
        /// Access to remote <see cref="ProjectProperty.IsImported"/>.
        /// </summary>
        public abstract bool IsImported { get; }

        /// <summary>
        /// Helper utility for External projects provider implementation to get access of the EvaluatedValueEscaped
        /// </summary>
        public static string GetEvaluatedValueEscaped(ProjectProperty property)
        {
            return property.EvaluatedValueEscapedInternal;
        }
    }
}


<|start_filename|>src/Build.UnitTests/Evaluation/SdkResultEvaluation_Tests.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Build.Construction;
using Microsoft.Build.Definition;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Execution;
using Microsoft.Build.Framework;
using Microsoft.Build.Unittest;
using Shouldly;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Xunit;
using Xunit.Abstractions;

namespace Microsoft.Build.UnitTests.Evaluation
{
    public class SdkResultEvaluation_Tests : IDisposable
    {
        private TestEnvironment _env;
        private readonly string _testFolder;
        private MockLogger _logger;
        private ProjectCollection _projectCollection;
        private ITestOutputHelper _log;
        private bool _originalWarnOnUnitializedProperty;

        public SdkResultEvaluation_Tests(ITestOutputHelper log)
        {
            _log = log;
    
            _env = TestEnvironment.Create();

            _originalWarnOnUnitializedProperty = BuildParameters.WarnOnUninitializedProperty;
            BuildParameters.WarnOnUninitializedProperty = false;

            _testFolder = _env.CreateFolder().Path;
            _logger = new MockLogger();
            _projectCollection = _env.CreateProjectCollection().Collection;
            _projectCollection.RegisterLogger(_logger);
        }

        private Project CreateProject(string projectPath, ProjectOptions projectOptions)
        {
            ProjectRootElement projectRootElement = ProjectRootElement.Open(projectPath, _projectCollection);

            projectOptions.ProjectCollection = _projectCollection;

            var project = Project.FromProjectRootElement(projectRootElement, projectOptions);

            return project;
        }

        private void CreateMockSdkResultPropertiesAndItems(out Dictionary<string, string> propertiesToAdd, out Dictionary<string, SdkResultItem> itemsToAdd)
        {
            propertiesToAdd = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
                {
                    {"PropertyFromSdkResolver", "ValueFromSdkResolver" }
                };

            itemsToAdd = new Dictionary<string, SdkResultItem>(StringComparer.OrdinalIgnoreCase)
                {
                    { "ItemNameFromSdkResolver", new SdkResultItem( "ItemValueFromSdkResolver",
                        new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
                        {
                            { "MetadataName", "MetadataValue" }
                        })
                    }
                };
        }

        private void ValidateExpectedPropertiesAndItems(bool includePropertiesAndItems, Project project, int expectedItemCount = 1)
        {
            if (includePropertiesAndItems)
            {
                project.GetPropertyValue("PropertyFromSdkResolver").ShouldBe("ValueFromSdkResolver");

                var itemsFromResolver = project.GetItems("ItemNameFromSdkResolver");
                itemsFromResolver.Count.ShouldBe(expectedItemCount);
                foreach (var item in itemsFromResolver)
                {
                    ValidateItemFromResolver(item);
                }
            }
            else
            {
                project.GetProperty("PropertyFromSdkResolver").ShouldBeNull();
                project.GetItems("ItemNameFromSdkResolver").ShouldBeEmpty();
            }
        }

        private void ValidateItemFromResolver(ProjectItem item)
        {
            item.EvaluatedInclude.ShouldBe("ItemValueFromSdkResolver");
            item.Metadata.Select(m => (m.Name, m.EvaluatedValue))
                .ShouldBeSameIgnoringOrder(new[] { (Name: "MetadataName", EvaluatedValue: "MetadataValue") });
        }

        [Theory]
        [InlineData(true)]
        [InlineData(false)]
        public void SdkResolverCanReturnNoPaths(bool includePropertiesAndItems)
        {
            Dictionary<string, string> propertiesToAdd = null;
            Dictionary<string, SdkResultItem> itemsToAdd = null;

            if (includePropertiesAndItems)
            {
                CreateMockSdkResultPropertiesAndItems(out propertiesToAdd, out itemsToAdd);
            }

            var projectOptions = SdkUtilities.CreateProjectOptionsWithResolver(new SdkUtilities.ConfigurableMockSdkResolver(
                new Build.BackEnd.SdkResolution.SdkResult(
                        new SdkReference("TestPropsAndItemsFromResolverSdk", null, null),
                        Enumerable.Empty<string>(),
                        version: null,
                        propertiesToAdd,
                        itemsToAdd,
                        warnings: null
                    ))
                );

            string projectContent = @"
                    <Project>
                        <Import Project=""Sdk.props"" Sdk=""TestPropsAndItemsFromResolverSdk""/>
                    </Project>";

            string projectPath = Path.Combine(_testFolder, "project.proj");
            File.WriteAllText(projectPath, projectContent);

            var project = CreateProject(projectPath, projectOptions);

            ValidateExpectedPropertiesAndItems(includePropertiesAndItems, project);

            _logger.ErrorCount.ShouldBe(0);
            _logger.WarningCount.ShouldBe(0);
        }

        [Theory]
        [InlineData(true, true)]
        [InlineData(true, false)]
        [InlineData(false, true)]
        [InlineData(false, false)]
        public void SdkResolverCanReturnSinglePath(bool includePropertiesAndItems, bool useSinglePathResult)
        {
            Dictionary<string, string> propertiesToAdd = null;
            Dictionary<string, SdkResultItem> itemsToAdd = null;

            if (includePropertiesAndItems)
            {
                CreateMockSdkResultPropertiesAndItems(out propertiesToAdd, out itemsToAdd);
            }

            var sdkResult = useSinglePathResult ?
                new Build.BackEnd.SdkResolution.SdkResult(
                    new SdkReference("TestPropsAndItemsFromResolverSdk", null, null),
                    Path.Combine(_testFolder, "Sdk"),
                    version: null,
                    warnings: null,
                    propertiesToAdd,
                    itemsToAdd) :
                new Build.BackEnd.SdkResolution.SdkResult(
                    new SdkReference("TestPropsAndItemsFromResolverSdk", null, null),
                    new[] { Path.Combine(_testFolder, "Sdk") },
                    version: null,
                    propertiesToAdd,
                    itemsToAdd,
                    warnings: null);

            var projectOptions = SdkUtilities.CreateProjectOptionsWithResolver(new SdkUtilities.ConfigurableMockSdkResolver(sdkResult));

            string projectContent = @"
                    <Project>
                        <PropertyGroup>
                            <ValueFromResolverBefore>Value=$(PropertyFromSdkResolver)</ValueFromResolverBefore>
                        </PropertyGroup>
                        <ItemGroup>
                            <ItemsFromSdkResolverBefore Include=""@(ItemNameFromSdkResolver)"" />
                        </ItemGroup>
                        <Import Project=""Sdk.props"" Sdk=""TestPropsAndItemsFromResolverSdk""/>
                        <PropertyGroup>
                            <ValueFromResolverAfter>Value=$(PropertyFromSdkResolver)</ValueFromResolverAfter>
                        </PropertyGroup>
                        <ItemGroup>
                            <ItemsFromSdkResolverAfter Include=""@(ItemNameFromSdkResolver)"" />
                        </ItemGroup>
                    </Project>";

            string projectPath = Path.Combine(_testFolder, "project.proj");
            File.WriteAllText(projectPath, projectContent);

            string sdkImportContents = @"
                    <Project>
                        <PropertyGroup>
                            <PropertyFromImportedSdk>ValueFromImportedSdk</PropertyFromImportedSdk>
                        </PropertyGroup>
                    </Project>";

            string sdkPropsPath = Path.Combine(_testFolder, "Sdk", "Sdk.props");
            Directory.CreateDirectory(Path.Combine(_testFolder, "Sdk"));
            File.WriteAllText(sdkPropsPath, sdkImportContents);

            var project = CreateProject(projectPath, projectOptions);

            ValidateExpectedPropertiesAndItems(includePropertiesAndItems, project);

            project.GetPropertyValue("ValueFromResolverBefore").ShouldBe("Value=");
            if (includePropertiesAndItems)
            {
                project.GetPropertyValue("ValueFromResolverAfter").ShouldBe("Value=ValueFromSdkResolver");
            }
            else
            {
                project.GetPropertyValue("ValueFromResolverAfter").ShouldBe("Value=");
            }

            project.GetPropertyValue("PropertyFromImportedSdk").ShouldBe("ValueFromImportedSdk");

            project.GetItems("ItemsFromSdkResolverBefore").ShouldBeEmpty();
            if (includePropertiesAndItems)
            {
                var items = project.GetItems("ItemsFromSdkResolverAfter");
                items.Count.ShouldBe(1);
                ValidateItemFromResolver(items.Single());
            }
            else
            {
                project.GetItems("ItemsFromSdkResolverAfter").ShouldBeEmpty();
            }

            _logger.ErrorCount.ShouldBe(0);
            _logger.WarningCount.ShouldBe(0);
        }

        [Theory]
        [InlineData(true)]
        [InlineData(false)]
        public void SdkResolverCanReturnMultiplePaths(bool includePropertiesAndItems)
        {
            Dictionary<string, string> propertiesToAdd = null;
            Dictionary<string, SdkResultItem> itemsToAdd = null;

            if (includePropertiesAndItems)
            {
                CreateMockSdkResultPropertiesAndItems(out propertiesToAdd, out itemsToAdd);
            }

            var projectOptions = SdkUtilities.CreateProjectOptionsWithResolver(new SdkUtilities.ConfigurableMockSdkResolver(
                new Build.BackEnd.SdkResolution.SdkResult(
                        new SdkReference("TestPropsAndItemsFromResolverSdk", null, null),
                        new[] {
                            Path.Combine(_testFolder, "Sdk1"),
                            Path.Combine(_testFolder, "Sdk2")
                        },
                        version: null,
                        propertiesToAdd,
                        itemsToAdd,
                        warnings: null
                    ))
                );

            string projectContent = @"
                    <Project>
                        <PropertyGroup>
                            <ValueFromResolverBefore>Value=$(PropertyFromSdkResolver)</ValueFromResolverBefore>
                        </PropertyGroup>
                        <ItemGroup>
                            <ItemsFromSdkResolverBefore Include=""@(ItemNameFromSdkResolver)"" />
                        </ItemGroup>
                        <Import Project=""Sdk.props"" Sdk=""TestPropsAndItemsFromResolverSdk""/>
                        <PropertyGroup>
                            <ValueFromResolverAfter>Value=$(PropertyFromSdkResolver)</ValueFromResolverAfter>
                        </PropertyGroup>
                        <ItemGroup>
                            <ItemsFromSdkResolverAfter Include=""@(ItemNameFromSdkResolver)"" />
                        </ItemGroup>
                    </Project>";

            string projectPath = Path.Combine(_testFolder, "project.proj");
            File.WriteAllText(projectPath, projectContent);

            string sdk1ImportContents = @"
                    <Project>
                        <PropertyGroup>
                            <PropertyFromImportedSdk1>ValueFromImportedSdk1</PropertyFromImportedSdk1>
                        </PropertyGroup>
                    </Project>";

            string sdk1PropsPath = Path.Combine(_testFolder, "Sdk1", "Sdk.props");
            Directory.CreateDirectory(Path.Combine(_testFolder, "Sdk1"));
            File.WriteAllText(sdk1PropsPath, sdk1ImportContents);

            string sdk2ImportContents = @"
                    <Project>
                        <PropertyGroup>
                            <PropertyFromImportedSdk2>ValueFromImportedSdk2</PropertyFromImportedSdk2>
                        </PropertyGroup>
                    </Project>";

            string sdk2PropsPath = Path.Combine(_testFolder, "Sdk2", "Sdk.props");
            Directory.CreateDirectory(Path.Combine(_testFolder, "Sdk2"));
            File.WriteAllText(sdk2PropsPath, sdk2ImportContents);

            var project = CreateProject(projectPath, projectOptions);

            ValidateExpectedPropertiesAndItems(includePropertiesAndItems, project);

            project.GetPropertyValue("ValueFromResolverBefore").ShouldBe("Value=");
            if (includePropertiesAndItems)
            {
                project.GetPropertyValue("ValueFromResolverAfter").ShouldBe("Value=ValueFromSdkResolver");
            }
            else
            {
                project.GetPropertyValue("ValueFromResolverAfter").ShouldBe("Value=");
            }

            project.GetPropertyValue("PropertyFromImportedSdk1").ShouldBe("ValueFromImportedSdk1");
            project.GetPropertyValue("PropertyFromImportedSdk2").ShouldBe("ValueFromImportedSdk2");

            project.GetItems("ItemsFromSdkResolverBefore").ShouldBeEmpty();
            if (includePropertiesAndItems)
            {
                var items = project.GetItems("ItemsFromSdkResolverAfter");
                items.Count.ShouldBe(1);
                ValidateItemFromResolver(items.Single());
            }
            else
            {
                project.GetItems("ItemsFromSdkResolverAfter").ShouldBeEmpty();
            }

            if (_logger.ErrorCount > 0 || _logger.WarningCount > 0)
            {
                _log.WriteLine(_logger.FullLog);
            }

            _logger.ErrorCount.ShouldBe(0);
            _logger.WarningCount.ShouldBe(0);
        }

        //  When two different SdkResults (ie from the Sdk.props and Sdk.targets imports) return the same combination of items / properties:
        //  - Test that there aren't warnings for duplicate imports
        //  - Test that items from resolver are duplicated in final evaluation result
        [Fact]
        public void SdkResolverCanReturnTheSamePropertiesAndItemsMultipleTimes()
        {
            Dictionary<string, string> propertiesToAdd;
            Dictionary<string, SdkResultItem> itemsToAdd;
            CreateMockSdkResultPropertiesAndItems(out propertiesToAdd, out itemsToAdd);

            var projectOptions = SdkUtilities.CreateProjectOptionsWithResolver(new SdkUtilities.ConfigurableMockSdkResolver(
                new Build.BackEnd.SdkResolution.SdkResult(
                        new SdkReference("TestPropsAndItemsFromResolverSdk", null, null),
                        new[] { Path.Combine(_testFolder, "Sdk") },
                        version: null,
                        propertiesToAdd,
                        itemsToAdd,
                        warnings: null
                    ))
                );

            string projectContent = @"
                    <Project Sdk=""TestPropsAndItemsFromResolverSdk"">
                        <PropertyGroup>
                            <ValueFromResolverInProjectBody>Value=$(PropertyFromSdkResolver)</ValueFromResolverInProjectBody>
                        </PropertyGroup>
                        <ItemGroup>
                            <ItemsFromSdkResolverInProjectBody Include=""@(ItemNameFromSdkResolver)"" />
                        </ItemGroup>
                    </Project>";

            string projectPath = Path.Combine(_testFolder, "project.proj");
            File.WriteAllText(projectPath, projectContent);

            string sdkPropsContents = @"
                    <Project>
                        <PropertyGroup>
                            <PropertyFromSdkProps>PropertyFromSdkPropsValue</PropertyFromSdkProps>
                        </PropertyGroup>
                    </Project>";

            string sdkPropsPath = Path.Combine(_testFolder, "Sdk", "Sdk.props");
            Directory.CreateDirectory(Path.Combine(_testFolder, "Sdk"));
            File.WriteAllText(sdkPropsPath, sdkPropsContents);

            string sdkTargetsContents = @"
                    <Project>
                        <PropertyGroup>
                            <PropertyFromSdkTargets>PropertyFromSdkTargetsValue</PropertyFromSdkTargets>
                        </PropertyGroup>
                    </Project>";

            string sdkTargetsPath = Path.Combine(_testFolder, "Sdk", "Sdk.targets");
            File.WriteAllText(sdkTargetsPath, sdkTargetsContents);

            var project = CreateProject(projectPath, projectOptions);

            ValidateExpectedPropertiesAndItems(true, project, expectedItemCount: 2);

            project.GetPropertyValue("ValueFromResolverInProjectBody").ShouldBe("Value=ValueFromSdkResolver");
            project.GetPropertyValue("PropertyFromSdkProps").ShouldBe("PropertyFromSdkPropsValue");
            project.GetPropertyValue("PropertyFromSdkTargets").ShouldBe("PropertyFromSdkTargetsValue");

            var itemsFromBody = project.GetItems("ItemsFromSdkResolverInProjectBody");
            itemsFromBody.Count.ShouldBe(1);
            ValidateItemFromResolver(itemsFromBody.Single());

            _logger.ErrorCount.ShouldBe(0);
            _logger.WarningCount.ShouldBe(0);
        }

        [Fact]
        public void SdkResolverCanReturnSpecialCharacters()
        {
            //  %3B - semicolon
            //  %24 - $
            //  %0A - LF

            string specialString = "%3B;%24$%0A\\\"'";

            Dictionary<string, string> propertiesToAdd = new Dictionary<string, string>()
            {
                { "PropertyName", "PropertyValue" + specialString }
            };

            Dictionary<string, SdkResultItem> itemsToAdd = new Dictionary<string, SdkResultItem>()
            {
                {
                    "ItemName",
                    new SdkResultItem(itemSpec: "ItemValue" + specialString, new Dictionary<string, string>()
                        { { "MetadataName", "MetadataValue" + specialString } })
                }
            };

            var projectOptions = SdkUtilities.CreateProjectOptionsWithResolver(new SdkUtilities.ConfigurableMockSdkResolver(
                new Build.BackEnd.SdkResolution.SdkResult(
                        new SdkReference("TestSpecialCharactersFromSdkResolver", null, null),
                        Enumerable.Empty<string>(),
                        version: null,
                        propertiesToAdd,
                        itemsToAdd,
                        warnings: null
                    ))
                );

            string projectContent = @"
                    <Project>
                        <Import Project=""Sdk.props"" Sdk=""TestSpecialCharactersFromSdkResolver""/>
                    </Project>";

            string projectPath = Path.Combine(_testFolder, "project.proj");
            File.WriteAllText(projectPath, projectContent);

            var project = CreateProject(projectPath, projectOptions);

            project.GetPropertyValue("PropertyName").ShouldBe("PropertyValue" + specialString);

            var itemsFromResolver = project.GetItems("ItemName");
            var item = itemsFromResolver.ShouldHaveSingleItem();
            item.EvaluatedInclude.ShouldBe("ItemValue" + specialString);
            item.Metadata.Select(m => (m.Name, m.EvaluatedValue))
                .ShouldBeSameIgnoringOrder(new[] { (Name: "MetadataName", EvaluatedValue: "MetadataValue" + specialString) });

            _logger.ErrorCount.ShouldBe(0);
            _logger.WarningCount.ShouldBe(0);
        }

        public void Dispose()
        {
            _env.Dispose();
            BuildParameters.WarnOnUninitializedProperty = _originalWarnOnUnitializedProperty;
        }
    }
}


<|start_filename|>src/Tasks.UnitTests/WriteLinesToFile_Tests.cs<|end_filename|>
﻿using System;
using System.IO;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using Microsoft.Build.UnitTests;
using Microsoft.Build.Utilities;
using Shouldly;
using Xunit;
using Xunit.Abstractions;

namespace Microsoft.Build.Tasks.UnitTests
{
    public sealed class WriteLinesToFile_Tests
    {
        private readonly ITestOutputHelper _output;

        public WriteLinesToFile_Tests(ITestOutputHelper output)
        {
            _output = output;
        }

        /// <summary>
        /// Invalid encoding
        /// </summary>
        [Fact]
        public void InvalidEncoding()
        {
            var a = new WriteLinesToFile
            {
                BuildEngine = new MockEngine(_output),
                Encoding = "||invalid||",
                File = new TaskItem("c:\\" + Guid.NewGuid().ToString()),
                Lines = new TaskItem[] { new TaskItem("x") }
            };

            Assert.False(a.Execute());
            ((MockEngine)a.BuildEngine).AssertLogContains("MSB3098");
            Assert.False(File.Exists(a.File.ItemSpec));
        }

        /// <summary>
        /// Reading blank lines from a file should be ignored.
        /// </summary>
        [Fact]
        public void Encoding()
        {
            var file = FileUtilities.GetTemporaryFile();
            try
            {
                // Write default encoding: UTF8
                var a = new WriteLinesToFile
                {
                    BuildEngine = new MockEngine(_output),
                    File = new TaskItem(file),
                    Lines = new ITaskItem[] { new TaskItem("\uBDEA") }
                };
                Assert.True(a.Execute());

                var r = new ReadLinesFromFile
                {
                    File = new TaskItem(file)
                };
                Assert.True(r.Execute());

                Assert.Equal("\uBDEA", r.Lines[0].ItemSpec);

                File.Delete(file);

                // Write ANSI .. that won't work! 
                a = new WriteLinesToFile
                {
                    BuildEngine = new MockEngine(_output),
                    File = new TaskItem(file),
                    Lines = new ITaskItem[] { new TaskItem("\uBDEA") },
                    Encoding = "ASCII"
                };
                Assert.True(a.Execute());

                // Read the line from the file.
                r = new ReadLinesFromFile
                {
                    File = new TaskItem(file)
                };
                Assert.True(r.Execute());

                Assert.NotEqual("\uBDEA", r.Lines[0].ItemSpec);
            }
            finally
            {
                File.Delete(file);
            }
        }

        [Fact]
        public void WriteLinesWriteOnlyWhenDifferentTest()
        {
            var file = FileUtilities.GetTemporaryFile();
            try
            {
                // Write an initial file.
                var a = new WriteLinesToFile
                {
                    Overwrite = true,
                    BuildEngine = new MockEngine(_output),
                    File = new TaskItem(file),
                    WriteOnlyWhenDifferent = true,
                    Lines = new ITaskItem[] { new TaskItem("File contents1") }
                };

                a.Execute().ShouldBeTrue();

                // Verify contents
                var r = new ReadLinesFromFile { File = new TaskItem(file) };
                r.Execute().ShouldBeTrue();
                r.Lines[0].ItemSpec.ShouldBe("File contents1");

                var writeTime = DateTime.Now.AddHours(-1);

                File.SetLastWriteTime(file, writeTime);

                // Write the same contents to the file, timestamps should match.
                var a2 = new WriteLinesToFile
                {
                    Overwrite = true,
                    BuildEngine = new MockEngine(_output),
                    File = new TaskItem(file),
                    WriteOnlyWhenDifferent = true,
                    Lines = new ITaskItem[] { new TaskItem("File contents1") }
                };
                a2.Execute().ShouldBeTrue();
                File.GetLastWriteTime(file).ShouldBe(writeTime, tolerance: TimeSpan.FromSeconds(1));

                // Write different contents to the file, last write time should differ.
                var a3 = new WriteLinesToFile
                {
                    Overwrite = true,
                    BuildEngine = new MockEngine(_output),
                    File = new TaskItem(file),
                    WriteOnlyWhenDifferent = true,
                    Lines = new ITaskItem[] { new TaskItem("File contents2") }
                };

                a3.Execute().ShouldBeTrue();
                File.GetLastWriteTime(file).ShouldBeGreaterThan(writeTime.AddSeconds(1));
            }
            finally
            {
                File.Delete(file);
            }
        }

        /// <summary>
        /// Should create directory structure when target <see cref="WriteLinesToFile.File"/> does not exist.
        /// </summary>
        [Fact]
        public void WriteLinesToFileDoesCreateDirectory()
        {
            using (var testEnv = TestEnvironment.Create())
            {
                var directory = testEnv.CreateFolder(folderPath: null, createFolder: false);
                var file = Path.Combine(directory.Path, $"{Guid.NewGuid().ToString("N")}.tmp");

                var WriteLinesToFile = new WriteLinesToFile
                {
                    BuildEngine = new MockEngine(_output),
                    File = new TaskItem(file),
                    Lines = new ITaskItem[] { new TaskItem("WriteLinesToFileDoesCreateDirectory Test") }
                };

                // Verify that the diretory doesn't exist. Otherwise the test would pass - even it should not.
                Directory.Exists(directory.Path).ShouldBeFalse();

                WriteLinesToFile.Execute().ShouldBeTrue();

                Directory.Exists(directory.Path).ShouldBeTrue();
            }
        }

        [Theory]
        [InlineData(true)]
        [InlineData(false)]
        private void WritingNothingErasesExistingFile(bool useNullLines)
        {
            ITaskItem[] lines = useNullLines ? null : Array.Empty<ITaskItem>();

            using (var testEnv = TestEnvironment.Create())
            {
                var file = testEnv.CreateFile("FileToBeEmptied.txt", "Contents that should be erased");

                File.Exists(file.Path).ShouldBeTrue();
                File.ReadAllText(file.Path).ShouldNotBeEmpty();

                new WriteLinesToFile
                {
                    Overwrite = true,
                    BuildEngine = new MockEngine(_output),
                    File = new TaskItem(file.Path),
                    Lines = lines
                }.Execute().ShouldBeTrue();

                File.Exists(file.Path).ShouldBeTrue();
                File.ReadAllText(file.Path).ShouldBeEmpty();
            }
        }

        [Theory]
        [InlineData(true)]
        [InlineData(false)]
        private void WritingNothingCreatesNewFile(bool useNullLines)
        {
            ITaskItem[] lines = useNullLines ? null : Array.Empty<ITaskItem>();

            using (var testEnv = TestEnvironment.Create())
            {
                var file = testEnv.GetTempFile();

                File.Exists(file.Path).ShouldBeFalse();

                new WriteLinesToFile
                {
                    Overwrite = true,
                    BuildEngine = new MockEngine(_output),
                    File = new TaskItem(file.Path),
                    Lines = lines
                }.Execute().ShouldBeTrue();

                File.Exists(file.Path).ShouldBeTrue();
                File.ReadAllText(file.Path).ShouldBeEmpty();
            }
        }
    }
}


<|start_filename|>src/Build/BackEnd/Shared/TargetResult.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Diagnostics;
using System.IO;
using System.Globalization;
using Microsoft.Build.BackEnd;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using TaskItem = Microsoft.Build.Execution.ProjectItemInstance.TaskItem;
using Microsoft.Build.Shared.FileSystem;
using Microsoft.Build.Collections;

namespace Microsoft.Build.Execution
{
    /// <summary>
    /// Contains the result items for a single target as well as the overall result code.
    /// </summary>
    public class TargetResult : ITargetResult, ITranslatable
    {
        /// <summary>
        /// The result for this target.
        /// </summary>
        private WorkUnitResult _result;

        /// <summary>
        /// Flag indicating whether to consider this target failure as having caused a build failure.
        /// </summary>
        private bool _targetFailureDoesntCauseBuildFailure;

        /// <summary>
        /// Flag indicating whether at least one target which has run after us (transitively via AfterTargets) failed.
        /// </summary>
        private bool _afterTargetsHaveFailed;

        /// <summary>
        /// The store of items in this result.
        /// </summary>
        private TaskItem[] _items;

        /// <summary>
        /// The context under which these results have been cached.
        /// </summary>
        private CacheInfo _cacheInfo;

        /// <summary>
        /// Initializes the results with specified items and result.
        /// </summary>
        /// <param name="items">The items produced by the target.</param>
        /// <param name="result">The overall result for the target.</param>
        internal TargetResult(TaskItem[] items, WorkUnitResult result)
        {
            ErrorUtilities.VerifyThrowArgumentNull(items, nameof(items));
            ErrorUtilities.VerifyThrowArgumentNull(result, nameof(result));
            _items = items;
            _result = result;
        }

        /// <summary>
        /// Private constructor for deserialization
        /// </summary>
        private TargetResult(ITranslator translator)
        {
            ((ITranslatable)this).Translate(translator);
        }

        /// <summary>
        /// Returns the exception which aborted this target, if any.
        /// </summary>
        /// <value>The exception which aborted this target, if any.</value>
        public Exception Exception
        {
            [DebuggerStepThrough]
            get => _result.Exception;
        }

        /// <summary>
        /// Returns the items produced by the target.
        /// These are ITaskItem's, so they have no item-type.
        /// </summary>
        /// <value>The items produced by the target.</value>
        public ITaskItem[] Items
        {
            [DebuggerStepThrough]
            get
            {
                lock (_result)
                {
                    RetrieveItemsFromCache();

                    return _items;
                }
            }
        }

        /// <summary>
        /// Returns the result code for the target.
        /// </summary>
        /// <value>The result code for the target.</value>
        public TargetResultCode ResultCode
        {
            [DebuggerStepThrough]
            get
            {
                switch (_result.ResultCode)
                {
                    case WorkUnitResultCode.Canceled:
                    case WorkUnitResultCode.Failed:
                        return TargetResultCode.Failure;

                    case WorkUnitResultCode.Skipped:
                        return TargetResultCode.Skipped;

                    case WorkUnitResultCode.Success:
                        return TargetResultCode.Success;

                    default:
                        return TargetResultCode.Skipped;
                }
            }
        }

        /// <summary>
        /// Returns the internal result for the target.
        /// </summary>
        internal WorkUnitResult WorkUnitResult
        {
            [DebuggerStepThrough]
            get => _result;
        }

        /// <summary>
        /// Sets or gets a flag indicating whether or not a failure results should cause the build to fail.
        /// </summary>
        internal bool TargetFailureDoesntCauseBuildFailure
        {
            [DebuggerStepThrough]
            get => _targetFailureDoesntCauseBuildFailure;

            [DebuggerStepThrough]
            set => _targetFailureDoesntCauseBuildFailure = value;
        }

        /// <summary>
        /// Sets or gets a flag indicating whether at least one target which has run after us (transitively via AfterTargets) failed.
        /// </summary>
        internal bool AfterTargetsHaveFailed
        {
            [DebuggerStepThrough]
            get => _afterTargetsHaveFailed;

            [DebuggerStepThrough]
            set => _afterTargetsHaveFailed = value;
        }

        #region INodePacketTranslatable Members

        /// <summary>
        /// Reads or writes the packet to the serializer.
        /// </summary>
        void ITranslatable.Translate(ITranslator translator)
        {
            if (translator.Mode == TranslationDirection.WriteToStream)
            {
                lock (_result)
                {
                    // Should we have cached these items but now want to send them to another node, we need to 
                    // ensure they are loaded before doing so.
                    RetrieveItemsFromCache();
                    InternalTranslate(translator);
                }
            }
            else
            {
                InternalTranslate(translator);
            }
        }

        /// <summary>
        /// Factory for serialization.
        /// </summary>
        internal static TargetResult FactoryForDeserialization(ITranslator translator)
        {
            return new TargetResult(translator);
        }

        #endregion

        /// <summary>
        /// Gets the name of the cache file for this configuration.
        /// </summary>
        internal static string GetCacheFile(int configId, string targetToCache)
        {
            string filename = Path.Combine(FileUtilities.GetCacheDirectory(), String.Format(CultureInfo.InvariantCulture, Path.Combine("Results{0}", "{1}.cache"), configId, targetToCache));
            return filename;
        }

        /// <summary>
        /// Gets the name of the cache file for this configuration.
        /// </summary>
        internal static string GetCacheDirectory(int configId, string targetToCache)
        {
            string filename = GetCacheFile(configId, targetToCache);
            string directoryName = Path.GetDirectoryName(filename);
            return directoryName;
        }

        /// <summary>
        /// Cache the items.
        /// </summary>
        internal void CacheItems(int configId, string targetName)
        {
            lock (_result)
            {
                if (_items == null)
                {
                    // Already cached.
                    return;
                }

                if (_items.Length == 0)
                {
                    // Nothing to cache.
                    return;
                }

                ITranslator translator = GetResultsCacheTranslator(configId, targetName, TranslationDirection.WriteToStream);

                // If the translator is null, it means these results were cached once before.  Since target results are immutable once they
                // have been created, there is no point in writing them again.
                if (translator != null)
                {
                    try
                    {
                        TranslateItems(translator);
                        _items = null;
                        _cacheInfo = new CacheInfo(configId, targetName);
                    }
                    finally
                    {
                        translator.Writer.BaseStream.Dispose();
                    }
                }
            }
        }

        /// <summary>
        /// Performs the actual translation
        /// </summary>
        private void InternalTranslate(ITranslator translator)
        {
            translator.Translate(ref _result, WorkUnitResult.FactoryForDeserialization);
            translator.Translate(ref _targetFailureDoesntCauseBuildFailure);
            translator.Translate(ref _afterTargetsHaveFailed);
            TranslateItems(translator);
        }

        /// <summary>
        /// Retrieve the items from the cache.
        /// </summary>
        private void RetrieveItemsFromCache()
        {
            lock (_result)
            {
                if (_items == null)
                {
                    ITranslator translator = GetResultsCacheTranslator(_cacheInfo.ConfigId, _cacheInfo.TargetName, TranslationDirection.ReadFromStream);

                    try
                    {
                        TranslateItems(translator);
                        _cacheInfo = new CacheInfo();
                    }
                    finally
                    {
                        translator.Reader.BaseStream.Dispose();
                    }
                }
            }
        }

        private void TranslateItems(ITranslator translator)
        {
            var itemsCount = _items?.Length ?? 0;
            translator.Translate(ref itemsCount);

            if (translator.Mode == TranslationDirection.WriteToStream)
            {
                // We will just calculate a very rough starting buffer size for the memory stream based on the number of items and a
                // rough guess for an average number of bytes needed to store them.  This doesn't have to be accurate, just
                // big enough to avoid unnecessary buffer reallocations in most cases.
                var defaultBufferCapacity = _items.Length * 128;
                
                using var itemsStream = new MemoryStream(defaultBufferCapacity);
                var itemTranslator = BinaryTranslator.GetWriteTranslator(itemsStream);

                // When creating the interner, we use the number of items as the initial size of the collections since the
                // number of strings will be of the order of the number of items in the collection.  This assumes basically
                // one unique string per item (frequently a path related to the item) with most of the rest of the metadata
                // being the same (and thus interning.)  This is a hueristic meant to get us in the ballpark to avoid 
                // too many reallocations when growing the collections.
                var interner = new LookasideStringInterner(StringComparer.Ordinal, _items.Length);
                foreach (TaskItem t in _items)
                {
                    t.TranslateWithInterning(itemTranslator, interner);
                }

                interner.Translate(translator);
                var buffer = itemsStream.GetBuffer();
                var bufferSize = (int)itemsStream.Length;
                translator.Translate(ref buffer, ref bufferSize);
            }
            else
            {
                var interner = new LookasideStringInterner(translator);

                byte[] buffer = null;
                translator.Translate(ref buffer);
                ErrorUtilities.VerifyThrow(buffer != null, "Unexpected null items buffer during translation.");

                using MemoryStream itemsStream = new MemoryStream(buffer, 0, buffer.Length, writable: false, publiclyVisible: true);
                var itemTranslator = BinaryTranslator.GetReadTranslator(itemsStream, null);
                _items = new TaskItem[itemsCount];
                for (int i = 0; i < _items.Length; i++)
                {
                    _items[i] = TaskItem.FactoryForDeserialization(itemTranslator, interner);
                }
            }
        }

        /// <summary>
        /// Gets the translator for this configuration.
        /// </summary>
        private static ITranslator GetResultsCacheTranslator(int configId, string targetToCache, TranslationDirection direction)
        {
            string cacheFile = GetCacheFile(configId, targetToCache);
            if (direction == TranslationDirection.WriteToStream)
            {
                Directory.CreateDirectory(Path.GetDirectoryName(cacheFile));
                if (FileSystems.Default.FileExists(cacheFile))
                {
                    // If the file already exists, then we have cached this once before.  No need to cache it again since it cannot have changed.
                    return null;
                }

                return BinaryTranslator.GetWriteTranslator(File.Create(cacheFile));
            }
            else
            {
                return BinaryTranslator.GetReadTranslator(File.OpenRead(cacheFile), null);
            }
        }

        /// <summary>
        /// Information about where the cache for the items in this result are stored.
        /// </summary>
        private struct CacheInfo
        {
            /// <summary>
            /// Constructor.
            /// </summary>
            public CacheInfo(int configId, string targetName)
            {
                ConfigId = configId;
                TargetName = targetName;
            }

            /// <summary>
            /// Retrieves the configuration id.
            /// </summary>
            public int ConfigId { get; }

            /// <summary>
            /// Retrieves the target name.
            /// </summary>
            public string TargetName { get; }
        }
    }
}


<|start_filename|>src/Build/BackEnd/Components/Communications/TranslatorExtensions.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Concurrent;
using System.Linq;
using Microsoft.Build.Collections;
using Microsoft.Build.Execution;
using Microsoft.Build.Shared;
using System.Reflection;

namespace Microsoft.Build.BackEnd
{
    /// <summary>
    /// This class is responsible for serializing and deserializing anything that is not 
    /// officially supported by ITranslator, but that we still want to do 
    /// custom translation of.  
    /// </summary>
    internal static class TranslatorExtensions
    {
        private static Lazy<ConcurrentDictionary<Type, ConstructorInfo>> parameterlessConstructorCache = new Lazy<ConcurrentDictionary<Type, ConstructorInfo>>(() => new ConcurrentDictionary<Type, ConstructorInfo>());

        /// <summary>
        /// Translates a PropertyDictionary of ProjectPropertyInstances.
        /// </summary>
        /// <param name="translator">The tranlator doing the translating</param>
        /// <param name="value">The dictionary to translate.</param>
        public static void TranslateProjectPropertyInstanceDictionary(this ITranslator translator, ref PropertyDictionary<ProjectPropertyInstance> value)
        {
            if (!translator.TranslateNullable(value))
            {
                return;
            }

            if (translator.Mode == TranslationDirection.ReadFromStream)
            {
                int count = 0;
                translator.Translate(ref count);

                value = new PropertyDictionary<ProjectPropertyInstance>(count);
                for (int i = 0; i < count; i++)
                {
                    ProjectPropertyInstance instance = null;
                    translator.Translate(ref instance, ProjectPropertyInstance.FactoryForDeserialization);
                    value[instance.Name] = instance;
                }
            }
            else // TranslationDirection.WriteToStream
            {
                int count = value.Count;
                translator.Translate(ref count);

                foreach (ProjectPropertyInstance instance in value)
                {
                    ProjectPropertyInstance instanceForSerialization = instance;
                    translator.Translate(ref instanceForSerialization, ProjectPropertyInstance.FactoryForDeserialization);
                }
            }
        }

        /// <summary>
        /// Deserialize a type or a subtype by its full name. The type must implement ITranslateable
        /// </summary>
        /// <typeparam name="T">Top level type. Serialized types can be of this type, or subtypes</typeparam>
        /// <returns></returns>
        public static T FactoryForDeserializingTypeWithName<T>(this ITranslator translator)
        {
            string typeName = null;
            translator.Translate(ref typeName);

            var type = Type.GetType(typeName);
            ErrorUtilities.VerifyThrowInvalidOperation(type != null, "type cannot be null");
            ErrorUtilities.VerifyThrowInvalidOperation(
                typeof(T).IsAssignableFrom(type),
                $"{typeName} must be a {typeof(T).FullName}");
            ErrorUtilities.VerifyThrowInvalidOperation(
                typeof(ITranslatable).IsAssignableFrom(type),
                $"{typeName} must be a {nameof(ITranslatable)}");

            var parameterlessConstructor = parameterlessConstructorCache.Value.GetOrAdd(
                type,
                t =>
                {
                    ConstructorInfo constructor = null;
#if FEATURE_TYPE_GETCONSTRUCTOR
                    constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
#else
                    constructor =
                        type
                            .GetTypeInfo()
                            .GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)
                            .FirstOrDefault(c => c.GetParameters().Length == 0);
#endif
                    ErrorUtilities.VerifyThrowInvalidOperation(
                        constructor != null,
                        $"{typeName} must have a private parameterless constructor");
                    return constructor;
                });

            var targetInstanceChild = (ITranslatable) parameterlessConstructor.Invoke(Array.Empty<object>());

            targetInstanceChild.Translate(translator);

            return (T) targetInstanceChild;
        }
    }
}


<|start_filename|>src/Tasks/ManifestUtil/Util.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using Microsoft.Win32;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using Microsoft.Build.Shared.FileSystem;

namespace Microsoft.Build.Tasks.Deployment.ManifestUtilities
{
    internal static class Util
    {
        internal static readonly string Schema = Environment.GetEnvironmentVariable("VSPSCHEMA");
        internal static readonly bool logging = !String.IsNullOrEmpty(Environment.GetEnvironmentVariable("VSPLOG"));
        internal static readonly string logPath = GetLogPath();
        private static readonly char[] s_fileNameInvalidChars = { '\\', '/', ':', '*', '?', '"', '<', '>', '|' };
        private static StreamWriter s_logFileWriter;
        // Major, Minor, Build and Revision of CLR v2.0
        private static readonly int[] s_clrVersion2 = { 2, 0, 50727, 0 };
#if RUNTIME_TYPE_NETCORE
        // Major, Minor, Build and Revision of CLR v4.0
        private static readonly int[] s_clrVersion4 = { 4, 0, 30319, 0 };
#endif

        #region " Platform <-> ProcessorArchitecture mapping "
        // Note: These two arrays are parallel and must correspond to one another.
        private static readonly string[] s_platforms =
        {
            "AnyCPU",
            "x86",
            "x64",
            "Itanium",
            "arm",
            "arm64",
        };
        private static readonly string[] s_processorArchitectures =
        {
            "msil",
            "x86",
            "amd64",
            "ia64",
            "arm",
            "arm64",
        };
        #endregion

        public static string ByteArrayToHex(Byte[] a)
        {
            if (a == null)
                return null;
            StringBuilder s = new StringBuilder(a.Length);
            foreach (Byte b in a)
                s.Append(b.ToString("X02", CultureInfo.InvariantCulture));
            return s.ToString();
        }

        public static string ByteArrayToString(Byte[] a)
        {
            if (a == null)
                return null;
            StringBuilder s = new StringBuilder(a.Length);
            foreach (Byte b in a)
                s.Append(Convert.ToChar(b));
            return s.ToString();
        }

        public static int CopyStream(Stream input, Stream output)
        {
            const int bufferSize = 0x4000;
            byte[] buffer = new byte[bufferSize];
            int bytesCopied = 0;
            int bytesRead;
            do
            {
                bytesRead = input.Read(buffer, 0, bufferSize);
                output.Write(buffer, 0, bytesRead);
                bytesCopied += bytesRead;
            } while (bytesRead > 0);
            output.Flush();
            input.Position = 0;
            output.Position = 0;
            return bytesCopied;
        }

        public static string FilterNonprintableChars(string value)
        {
            StringBuilder sb = new StringBuilder(value);
            int i = 0;
            while (i < sb.Length)
                if (sb[i] < ' ')
                    sb.Remove(i, 1);
                else
                    ++i;
            return sb.ToString();
        }

        public static string GetAssemblyPath()
        {
            return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        }

        public static string GetClrVersion()
        {
            Version v = Environment.Version;
#if RUNTIME_TYPE_NETCORE
            // This is a version of ClickOnce .NET FX target runtime, which cannot be obtained in .NET (Core) process.
            // Set to .NET FX v4 runtime as the ony one supported for manifest generation in .NET (Core) process.
            v = new Version(s_clrVersion4[0], s_clrVersion4[1], s_clrVersion4[2], s_clrVersion4[3]);
#else
            v = new Version(v.Major, v.Minor, v.Build, 0);
#endif
            return v.ToString();
        }

        /// <summary>
        /// Return a CLRVersion from a given target framework version.
        /// </summary>
        /// <param name="targetFrameworkVersion"></param>
        /// <returns></returns>
        public static string GetClrVersion(string targetFrameworkVersion)
        {
            if (string.IsNullOrEmpty(targetFrameworkVersion))
                return GetClrVersion();

            Version clrVersion;
#if RUNTIME_TYPE_NETCORE
            // This is a version of ClickOnce .NET FX target runtime, which cannot be obtained in .NET (Core) process.
            // Set to .NET FX v4 runtime as the ony one supported for manifest generation in .NET (Core) process.
            Version currentVersion = new Version(s_clrVersion4[0], s_clrVersion4[1], s_clrVersion4[2], s_clrVersion4[3]);
#else
            Version currentVersion = Environment.Version;
#endif
            Version frameworkVersion = GetTargetFrameworkVersion(targetFrameworkVersion);

            // for FX 4.0 or above use the current version.
            if (frameworkVersion != null && (frameworkVersion.Major >= currentVersion.Major))
            {
                clrVersion = new Version(currentVersion.Major, currentVersion.Minor, currentVersion.Build, 0);
            }
            else
            {
#if RUNTIME_TYPE_NETCORE
                // Set to .NET FX v4 runtime as the ony one supported for manifest generation in .NET (Core) process.
                clrVersion = new Version(s_clrVersion4[0], s_clrVersion4[1], s_clrVersion4[2], s_clrVersion4[3]);
#else
                clrVersion = new Version(s_clrVersion2[0], s_clrVersion2[1], s_clrVersion2[2], s_clrVersion2[3]);
#endif
            }
            return clrVersion.ToString();
        }

        /// <summary>
        /// Gets a Version object corresponding to the given target framework version string.
        /// </summary>
        public static Version GetTargetFrameworkVersion(string targetFramework)
        {
            Version frameworkVersion = null;
            if (!String.IsNullOrEmpty(targetFramework))
            {
                if (targetFramework.StartsWith("v", StringComparison.OrdinalIgnoreCase))
                {
                    Version.TryParse(targetFramework.Substring(1), out frameworkVersion);
                }
                else
                {
                    Version.TryParse(targetFramework, out frameworkVersion);
                }
            }
            return frameworkVersion;
        }

        public static string GetEmbeddedResourceString(string name)
        {
            Stream s = GetEmbeddedResourceStream(name);
            StreamReader r = new StreamReader(s);
            return r.ReadToEnd();
        }

        public static Stream GetEmbeddedResourceStream(string name)
        {
            Assembly a = Assembly.GetExecutingAssembly();
            Stream s = a.GetManifestResourceStream(String.Format(CultureInfo.InvariantCulture, "{0}.{1}", typeof(Util).Namespace, name));
            Debug.Assert(s != null, String.Format(CultureInfo.CurrentCulture, "EmbeddedResource '{0}' not found", name));
            return s;
        }

        public static void GetFileInfo(string path, out string hash, out long length)
        {
            GetFileInfoImpl(path, null, out hash, out length);
        }

        public static void GetFileInfo(string path, string targetFrameworkVersion, out string hash, out long length)
        {
            GetFileInfoImpl(path, targetFrameworkVersion, out hash, out length);
        }

        [SuppressMessage("Microsoft.Security.Cryptography", "CA5354: SHA1CannotBeUsed.", Justification = ".NET 4.0 and earlier versions cannot parse SHA-2.")]
        private static void GetFileInfoImpl(string path, string targetFrameWorkVersion, out string hash, out long length)
        {
            FileInfo fi = new FileInfo(path);
            length = fi.Length;

            Stream s = null;
            try
            {
                s = fi.OpenRead();
                HashAlgorithm hashAlg;

                if (string.IsNullOrEmpty(targetFrameWorkVersion) || CompareFrameworkVersions(targetFrameWorkVersion, Constants.TargetFrameworkVersion40) <= 0)
                {
                    hashAlg = new SHA1CryptoServiceProvider();
                }
                else
                {
                    hashAlg = new SHA256CryptoServiceProvider();
                }
                byte[] hashBytes = hashAlg.ComputeHash(s);
                hash = Convert.ToBase64String(hashBytes);
            }
            finally
            {
                s?.Close();
            }
        }

        private static string GetLogPath()
        {
            if (!logging) return null;
            string logPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Microsoft\VisualStudio\8.0\VSPLOG");
            if (!FileSystems.Default.DirectoryExists(logPath))
                Directory.CreateDirectory(logPath);
            return logPath;
        }

        public static string GetRegisteredOrganization()
        {
            RegistryKey key = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", false);
            if (key != null)
            {
                string org = (string)key.GetValue("RegisteredOrganization");
                org = org?.Trim();
                if (!String.IsNullOrEmpty(org))
                    return org;
            }
            return null;
        }

        public static bool IsValidAssemblyName(string value)
        {
            return IsValidFileName(value);
        }

        public static bool IsValidCulture(string value)
        {
            if (String.Equals(value, "neutral", StringComparison.OrdinalIgnoreCase))
                return true; // "neutral" is valid in a manifest but not in CultureInfo class
            if (String.Equals(value, "*", StringComparison.OrdinalIgnoreCase))
                return true; // "*" is same as "neutral"
            CultureInfo culture;
            try
            {
                culture = new CultureInfo(value);
            }
            catch (ArgumentException)
            {
                return false;
            }
            return true;
        }

        public static bool IsValidFileName(string value)
        {
            return value.IndexOfAny(s_fileNameInvalidChars) < 0;
        }

        public static bool IsValidVersion(string value, int octets)
        {
            Version version;
            try
            {
                version = new Version(value);
            }
            catch (FormatException)
            {
                return false;
            }
            catch (ArgumentOutOfRangeException)
            {
                return false;
            }
            catch (ArgumentNullException)
            {
                return false;
            }
            catch (ArgumentException)
            {
                return false;
            }
            catch (OverflowException)
            {
                return false;
            }

            if (octets >= 1 && version.Major < 0)
                return false;
            if (octets >= 2 && version.Minor < 0)
                return false;
            if (octets >= 3 && version.Build < 0)
                return false;
            if (octets >= 4 && version.Revision < 0)
                return false;

            return true;
        }

        internal static bool IsValidFrameworkVersion(string value)
        {
            if (value.StartsWith("v", StringComparison.OrdinalIgnoreCase))
                return IsValidVersion(value.Substring(1), 2);
            return IsValidVersion(value, 2);
        }

        public static string PlatformToProcessorArchitecture(string platform)
        {
            for (int i = 0; i < s_platforms.Length; ++i)
                if (String.Equals(platform, s_platforms[i], StringComparison.OrdinalIgnoreCase))
                    return s_processorArchitectures[i];
            return null;
        }

        private static ITaskItem[] RemoveDuplicateItems(ITaskItem[] items)
        {
            if (items == null)
                return null;
            if (items.Length <= 1)
                return items;
            var list = new Dictionary<string, ITaskItem>();
            foreach (ITaskItem item in items)
            {
                if (String.IsNullOrEmpty(item.ItemSpec))
                {
                    continue;
                }

                string key;
                var id = new AssemblyIdentity(item.ItemSpec);
                if (id.IsStrongName)
                {
                    key = id.GetFullName(AssemblyIdentity.FullNameFlags.All);
                }
                else
                {
                    key = Path.GetFullPath(item.ItemSpec).ToUpperInvariant();
                }

                if (!list.ContainsKey(key))
                {
                    list.Add(key, item);
                }
            }

            return list.Values.ToArray();
        }

        public static ITaskItem[] SortItems(ITaskItem[] items)
        {
            ITaskItem[] outputItems = RemoveDuplicateItems(items);
            if (outputItems != null)
                Array.Sort(outputItems, s_itemComparer);
            return outputItems;
        }

        public static void WriteFile(string path, string s)
        {
            using (StreamWriter w = new StreamWriter(path))
            {
                w.Write(s);
            }
        }

        public static void WriteFile(string path, Stream s)
        {
            StreamReader r = new StreamReader(s);
            WriteFile(path, r.ReadToEnd());
        }

        public static void WriteLog(string text)
        {
            if (!logging)
                return;
            if (s_logFileWriter == null)
                try
                {
                    s_logFileWriter = new StreamWriter(Path.Combine(logPath, "Microsoft.Build.Tasks.log"), false);
                }
                catch (UnauthorizedAccessException)
                {
                    return;
                }
                catch (ArgumentException)
                {
                    return;
                }
                catch (IOException)
                {
                    return;
                }
                catch (SecurityException)
                {
                    return;
                }
            s_logFileWriter.WriteLine(text);
            s_logFileWriter.Flush();
        }

        public static void WriteLogFile(string filename, Stream s)
        {
            if (!logging)
                return;
            string path = Path.Combine(logPath, filename);
            StreamReader r = new StreamReader(s);
            string text = r.ReadToEnd();
            try
            {
                WriteFile(path, text);
            }
            catch (UnauthorizedAccessException)
            {
            }
            catch (ArgumentException)
            {
            }
            catch (IOException)
            {
            }
            catch (SecurityException)
            {
            }
            s.Position = 0;
        }

        public static void WriteLogFile(string filename, string s)
        {
            if (!logging)
                return;
            string path = Path.Combine(logPath, filename);
            try
            {
                WriteFile(path, s);
            }
            catch (UnauthorizedAccessException)
            {
                return;
            }
            catch (ArgumentException)
            {
                return;
            }
            catch (IOException)
            {
                return;
            }
            catch (SecurityException)
            {
                return;
            }
        }

        public static void WriteLogFile(string filename, System.Xml.XmlElement element)
        {
            if (!logging)
                return;
            WriteLogFile(filename, element.OuterXml);
        }

        public static string WriteTempFile(Stream s)
        {
            // May throw IO-related exceptions
            string path = FileUtilities.GetTemporaryFile();

            WriteFile(path, s);
            return path;
        }

        public static string WriteTempFile(string s)
        {
            // May throw IO-related exceptions
            string path = FileUtilities.GetTemporaryFile();

            WriteFile(path, s);
            return path;
        }

        #region ItemComparer 
        private static readonly ItemComparer s_itemComparer = new ItemComparer();
        private class ItemComparer : IComparer
        {
            int IComparer.Compare(object obj1, object obj2)
            {
                if (obj1 == null || obj2 == null)
                {
                    Debug.Fail("Comparing null objects");
                    return 0;
                }
                if (!(obj1 is ITaskItem) || !(obj2 is ITaskItem))
                {
                    Debug.Fail("Comparing objects that are not ITaskItem");
                    return 0;
                }
                ITaskItem item1 = obj1 as ITaskItem;
                ITaskItem item2 = obj2 as ITaskItem;
                if (item1.ItemSpec == null || item2.ItemSpec == null)
                {
                    Debug.Fail("Objects do not have a ItemSpec");
                    return 0;
                }
                return String.Compare(item1.ItemSpec, item2.ItemSpec, StringComparison.Ordinal);
            }
        }
        #endregion

        public static Version ConvertFrameworkVersionToString(string version)
        {
            if (version.StartsWith("v", StringComparison.OrdinalIgnoreCase))
            {
                return new Version(version.Substring(1));
            }
            return new Version(version);
        }

        public static int CompareFrameworkVersions(string versionA, string versionB)
        {
            Version version1 = ConvertFrameworkVersionToString(versionA);
            Version version2 = ConvertFrameworkVersionToString(versionB);
            return version1.CompareTo(version2);
        }
    }
}


<|start_filename|>src/Shared/LanguageParser/CSharptokenCharReader.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.IO;

namespace Microsoft.Build.Shared.LanguageParser
{
    /*
     * Class:   CSharpTokenCharReader
     *
     * Reads over the contents of a C# source file (in the form of a string). 
     * Provides utility functions for dealing with C#-specific tokens.
     *
     */
    sealed internal class CSharpTokenCharReader : TokenCharReader
    {
        /*
         * Method:  CSharpTokenCharReader
         * 
         * Construct
         */
        internal CSharpTokenCharReader(Stream binaryStream, bool forceANSI)
            : base(binaryStream, forceANSI)
        {
        }

        /*
         * Method:  SinkLongIntegerSuffix
         * 
         * Skip C# integer literal long suffix: L, U, l, u, ul, etc.                    
         */
        internal bool SinkLongIntegerSuffix()
        {
            // Skip the long integer suffix if there is one.
            if (CurrentCharacter == 'U' || CurrentCharacter == 'u')
            {
                Skip();
                if (CurrentCharacter == 'L' || CurrentCharacter == 'l')
                {
                    Skip();
                }
            }
            else if (CurrentCharacter == 'L' || CurrentCharacter == 'l')
            {
                Skip();
                if (CurrentCharacter == 'U' || CurrentCharacter == 'u')
                {
                    Skip();
                }
            }

            return true; // An integer suffix can be zero characters, so there's always a match.
        }

        /*
         * Method:  SinkOperatorOrPunctuator
         * 
         * Determine whether this is a C# operator or punctuator
         */
        internal bool SinkOperatorOrPunctuator()
        {
            const string operatorsAndPunctuators = "{}[]().,:;+-*/%&|^!~=<>?";
            if (operatorsAndPunctuators.IndexOf(CurrentCharacter) == -1)
            {
                return false;
            }
            Skip();
            return true;
        }

        /*
         * Method:  SinkStringEscape
         * 
         * Determine whether this is a valid escape character for strings?
         */
        internal bool SinkStringEscape()
        {
            switch (CurrentCharacter)
            {
                case '\'':
                case '\"':
                case '0':
                case 'a':
                case 'b':
                case 'f':
                case 'n':
                case 'r':
                case 't':
                case 'u':
                case 'U':
                case 'x':
                case 'v':
                case '\x005c' /* backslash */:
                    Skip();
                    return true;
            }
            return false;
        }

        /*
         * Method:  MatchRegularStringLiteral
         * 
         * Determine whether this is a regular C# string literal character
         */
        internal bool MatchRegularStringLiteral()
        {
            if (CurrentCharacter == '\"' || CurrentCharacter == '\\' || TokenChar.IsNewLine(CurrentCharacter))
            {
                return false;
            }

            return true;
        }

        /*
         * Method:  SinkMultipleWhiteSpace
         * 
         * Sink some C# whitespace
         */
        internal bool SinkMultipleWhiteSpace()
        {
            int count = 0;
            while (!EndOfLines && Char.IsWhiteSpace(CurrentCharacter))
            {
                Skip();
                ++count;
            }

            return count > 0;
        }
    }
}



<|start_filename|>src/Samples/XmlFileLogger/ObjectModel/TaskParameter.cs<|end_filename|>
﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace Microsoft.Build.Logging.StructuredLogger
{
    /// <summary>
    /// Abstract base class for task input / output parameters (can be ItemGroups)
    /// </summary>
    internal abstract class TaskParameter : ILogNode
    {
        protected bool collapseSingleItem;
        protected string itemAttributeName;
        protected readonly List<Item> items = new List<Item>();
        protected readonly string name;

        /// <summary>
        /// Initializes a new instance of the <see cref="TaskParameter"/> class.
        /// </summary>
        /// <param name="message">The message from the logging system.</param>
        /// <param name="prefix">The prefix parsed out (e.g. 'Output Item(s): ').</param>
        /// <param name="collapseSingleItem">If set to <c>true</c>, will collapse the node to a single item when possible.</param>
        /// <param name="itemAttributeName">Name of the item 'Include' attribute.</param>
        protected TaskParameter(string message, string prefix, bool collapseSingleItem = true, string itemAttributeName = "Include")
        {
            this.collapseSingleItem = collapseSingleItem;
            this.itemAttributeName = itemAttributeName;

            foreach (var item in ItemGroupParser.ParseItemList(message, prefix, out name))
            {
                items.Add(item);
            }
        }

        /// <summary>
        /// Saves the task parameter node to XML XElement.
        /// </summary>
        /// <param name="parentElement">The parent element.</param>
        public void SaveToElement(XElement parentElement)
        {
            XElement element = new XElement(name);
            parentElement.Add(element);

            if (collapseSingleItem && items.Count == 1 && !items[0].Metadata.Any())
            {
                element.Add(items[0].Text);
            }
            else
            {
                foreach (var item in items)
                {
                    item.SaveToElement(element, itemAttributeName, collapseSingleItem);
                }
            }
        }

        /// <summary>
        /// Creates a concrete Task Parameter type based on the message logging message.
        /// </summary>
        /// <param name="message">The message string from the logger.</param>
        /// <param name="prefix">The prefix to the message string.</param>
        /// <returns>Concrete task parameter node.</returns>
        public static TaskParameter Create(string message, string prefix)
        {
            return prefix switch
            {
                XmlFileLogger.OutputItemsMessagePrefix => new OutputItem(message, prefix),
                XmlFileLogger.TaskParameterMessagePrefix => new InputParameter(message, prefix),
                XmlFileLogger.OutputPropertyMessagePrefix => new OutputProperty(message, prefix),
                XmlFileLogger.ItemGroupIncludeMessagePrefix => new ItemGroup(message, prefix, "Include"),
                XmlFileLogger.ItemGroupRemoveMessagePrefix => new ItemGroup(message, prefix, "Remove"),
                _ => throw new UnknownTaskParameterPrefixException(prefix),
            };
        }
    }
}
