// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Generic;
using System.Globalization;
using System.IO;
using Microsoft.TestCommon;

namespace System.Web.Mvc.Test
{
    public class TypeCacheSerializerTest
    {
        private static string _expectedDeserializationFormat =
            "<?xml version=\"1.0\" encoding=\"utf-16\"?>" + Environment.NewLine
          + "<!--This file is automatically generated. Please do not modify the contents of this file.-->" + Environment.NewLine
          + "<typeCache lastModified=\"__IGNORED__\" mvcVersionId=\"{0}\">" + Environment.NewLine
          + "  <assembly name=\"{1}\">" + Environment.NewLine
          + "    <module versionId=\"{2}\">" + Environment.NewLine
          + "      <type>System.String</type>" + Environment.NewLine
          + "      <type>System.Object</type>" + Environment.NewLine
          + "    </module>" + Environment.NewLine
          + "  </assembly>" + Environment.NewLine
          + "</typeCache>";

        private static readonly string _mscorlibAsmFullName = typeof(object).Assembly.FullName;

        [Fact]
        public void DeserializeTypes_ReturnsNullIfModuleVersionIdDoesNotMatch()
        {
            // Arrange
            string expected = String.Format(_expectedDeserializationFormat,
                                            GetMvidForType(typeof(TypeCacheSerializer)) /* mvcVersionId */,
                                            _mscorlibAsmFullName /* assembly.name */,
                                            Guid.Empty /* module.versionId */
                );

            TypeCacheSerializer serializer = new TypeCacheSerializer();
            StringReader input = new StringReader(expected);

            // Act
            List<Type> deserializedTypes = serializer.DeserializeTypes(input);

            // Assert
            Assert.Null(deserializedTypes);
        }

        [Fact]
        public void DeserializeTypes_ReturnsNullIfMvcVersionIdDoesNotMatch()
        {
            // Arrange
            string expected = String.Format(_expectedDeserializationFormat,
                                            Guid.Empty /* mvcVersionId */,
                                            _mscorlibAsmFullName /* assembly.name */,
                                            GetMvidForType(typeof(object)) /* module.versionId */
                );

            TypeCacheSerializer serializer = new TypeCacheSerializer();
            StringReader input = new StringReader(expected);

            // Act
            List<Type> deserializedTypes = serializer.DeserializeTypes(input);

            // Assert
            Assert.Null(deserializedTypes);
        }

        [Fact]
        public void DeserializeTypes_ReturnsNullIfTypeNotFound()
        {
            string expectedFormat =
                "<?xml version=\"1.0\" encoding=\"utf-16\"?>" + Environment.NewLine
              + "<!--This file is automatically generated. Please do not modify the contents of this file.-->" + Environment.NewLine
              + "<typeCache lastModified=\"__IGNORED__\" mvcVersionId=\"{0}\">" + Environment.NewLine
              + "  <assembly name=\"{1}\">" + Environment.NewLine
              + "    <module versionId=\"{2}\">" + Environment.NewLine
              + "      <type>System.String</type>" + Environment.NewLine
              + "      <type>This.Type.Does.Not.Exist</type>" + Environment.NewLine
              + "    </module>" + Environment.NewLine
              + "  </assembly>" + Environment.NewLine
              + "</typeCache>";

            // Arrange
            string expected = String.Format(expectedFormat,
                                            GetMvidForType(typeof(TypeCacheSerializer)) /* mvcVersionId */,
                                            _mscorlibAsmFullName /* assembly.name */,
                                            GetMvidForType(typeof(object)) /* module.versionId */
                );

            TypeCacheSerializer serializer = new TypeCacheSerializer();
            StringReader input = new StringReader(expected);

            // Act
            List<Type> deserializedTypes = serializer.DeserializeTypes(input);

            // Assert
            Assert.Null(deserializedTypes);
        }

        [Fact]
        public void DeserializeTypes_Success()
        {
            // Arrange
            string expected = String.Format(_expectedDeserializationFormat,
                                            GetMvidForType(typeof(TypeCacheSerializer)) /* mvcVersionId */,
                                            _mscorlibAsmFullName /* assembly.name */,
                                            GetMvidForType(typeof(object)) /* module.versionId */
                );

            TypeCacheSerializer serializer = new TypeCacheSerializer();
            StringReader input = new StringReader(expected);

            Type[] expectedTypes = new Type[]
            {
                typeof(string),
                typeof(object)
            };

            // Act
            List<Type> deserializedTypes = serializer.DeserializeTypes(input);

            // Assert
            Assert.Equal(expectedTypes, deserializedTypes.ToArray());
        }

        [Fact]
        public void SerializeTypes()
        {
            // Arrange
            DateTime expectedDate = new DateTime(2001, 1, 1, 0, 0, 0, DateTimeKind.Utc); // Jan 1, 2001 midnight UTC
            string expectedFormat =
                "<?xml version=\"1.0\" encoding=\"utf-16\"?>" + Environment.NewLine
              + "<!--This file is automatically generated. Please do not modify the contents of this file.-->" + Environment.NewLine
              + "<typeCache lastModified=\"{0}\" mvcVersionId=\"{1}\">" + Environment.NewLine
              + "  <assembly name=\"{2}\">" + Environment.NewLine
              + "    <module versionId=\"{3}\">" + Environment.NewLine
              + "      <type>System.String</type>" + Environment.NewLine
              + "      <type>System.Object</type>" + Environment.NewLine
              + "    </module>" + Environment.NewLine
              + "  </assembly>" + Environment.NewLine
              + "</typeCache>";

            string expected = String.Format(CultureInfo.InvariantCulture,
                                            expectedFormat,
                                            expectedDate /* lastModified */,
                                            GetMvidForType(typeof(TypeCacheSerializer)) /* mvcVersionId */,
                                            _mscorlibAsmFullName /* assembly.name */,
                                            GetMvidForType(typeof(object)) /* module.versionId */
                );

            Type[] typesToSerialize = new Type[]
            {
                typeof(string),
                typeof(object)
            };

            TypeCacheSerializer serializer = new TypeCacheSerializer();
            serializer.CurrentDateOverride = expectedDate;

            StringWriter output = new StringWriter();

            // Act
            serializer.SerializeTypes(typesToSerialize, output);
            string outputString = output.ToString();

            // Assert
            Assert.Equal(expected, outputString);
        }

        private static Guid GetMvidForType(Type type)
        {
            return type.Module.ModuleVersionId;
        }
    }
}
