using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions.TestingHelpers;
using Moq;
using NUnit.Framework;

namespace c24.Deputy.Checks
{
    public class SolutionIntegrityCheck_Tests
    {
        public class Given_a_project_with_a_reference_which_does_not_exist_in_solution
        {
            private readonly ProjectReference reference;
            private readonly SolutionIntegrityCheck check;

            public Given_a_project_with_a_reference_which_does_not_exist_in_solution()
            {
                var projectsInSolution = new[] { ProjectReferenceTestSample.ReferenceFromSolutionToProjectWithReferences };
                
                var parserMock = new Mock<IProjectParser>();
                parserMock
                    .Setup(p => p.ParseProjectReferences(ProjectReferenceTestSample.ReferenceFromSolutionToProjectWithReferences.FullPath))
                    .Returns(new[] { ProjectReferenceTestSample.ReferenceFromProjectToAProjectWithSameName });

                var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
                {
                    {Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "testB.csproj")), new MockFileData(String.Empty)}
                });

                this.reference = ProjectReferenceTestSample.ReferenceFromSolutionToProjectWithReferences;
                this.check = new SolutionIntegrityCheck(fileSystem, projectsInSolution, parserMock.Object);
            }

            [Test]
            public void Then_should_not_be_satisfied()
            {
                Assert.IsFalse(this.check.IsSatisfiedBy(this.reference));
            }

            [Test]
            public void Then_should_report_error()
            {
                var report = this.check.Report(this.reference);
                Assert.AreEqual(ReportSeverity.Error, report.Message.Severity);
            }

            [Test]
            public void Then_should_report_from_project_reference_check()
            {
                var report = this.check.Report(this.reference);
                Assert.AreEqual("ContainsReferencedProjectsCheck", report.Source);
            }
        }

        public class Given_a_reference_with_path_which_does_not_exist
        {
            private readonly ProjectReference reference;
            private readonly SolutionIntegrityCheck check;

            public Given_a_reference_with_path_which_does_not_exist()
            {
                this.reference = new ProjectReference
                {
                    Name = "what", 
                    Path = "what.csproj",
                    Referrer = "project",
                    SourceType = ReferenceSourceType.Project
                };

                this.check = new SolutionIntegrityCheck(
                    new MockFileSystem(new Dictionary<string, MockFileData>
                    {
                        { "any.csproj", new MockFileData(String.Empty) }
                    }), new ProjectReference[0], Mock.Of<IProjectParser>());
            }

            [Test]
            public void Then_should_not_be_satisfied()
            {
                Assert.IsFalse(this.check.IsSatisfiedBy(this.reference));
            }

            [Test]
            public void Then_should_report_error()
            {
                var report = this.check.Report(this.reference);
                Assert.AreEqual(ReportSeverity.Error, report.Message.Severity);
            }

            [Test]
            public void Then_should_report_from_exists_check()
            {
                var report = this.check.Report(this.reference);
                Assert.AreEqual("ExistsReferenceCheck", report.Source);
            }
        }
    }
}