#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion

using NUnit.Framework;
using System.Diagnostics;
using System;
using System.Reflection;
using System.IO;

namespace Google.Protobuf
{
    public class RefStructCompatibilityTest
    {
        /// <summary>
        /// Checks that the generated code can be compiler with an old C# compiler.
        /// The reason why this test is needed is that even though dotnet SDK projects allow to set LangVersion,
        /// this setting doesn't accurately simulate compilation with an actual old pre-roslyn C# compiler.
        /// For instance, the "ref struct" types are only supported by C# 7.2 and higher, but even if
        /// LangVersion is set low, the roslyn compiler still understands the concept of ref struct
        /// and silently accepts them. Therefore we try to build the generated code with an actual old C# compiler
        /// to be able to catch these sort of compatibility problems.
        /// </summary>
        [Test]
        public void GeneratedCodeCompilesWithOldCsharpCompiler()
        {
            if (Environment.OSVersion.Platform != PlatformID.Win32NT)
            {
                // This tests needs old C# compiler which is only available on Windows. Skipping it on all other platforms.
                return;
            }

            var currentAssemblyDir = Path.GetDirectoryName(typeof(RefStructCompatibilityTest).GetTypeInfo().Assembly.Location);
            var testProtosProjectDir = Path.GetFullPath(Path.Combine(currentAssemblyDir, "..", "..", "..", "..", "Google.Protobuf.Test.TestProtos"));
            var testProtosOutputDir = (currentAssemblyDir.Contains("bin/Debug/") || currentAssemblyDir.Contains("bin\\Debug\\")) ? "bin\\Debug\\net45" : "bin\\Release\\net45";

            // If "ref struct" types are used in the generated code, compilation with an old compiler will fail with the following error:
            // "XYZ is obsolete: 'Types with embedded references are not supported in this version of your compiler.'"
            // We build the code with GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE to avoid the use of ref struct in the generated code.
            var compatibilityFlag = "-define:GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE";
            var sources = "*.cs";  // the generated sources from the TestProtos project
            var args = $"-langversion:3 -target:library {compatibilityFlag} -reference:{testProtosOutputDir}\\Google.Protobuf.dll -out:{testProtosOutputDir}\\TestProtos.RefStructCompatibilityTest.OldCompiler.dll {sources}";
            RunOldCsharpCompilerAndCheckSuccess(args, testProtosProjectDir);
        }

        /// <summary>
        /// Invoke an old C# compiler in a subprocess and check it finished successful.
        /// </summary>
        /// <param name="args"></param>
        /// <param name="workingDirectory"></param>
        private void RunOldCsharpCompilerAndCheckSuccess(string args, string workingDirectory)
        {  
            using (var process = new Process())
            {
                // Get the path to the old C# 5 compiler from .NET framework. This approach is not 100% reliable, but works on most machines.
                // Alternative way of getting the framework path is System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory()
                // but it only works with the net45 target.
                var oldCsharpCompilerPath = Path.Combine(Environment.GetEnvironmentVariable("WINDIR"), "Microsoft.NET", "Framework", "v4.0.30319", "csc.exe");
                process.StartInfo.FileName = oldCsharpCompilerPath;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardError = true;
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.Arguments = args;
                process.StartInfo.WorkingDirectory = workingDirectory;

                process.OutputDataReceived += (sender, e) =>
                {
                    if (e.Data != null)
                    {
                        Console.WriteLine(e.Data);
                    }
                };
                process.ErrorDataReceived += (sender, e) =>
                {
                    if (e.Data != null)
                    {
                        Console.WriteLine(e.Data);
                    }
                };

                process.Start();

                process.BeginErrorReadLine();
                process.BeginOutputReadLine();

                process.WaitForExit();
                Assert.AreEqual(0, process.ExitCode);
            }
        }
    }
}