#region License
// Copyright (c) 2004 Choy Rim. All rights reserved.
#endregion
#region Imports
using System;
using System.Collections;
using System.Reflection;
using DotNetMock.Core;
using NUnit.Framework;

using DotNetMock.TestFramework;
#endregion

namespace DotNetMock.TestFramework.Tests
{
	[TestFixture]
	public class ImplementationFactoryTests 
	{
		const string EXPECTED_STATIC_ASSEMBLY_NAME = "Assembly";
		static readonly string EXPECTED_STATIC_TYPE_NAME = typeof(TestStaticImplementation).FullName;

		MockLinker linker;
		TestStaticImplementation implementation;
		Hashtable env;

		[Test] public void UseStaticImplementation() 
		{
			linker.ExpectedAssemblyName = EXPECTED_STATIC_ASSEMBLY_NAME;
			linker.ExpectedAssembly = Assembly.GetExecutingAssembly();
			linker.ExpectedType = typeof(TestStaticImplementation);

			env["DotNetMock_TestingAssembly"] = EXPECTED_STATIC_ASSEMBLY_NAME;
			env["DotNetMock_TestingComponent"] = EXPECTED_STATIC_TYPE_NAME;

			ImplementationFactory factory = new ImplementationFactory(env, linker);
			ITestFramework tf = factory.NewImplementation();
			Assert.IsNotNull(tf);
			Assert.AreSame(implementation, tf);

			Assert.AreEqual(1, linker.ActualAssemblyNames.Count);
			Assert.AreEqual("Assembly", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual(EXPECTED_STATIC_TYPE_NAME, linker.ActualTypeName);
			Assert.AreSame(Assembly.GetExecutingAssembly(), linker.ActualAssembly);
			Assert.AreEqual(typeof(TestStaticImplementation), linker.ActualType);
		}
		[Test] public void UseDynamicNUnitImplementation() 
		{
			linker.ExpectedAssemblyName = "nunit.framework";
			linker.ExpectedAssembly = typeof(Assertion).Module.Assembly;
			linker.ExpectedType = typeof(Assertion);

			ImplementationFactory factory = new ImplementationFactory(env, linker);
			ITestFramework tf = factory.NewImplementation();
			Assert.IsNotNull(tf);
			Assert.AreSame(implementation, tf);

			Assert.AreEqual(1, linker.ActualAssemblyNames.Count);
			Assert.AreEqual("nunit.framework", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("NUnit.Framework.Assertion", linker.ActualTypeName);
			Assert.AreSame(typeof(Assertion).Module.Assembly, linker.ActualAssembly);
			Assert.AreEqual("ProviderStub", linker.ActualType.FullName);
		}
		[Test] public void UseDynamicMbUnitImplementation() 
		{
			linker.ExpectedAssemblyName = "MbUnit.Core";
			linker.ExpectedAssembly = Assembly.GetExecutingAssembly();
			linker.ExpectedType = typeof(MbUnit.Core.Framework.Assert);

			ImplementationFactory factory = new ImplementationFactory(env, linker);
			ITestFramework tf = factory.NewImplementation();
			Assert.IsNotNull(tf);
			Assert.AreSame(implementation, tf);

			Assert.AreEqual(2, linker.ActualAssemblyNames.Count);
			Assert.AreEqual("MbUnit.Core", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("nunit.framework", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("MbUnit.Core.Framework.Assert", linker.ActualTypeName);
			Assert.AreSame(Assembly.GetExecutingAssembly(), linker.ActualAssembly);
			Assert.AreEqual("ProviderStub", linker.ActualType.FullName);
		}
		[Test] public void UseDynamicCsUnitImplementation() 
		{
			linker.ExpectedAssemblyName = "csUnit";
			linker.ExpectedAssembly = Assembly.GetExecutingAssembly();
			linker.ExpectedType = typeof(csUnit.Assert);

			ImplementationFactory factory = new ImplementationFactory(env, linker);
			ITestFramework tf = factory.NewImplementation();
			Assert.IsNotNull(tf);
			Assert.AreSame(implementation, tf);

			Assert.AreEqual(3, linker.ActualAssemblyNames.Count);
			Assert.AreEqual("csUnit", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("MbUnit.Core", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("nunit.framework", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("csUnit.Assert", linker.ActualTypeName);
			Assert.AreSame(Assembly.GetExecutingAssembly(), linker.ActualAssembly);
			Assert.AreEqual("ProviderStub", linker.ActualType.FullName);
		}
		[Test] public void UseDynamicNUnitImplementationViaPartialName() 
		{
			linker.ExpectedAssemblyName = "xxx";
			linker.ExpectedPartialAssemblyName = "nunit.framework";
			linker.ExpectedAssembly = typeof(Assertion).Module.Assembly;
			linker.ExpectedType = typeof(Assertion);

			ImplementationFactory factory = new ImplementationFactory(env, linker);
			ITestFramework tf = factory.NewImplementation();
			Assert.IsNotNull(tf);
			Assert.AreSame(implementation, tf);

			Assert.AreEqual(4, linker.ActualAssemblyNames.Count);
			Assert.AreEqual("nunit.framework", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("csUnit", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("MbUnit.Core", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("nunit.framework", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("NUnit.Framework.Assertion", linker.ActualTypeName);
			Assert.AreSame(typeof(Assertion).Module.Assembly, linker.ActualAssembly);
			Assert.AreEqual("ProviderStub", linker.ActualType.FullName);
		}
		[Test] public void UseDynamicMbUnitImplementationViaPartialName() 
		{
			linker.ExpectedAssemblyName = "xxx";
			linker.ExpectedPartialAssemblyName = "MbUnit.Core";
			linker.ExpectedAssembly = Assembly.GetExecutingAssembly();
			linker.ExpectedType = typeof(MbUnit.Core.Framework.Assert);

			ImplementationFactory factory = new ImplementationFactory(env, linker);
			ITestFramework tf = factory.NewImplementation();
			Assert.IsNotNull(tf);
			Assert.AreSame(implementation, tf);

			Assert.AreEqual(5, linker.ActualAssemblyNames.Count);
			Assert.AreEqual("MbUnit.Core", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("nunit.framework", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("csUnit", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("MbUnit.Core", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("nunit.framework", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("MbUnit.Core.Framework.Assert", linker.ActualTypeName);
			Assert.AreSame(Assembly.GetExecutingAssembly(), linker.ActualAssembly);
			Assert.AreEqual("ProviderStub", linker.ActualType.FullName);
		}
		[Test] public void UseDynamicCsUnitImplementationViaPartialName() 
		{
			linker.ExpectedAssemblyName = "xxx";
			linker.ExpectedPartialAssemblyName = "csUnit";
			linker.ExpectedAssembly = Assembly.GetExecutingAssembly();
			linker.ExpectedType = typeof(csUnit.Assert);

			ImplementationFactory factory = new ImplementationFactory(env, linker);
			ITestFramework tf = factory.NewImplementation();
			Assert.IsNotNull(tf);
			Assert.AreSame(implementation, tf);

			Assert.AreEqual(6, linker.ActualAssemblyNames.Count);
			Assert.AreEqual("csUnit", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("MbUnit.Core", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("nunit.framework", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("csUnit", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("MbUnit.Core", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("nunit.framework", linker.ActualAssemblyNames.Pop());
			Assert.AreEqual("csUnit.Assert", linker.ActualTypeName);
			Assert.AreSame(Assembly.GetExecutingAssembly(), linker.ActualAssembly);
			Assert.AreEqual("ProviderStub", linker.ActualType.FullName);
		}
		[SetUp]
		public void BeforeEachTest() 
		{
			linker = new MockLinker();
			implementation = new TestStaticImplementation();
			env = new Hashtable();

			linker.ExpectedInstance = implementation;
		}

		public class TestStaticImplementation : ITestFramework
		{
			#region ITestFramework Members

			public void Assert(bool assertion)
			{
				// TODO:  Add TestStaticImplementation.Assert implementation
			}

			void DotNetMock.Core.ITestFramework.Assert(string message, bool assertion)
			{
				// TODO:  Add TestStaticImplementation.DotNetMock.Core.ITestFramework.Assert implementation
			}

			public void AssertNotNull(object assertion)
			{
				// TODO:  Add TestStaticImplementation.AssertNotNull implementation
			}

			void DotNetMock.Core.ITestFramework.AssertNotNull(string message, object assertion)
			{
				// TODO:  Add TestStaticImplementation.DotNetMock.Core.ITestFramework.AssertNotNull implementation
			}

			public void AssertEquals(object expectedObject, object actualObject)
			{
				// TODO:  Add TestStaticImplementation.AssertEquals implementation
			}

			void DotNetMock.Core.ITestFramework.AssertEquals(string message, object expectedObject, object actualObject)
			{
				// TODO:  Add TestStaticImplementation.DotNetMock.Core.ITestFramework.AssertEquals implementation
			}

			public void Fail(string message)
			{
				// TODO:  Add TestStaticImplementation.Fail implementation
			}

			void DotNetMock.Core.ITestFramework.Fail()
			{
				// TODO:  Add TestStaticImplementation.DotNetMock.Core.ITestFramework.Fail implementation
			}

			public void AssertNull(object assertion)
			{
				// TODO:  Add TestStaticImplementation.AssertNull implementation
			}

			void DotNetMock.Core.ITestFramework.AssertNull(string message, object assertion)
			{
				// TODO:  Add TestStaticImplementation.DotNetMock.Core.ITestFramework.AssertNull implementation
			}

			#endregion
		}

		class MockLinker :
			IDynamicLinker
		{
			public Stack ActualAssemblyNames = new Stack();
			public string ExpectedAssemblyName = null;
			public string ExpectedPartialAssemblyName = null;
			public Assembly ExpectedAssembly = null;
			public string ActualTypeName = null;
			public Assembly ActualAssembly = null;
			public Type ExpectedType = null;
			public Type ActualType = null;
			public object ExpectedInstance = null;

			#region IDynamicLinker Members

			public Assembly LoadAssembly(string name)
			{
				ActualAssemblyNames.Push(name);
				if ( name!=ExpectedAssemblyName ) 
				{
					return null;
				}
				return ExpectedAssembly;
			}
			public Assembly LoadAssemblyWithPartialName(string name)
			{
				ActualAssemblyNames.Push(name);
				if ( name!=ExpectedPartialAssemblyName ) 
				{
					return null;
				}
				return ExpectedAssembly;
			}
			public Type GetType(string typeName, Assembly assembly) 
			{
				ActualTypeName = typeName;
				ActualAssembly = assembly;
				return ExpectedType;
			}
			public object CreateInstance(Type type)
			{
				ActualType = type;
				return ExpectedInstance;
			}

			#endregion
		}
	}
}
