File: NativeMethodsShared_Tests.cs
Web Access
Project: ..\..\..\src\Utilities.UnitTests\Microsoft.Build.Utilities.UnitTests.csproj (Microsoft.Build.Utilities.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Microsoft.Build.Shared;
using Xunit;
using Xunit.NetCore.Extensions;
 
 
 
#nullable disable
 
namespace Microsoft.Build.UnitTests
{
    public sealed class NativeMethodsShared_Tests
    {
        #region Data
 
        // Create a delegate to test the GetProcessId method when using GetProcAddress
        private delegate uint GetProcessIdDelegate();
 
        #endregion
 
        #region Tests
 
        /// <summary>
        /// Verify that getProcAddress works, bug previously was due to a bug in the attributes used to pinvoke the method
        /// when that bug was in play this test would fail.
        /// </summary>
        [WindowsOnlyFact("No Kernel32.dll except on Windows.")]
        [SupportedOSPlatform("windows")] // bypass CA1416: Validate platform compatibility
        public void TestGetProcAddress()
        {
            IntPtr kernel32Dll = NativeMethodsShared.LoadLibrary("kernel32.dll");
            try
            {
                IntPtr processHandle = NativeMethodsShared.NullIntPtr;
                if (kernel32Dll != NativeMethodsShared.NullIntPtr)
                {
                    processHandle = NativeMethodsShared.GetProcAddress(kernel32Dll, "GetCurrentProcessId");
                }
                else
                {
                    Assert.Fail();
                }
 
                // Make sure the pointer passed back for the method is not null
                Assert.NotEqual(processHandle, NativeMethodsShared.NullIntPtr);
 
                // Actually call the method
                GetProcessIdDelegate processIdDelegate = Marshal.GetDelegateForFunctionPointer<GetProcessIdDelegate>(processHandle);
                uint processId = processIdDelegate();
 
                // Make sure the return value is the same as retrieved from the .net methods to make sure everything works
                Assert.Equal((uint)Process.GetCurrentProcess().Id, processId); // "Expected the .net processId to match the one from GetCurrentProcessId"
            }
            finally
            {
                if (kernel32Dll != NativeMethodsShared.NullIntPtr)
                {
                    NativeMethodsShared.FreeLibrary(kernel32Dll);
                }
            }
        }
 
        /// <summary>
        /// Verifies that when NativeMethodsShared.GetLastWriteFileUtcTime() is called on a
        /// missing time, DateTime.MinValue is returned.
        /// </summary>
        [Fact]
        public void GetLastWriteFileUtcTimeReturnsMinValueForMissingFile()
        {
            string nonexistentFile = FileUtilities.GetTemporaryFileName();
 
            DateTime nonexistentFileTime = NativeMethodsShared.GetLastWriteFileUtcTime(nonexistentFile);
            Assert.Equal(DateTime.MinValue, nonexistentFileTime);
        }
 
        /// <summary>
        /// Verifies that when NativeMethodsShared.GetLastWriteFileUtcTime() is called on a
        /// *directory*, DateTime.MinValue is returned.
        /// </summary>
        [Fact]
        public void GetLastWriteFileUtcTimeReturnsMinValueForDirectory()
        {
            string directory = FileUtilities.GetTemporaryDirectory(createDirectory: true);
 
            DateTime directoryTime = NativeMethodsShared.GetLastWriteFileUtcTime(directory);
            Assert.Equal(DateTime.MinValue, directoryTime);
        }
 
        /// <summary>
        /// Verifies that when NativeMethodsShared.GetLastWriteDirectoryUtcTime() is called on a
        /// *file*, it returns DateTime.MinValue
        /// </summary>
        [Fact]
        public void GetLastWriteDirectoryUtcTimeReturnsMinValueForFile()
        {
            string file = FileUtilities.GetTemporaryFile();
 
            DateTime directoryTime;
            Assert.False(NativeMethodsShared.GetLastWriteDirectoryUtcTime(file, out directoryTime));
            Assert.Equal(DateTime.MinValue, directoryTime);
        }
 
 
        /// <summary>
        /// Verifies that NativeMethodsShared.SetCurrentDirectory(), when called on a nonexistent
        /// directory, will not set the current directory to that location.
        /// </summary>
        [Fact]
        public void SetCurrentDirectoryDoesNotSetNonexistentFolder()
        {
            string currentDirectory = Directory.GetCurrentDirectory();
            string nonexistentDirectory = Path.Combine(currentDirectory, "foo", "bar", "baz");
 
            // Make really sure the nonexistent directory doesn't actually exist
            if (Directory.Exists(nonexistentDirectory))
            {
                for (int i = 0; i < 10; i++)
                {
                    nonexistentDirectory = Path.Combine(currentDirectory, "foo", "bar", "baz") + Guid.NewGuid();
 
                    if (!Directory.Exists(nonexistentDirectory))
                    {
                        break;
                    }
                }
            }
 
            Assert.False(Directory.Exists(nonexistentDirectory),
                "Tried 10 times to get a nonexistent directory name and failed -- please try again");
 
            bool exceptionCaught = false;
            try
            {
                NativeMethodsShared.SetCurrentDirectory(nonexistentDirectory);
            }
            catch (Exception e)
            {
                exceptionCaught = true;
                Console.WriteLine(e.Message);
            }
            finally
            {
                // verify that the current directory did not change
                Assert.False(exceptionCaught); // "SetCurrentDirectory should not throw!"
                Assert.Equal(currentDirectory, Directory.GetCurrentDirectory());
            }
        }
 
        #endregion
    }
}