﻿using MJennings.Extensions;
using MJennings.Logging;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Diagnostics;
using Xunit;

namespace MJennings.Common.Tests.Logging
{
    public class LogEntryTests : LoggingTestsBase
    {
        [Fact]
        public void ToCsvString_WithPropertiesSet_ShouldProduceValidCsv()
        {
            var logEntry = new LogEntry();

            logEntry.LogEntryId = "102030405060708090";
            logEntry.Timestamp = new DateTime(2014, 11, 4, 13, 44, 55, 177);
            logEntry.Severity = LogLevel.Debug;
            logEntry.Source = "Some.Test.Source";
            logEntry.Message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";

            /*
            logEntry.StackTrace = new StackTrace();
            */

            /*
            try { throw new InvalidOperationException("You can't do that!"); }
            catch (Exception ex) { logEntry.Exception = ex; }
            */

            logEntry.Data.Add("Department", "Information Technology");
            logEntry.Data.Add("Number", 777);
            logEntry.Data.Add("Salary", 98765.43);
            logEntry.Data.Add("HireDate", new DateTime(2012, 6, 1));

            var expected = "\"102030405060708090\",\"2014-11-04 13:44:55.177\",\"Debug\",\"Some.Test.Source\",\"Lorem ipsum dolor sit amet, consectetur adipiscing elit.\",\"\",\"\",\"Information Technology\",\"777\",\"98765.43\",\"2012-06-01 00:00:00.000\"" + Environment.NewLine;
            var actual = logEntry.ToCsvString();

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void ToCsvString_WithMultilineMessage_LineBreaksShouldBeReplaced()
        {
            var logEntry = new LogEntry();

            logEntry.LogEntryId = "102030405060708090";
            logEntry.Timestamp = new DateTime(2014, 11, 4, 13, 44, 55, 177);
            logEntry.Severity = LogLevel.Debug;
            logEntry.Source = "Some.Test.Source";
            logEntry.Message = @"Lorem ipsum dolor sit amet,
consectetur adipiscing elit.";

            /*
            logEntry.StackTrace = new StackTrace();
            */

            /*
            try { throw new InvalidOperationException("You can't do that!"); }
            catch (Exception ex) { logEntry.Exception = ex; }
            */

            logEntry.Data.Add("Department", "Information Technology");
            logEntry.Data.Add("Number", 777);
            logEntry.Data.Add("Salary", 98765.43);
            logEntry.Data.Add("HireDate", new DateTime(2012, 6, 1));

            var expected = "\"102030405060708090\",\"2014-11-04 13:44:55.177\",\"Debug\",\"Some.Test.Source\",\"Lorem ipsum dolor sit amet,\\nconsectetur adipiscing elit.\",\"\",\"\",\"Information Technology\",\"777\",\"98765.43\",\"2012-06-01 00:00:00.000\"" + Environment.NewLine;
            var actual = logEntry.ToCsvString();

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void ToDelimitedString_WithPipeDelimiter_ShouldProduceDelimitedOutput()
        {
            var logEntry = new LogEntry();

            logEntry.LogEntryId = "102030405060708090";
            logEntry.Timestamp = new DateTime(2014, 11, 4, 13, 44, 55, 177);
            logEntry.Severity = LogLevel.Debug;
            logEntry.Source = "Some.Test.Source";
            logEntry.Message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";

            /*
            logEntry.StackTrace = new StackTrace();
            */

            /*
            try { throw new InvalidOperationException("You can't do that!"); }
            catch (Exception ex) { logEntry.Exception = ex; }
            */

            logEntry.Data.Add("Department", "Information Technology");
            logEntry.Data.Add("Number", 777);
            logEntry.Data.Add("Salary", 98765.43);
            logEntry.Data.Add("HireDate", new DateTime(2012, 6, 1));

            var expected = "102030405060708090|2014-11-04 13:44:55.177|Debug|Some.Test.Source|Lorem ipsum dolor sit amet, consectetur adipiscing elit.|||Information Technology|777|98765.43|2012-06-01 00:00:00.000";
            var actual = logEntry.ToDelimitedString("|");

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void ToSqlParameters_WithPropertiesSet_ShouldProduceSqlParametersArray()
        {
            var logEntry = new LogEntry();

            logEntry.LogEntryId = "102030405060708090";
            logEntry.Timestamp = new DateTime(2014, 11, 4, 13, 44, 55, 177);
            logEntry.Severity = LogLevel.Debug;
            logEntry.Source = "Some.Test.Source";
            logEntry.Message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
            logEntry.StackTrace = new StackTrace();

            try { throw new InvalidOperationException("You can't do that!"); }
            catch (Exception ex) { logEntry.Exception = ex; }

            logEntry.Data.Add("Department", "Information Technology");
            logEntry.Data.Add("Number", 777);
            logEntry.Data.Add("Salary", 98765.43);
            logEntry.Data.Add("HireDate", new DateTime(2012, 6, 1));

            var list = new List<SqlParameter>();
            list.Add(new SqlParameter("@LogEntryId", logEntry.LogEntryId));
            list.Add(new SqlParameter("@Timestamp", logEntry.Timestamp));
            list.Add(new SqlParameter("@Severity", logEntry.Severity));
            list.Add(new SqlParameter("@Source", logEntry.Source));
            list.Add(new SqlParameter("@Message", logEntry.Message));
            list.Add(new SqlParameter("@StackTrace", logEntry.StackTrace.ToString().Replace(Environment.NewLine, @"\n")));
            list.Add(new SqlParameter("@Exception", logEntry.Exception.ToLogString()));
            list.Add(new SqlParameter("@Department", logEntry.Data["Department"]));
            list.Add(new SqlParameter("@Number", logEntry.Data["Number"]));
            list.Add(new SqlParameter("@Salary", logEntry.Data["Salary"]));
            list.Add(new SqlParameter("@HireDate", logEntry.Data["HireDate"]));

            var expected = list.ToArray();
            var actual = logEntry.ToSqlParameters();

            Assert.Equal(expected.Length, actual.Length);

            for (var i = 0; i < expected.Length; i++)
            {
                Assert.Equal(expected[i].ParameterName, actual[i].ParameterName);
                Assert.Equal(expected[i].Value, actual[i].Value);
            }
        }

        [Fact]
        public void ToXmlString_WithUseAttributesTrue_ShouldProduceValidXml()
        {
            var logEntry = new LogEntry();

            logEntry.LogEntryId = "102030405060708090";
            logEntry.Timestamp = new DateTime(2014, 11, 4, 13, 44, 55, 177);
            logEntry.Severity = LogLevel.Debug;
            logEntry.Source = "Some.Test.Source";
            logEntry.Message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";

            /*
            logEntry.StackTrace = new StackTrace();
            */

            /*
            try { throw new InvalidOperationException("You can't do that!"); }
            catch (Exception ex) { logEntry.Exception = ex; }
            */

            logEntry.Data.Add("Department", "Information Technology");
            logEntry.Data.Add("Number", 777);
            logEntry.Data.Add("Salary", 98765.43);
            logEntry.Data.Add("HireDate", new DateTime(2012, 6, 1));

            var expected = "<LogEntry LogEntryId=\"102030405060708090\" Timestamp=\"2014-11-04 13:44:55.177\" Severity=\"Debug\" Source=\"Some.Test.Source\" Message=\"Lorem ipsum dolor sit amet, consectetur adipiscing elit.\" StackTrace=\"\" Exception=\"\" Department=\"Information Technology\" Number=\"777\" Salary=\"98765.43\" HireDate=\"2012-06-01 00:00:00.000\" />";
            var actual = logEntry.ToXmlString(true);

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void ToXmlString_WithUseAttributesFalse_ShouldProduceValidXml()
        {
            var logEntry = new LogEntry();

            logEntry.LogEntryId = "102030405060708090";
            logEntry.Timestamp = new DateTime(2014, 11, 4, 13, 44, 55, 177);
            logEntry.Severity = LogLevel.Debug;
            logEntry.Source = "Some.Test.Source";
            logEntry.Message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";

            /*
            logEntry.StackTrace = new StackTrace();
            */

            /*
            try { throw new InvalidOperationException("You can't do that!"); }
            catch (Exception ex) { logEntry.Exception = ex; }
            */

            logEntry.Data.Add("Department", "Information Technology");
            logEntry.Data.Add("Number", 777);
            logEntry.Data.Add("Salary", 98765.43);
            logEntry.Data.Add("HireDate", new DateTime(2012, 6, 1));

            var expected =
@"<LogEntry>
  <LogEntryId>102030405060708090</LogEntryId>
  <Timestamp>2014-11-04 13:44:55.177</Timestamp>
  <Severity>Debug</Severity>
  <Source>Some.Test.Source</Source>
  <Message>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</Message>
  <StackTrace></StackTrace>
  <Exception></Exception>
  <Department>Information Technology</Department>
  <Number>777</Number>
  <Salary>98765.43</Salary>
  <HireDate>2012-06-01 00:00:00.000</HireDate>
</LogEntry>";
            var actual = logEntry.ToXmlString(false);

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void ToJsonString_WithFormattedTrue_ShouldProduceValidJson()
        {
            var logEntry = new LogEntry();

            logEntry.LogEntryId = "102030405060708090";
            logEntry.Timestamp = new DateTime(2014, 11, 4, 13, 44, 55, 177);
            logEntry.Severity = LogLevel.Debug;
            logEntry.Source = "Some.Test.Source";
            logEntry.Message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";

            /*
            logEntry.StackTrace = new StackTrace();
            */

            /*
            try { throw new InvalidOperationException("You can't do that!"); }
            catch (Exception ex) { logEntry.Exception = ex; }
            */

            logEntry.Data.Add("Department", "Information Technology");
            logEntry.Data.Add("Number", 777);
            logEntry.Data.Add("Salary", 98765.43);
            logEntry.Data.Add("HireDate", new DateTime(2012, 6, 1));

            var expected =
"{" + Environment.NewLine +
"  \"LogEntryId\": \"102030405060708090\"," + Environment.NewLine +
"  \"Timestamp\": \"2014-11-04T13:44:55.177\"," + Environment.NewLine +
"  \"Severity\": \"Debug\"," + Environment.NewLine +
"  \"Source\": \"Some.Test.Source\"," + Environment.NewLine +
"  \"Message\": \"Lorem ipsum dolor sit amet, consectetur adipiscing elit.\"," + Environment.NewLine +
"  \"StackTrace\": null," + Environment.NewLine +
"  \"Exception\": null," + Environment.NewLine +
"  \"Department\": \"Information Technology\"," + Environment.NewLine +
"  \"Number\": 777," + Environment.NewLine +
"  \"Salary\": 98765.43," + Environment.NewLine +
"  \"HireDate\": \"2012-06-01T00:00:00\"" + Environment.NewLine +
"}";
            var actual = logEntry.ToJsonString(true);

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void ToJsonString_WithFormattedFalse_ShouldProduceValidJson()
        {
            var logEntry = new LogEntry();

            logEntry.LogEntryId = "102030405060708090";
            logEntry.Timestamp = new DateTime(2014, 11, 4, 13, 44, 55, 177);
            logEntry.Severity = LogLevel.Debug;
            logEntry.Source = "Some.Test.Source";
            logEntry.Message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";

            /*
            logEntry.StackTrace = new StackTrace();
            */

            /*
            try { throw new InvalidOperationException("You can't do that!"); }
            catch (Exception ex) { logEntry.Exception = ex; }
            */

            logEntry.Data.Add("Department", "Information Technology");
            logEntry.Data.Add("Number", 777);
            logEntry.Data.Add("Salary", 98765.43);
            logEntry.Data.Add("HireDate", new DateTime(2012, 6, 1));

            var expected = "{\"LogEntryId\":\"102030405060708090\",\"Timestamp\":\"2014-11-04T13:44:55.177\",\"Severity\":\"Debug\",\"Source\":\"Some.Test.Source\",\"Message\":\"Lorem ipsum dolor sit amet, consectetur adipiscing elit.\",\"StackTrace\":null,\"Exception\":null,\"Department\":\"Information Technology\",\"Number\":777,\"Salary\":98765.43,\"HireDate\":\"2012-06-01T00:00:00\"}";
            var actual = logEntry.ToJsonString(false);

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void ToHttpParametersString_WithPropertiesSet_ShouldProduceValidParametersString()
        {
            var logEntry = new LogEntry();

            logEntry.LogEntryId = "102030405060708090";
            logEntry.Timestamp = new DateTime(2014, 11, 4, 13, 44, 55, 177);
            logEntry.Severity = LogLevel.Debug;
            logEntry.Source = "Some.Test.Source";
            logEntry.Message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";

            /*
            logEntry.StackTrace = new StackTrace();
            */

            /*
            try { throw new InvalidOperationException("You can't do that!"); }
            catch (Exception ex) { logEntry.Exception = ex; }
            */

            logEntry.Data.Add("Department", "Information Technology");
            logEntry.Data.Add("Number", 777);
            logEntry.Data.Add("Salary", 98765.43);
            logEntry.Data.Add("HireDate", new DateTime(2012, 6, 1));

            var expected = "LogEntryId=102030405060708090&Timestamp=2014-11-04+13%3A44%3A55.177&Severity=Debug&Source=Some.Test.Source&Message=Lorem+ipsum+dolor+sit+amet%2C+consectetur+adipiscing+elit.&StackTrace=&Exception=&Department=Information+Technology&Number=777&Salary=98765.43&HireDate=2012-06-01+00%3A00%3A00.000";
            var actual = logEntry.ToHttpParametersString();

            Assert.Equal(expected, actual);
        }
    }
}
