#if NET_3_0
#region License

/*
 * Copyright © 2002-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#endregion

#region Imports

using System;
using System.IO;
using System.Text;
using System.Reflection;
using System.Net.Security;
using System.ServiceModel;

using NUnit.Framework;
using Spring.Objects.Factory.Config;
using Spring.ServiceModel;
using Spring.Core.IO;
using Spring.Objects.Factory;
using Spring.Objects.Factory.Xml;

#endregion

namespace Spring.ServiceModel
{
    /// <summary>
    /// Unit tests for the ServiceExporter class.
    /// </summary>
    /// <author>Bruno Baia</author>
    [TestFixture]
    public sealed class ServiceExporterTests
    {
        ServiceExporter se = null;

        [SetUp]
        public void SetUp()
        {
            const string xml =
    @"<?xml version='1.0' encoding='UTF-8' ?>
<objects xmlns='http://www.springframework.net'>
	<object id='service' type='Spring.ServiceModel.ServiceExporterTests+Service, Spring.Services.Tests'/>
	<object id='serviceWithMultipleInterfaces' type='Spring.ServiceModel.ServiceExporterTests+ServiceWithMultipleInterfaces, Spring.Services.Tests'/>
    <object id='decoratedService' type='Spring.ServiceModel.ServiceExporterTests+DecoratedService, Spring.Services.Tests'/>
</objects>";
            Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(xml));
            IObjectFactory objectFactory = new XmlObjectFactory(new InputStreamResource(stream, string.Empty));

            se = new ServiceExporter();
            se.ObjectFactory = objectFactory;
        }

        [Test]
        [ExpectedException(typeof(ArgumentException), ExpectedMessage = "The TargetName property is required.")]
        public void NullConfig()
        {
            se.ObjectName = "NullConfig";
            se.AfterPropertiesSet();
        }

        [Test]
        public void ProxiesContractInterface()
        {
            se.ObjectName = "ProxiesContractInterface";
            se.TargetName = "service";
            se.AfterPropertiesSet();

            Type proxyType = se.GetObject() as Type;
            Assert.IsNotNull(proxyType);
            Assert.IsTrue(typeof(IContract).IsAssignableFrom(proxyType));
        }

        [Test(Description = "http://jira.springframework.org/browse/SPRNET-1179")]
        public void ProxiesOnlyContractInterface()
        {
            se.ObjectName = "ProxiesOnlyContractInterface";
            se.TargetName = "serviceWithMultipleInterfaces";
            se.ContractInterface = typeof(IContract);
            se.AfterPropertiesSet();

            Type proxyType = se.GetObject() as Type;
            Assert.IsNotNull(proxyType);
            Assert.IsTrue(typeof(IContract).IsAssignableFrom(proxyType));
        }

        [Test(Description = "http://jira.springframework.org/browse/SPRNET-1179")]
        [ExpectedException(typeof(ArgumentException), ExpectedMessage = "ServiceExporter cannot export service type 'Spring.ServiceModel.ServiceExporterTests+ServiceWithMultipleInterfaces' as a WCF service because it implements multiple interfaces. Specify the contract interface to expose via the ContractInterface property.")]
        public void ProxiesOnlyContractInterfaceFailsIfNoContractInterface()
        {
            se.ObjectName = "ProxiesOnlyContractInterface";
            se.TargetName = "serviceWithMultipleInterfaces";
            // se.ContractInterface = typeof (IContract);
            se.AfterPropertiesSet();
        }

        [Test]
        public void ProxyTypeEqualsObjectName()
        {
            se.ObjectName = "ProxyTypeEqualsObjectName";
            se.TargetName = "service";
            se.AfterPropertiesSet();

            Type proxyType = se.GetObject() as Type;
            Assert.IsNotNull(proxyType);
            Assert.AreEqual("ProxyTypeEqualsObjectName", proxyType.FullName);
        }

        [Test]
        public void CreatesServiceContractAttributeWithNoDecoratedClassAndMinimalConfig()
        {
            se.ObjectName = "CreatesServiceContractAttributeWithNoDecoratedClassAndMinimalConfig";
            se.TargetName = "service";
            se.AfterPropertiesSet();

            Type proxyType = se.GetObject() as Type;
            Assert.IsNotNull(proxyType);
            object[] attrs = proxyType.GetCustomAttributes(typeof(ServiceContractAttribute), true);
            Assert.IsNotEmpty(attrs);
            Assert.AreEqual(1, attrs.Length);

            ServiceContractAttribute sca = attrs[0] as ServiceContractAttribute;
            Assert.IsNull(sca.CallbackContract);
            Assert.AreEqual(typeof(IContract).FullName, sca.ConfigurationName);
            Assert.AreEqual(typeof(IContract).Name, sca.Name);
            Assert.IsNull(sca.Namespace);
            Assert.AreEqual(ProtectionLevel.None, sca.ProtectionLevel);
            Assert.AreEqual(SessionMode.Allowed, sca.SessionMode);
        }

        [Test]
        public void CreatesServiceContractAttributeWithNoDecoratedClassAndFullConfig()
        {
            se.ObjectName = "CreatesServiceContractAttributeWithNoDecoratedClassAndFullConfig";
            se.TargetName = "service";
            se.CallbackContract = typeof(IDisposable);
            se.ConfigurationName = "CustomConfigName";
            se.Name = "serviceName";
            se.Namespace = "http://Spring.Services.Tests";
            se.ProtectionLevel = ProtectionLevel.Sign;
            se.SessionMode = SessionMode.Required;

            se.AfterPropertiesSet();

            Type proxyType = se.GetObject() as Type;
            Assert.IsNotNull(proxyType);
            object[] attrs = proxyType.GetCustomAttributes(typeof(ServiceContractAttribute), true);
            Assert.IsNotEmpty(attrs);
            Assert.AreEqual(1, attrs.Length);

            ServiceContractAttribute sca = attrs[0] as ServiceContractAttribute;
            Assert.AreEqual(se.CallbackContract, sca.CallbackContract);
            Assert.AreEqual(se.ConfigurationName, sca.ConfigurationName);
            Assert.AreEqual(se.Name, sca.Name);
            Assert.AreEqual(se.Namespace, sca.Namespace);
            Assert.AreEqual(se.ProtectionLevel, sca.ProtectionLevel);
            Assert.AreEqual(se.SessionMode, sca.SessionMode);
        }

        [Test]
        public void CreatesDefaultOperationContractAttributeWithNoDecoratedMethod()
        {
            se.ObjectName = "CreatesDefaultOperationContractAttributeWithNoDecoratedMethod";
            se.TargetName = "service";
            se.AfterPropertiesSet();

            Type proxyType = se.GetObject() as Type;
            Assert.IsNotNull(proxyType);
            MethodInfo method = proxyType.GetMethod("SomeMethod");
            Assert.IsNotNull(method);

            object[] attrs = method.GetCustomAttributes(typeof(OperationContractAttribute), true);
            Assert.IsNotEmpty(attrs);
            Assert.AreEqual(1, attrs.Length);
        }

        [Test]
        public void CreatesCustomOperationContractAttributeWithNoDecoratedMethod()
        {
            OperationContractAttribute oca1 = new OperationContractAttribute();
            oca1.Name = "MySomeMethod";

            se.ObjectName = "CreatesCustomOperationContractAttributeWithNoDecoratedMethod";
            se.TargetName = "service";
            se.MemberAttributes.Add("SomeMethod", oca1);
            se.AfterPropertiesSet();

            Type proxyType = se.GetObject() as Type;
            Assert.IsNotNull(proxyType);
            MethodInfo method = proxyType.GetMethod("SomeMethod");
            Assert.IsNotNull(method);

            object[] attrs = method.GetCustomAttributes(typeof(OperationContractAttribute), true);
            Assert.IsNotEmpty(attrs);
            Assert.AreEqual(1, attrs.Length);

            OperationContractAttribute oca2 = attrs[0] as OperationContractAttribute;
            Assert.AreEqual(oca1.Name, oca2.Name);
        }

        [Test]
        public void OverridesExistingServiceContractAttributeWithDecoratedClass()
        {
            se.ObjectName = "OverridesExistingServiceContractAttributeWithDecoratedClass";
            se.TargetName = "decoratedService";
            se.AfterPropertiesSet();

            Type proxyType = se.GetObject() as Type;
            Assert.IsNotNull(proxyType);
            object[] attrs = proxyType.GetCustomAttributes(typeof(ServiceContractAttribute), true);
            Assert.IsNotEmpty(attrs);
            Assert.AreEqual(1, attrs.Length);

            ServiceContractAttribute sca = attrs[0] as ServiceContractAttribute;
            Assert.IsNull(sca.Namespace);
        }

        [Test]
        public void UsesExistingOperationContractAttributeWithDecoratedMethod()
        {
            se.ObjectName = "UsesExistingOperationContractAttributeWithDecoratedMethod";
            se.TargetName = "decoratedService";
            se.AfterPropertiesSet();

            Type proxyType = se.GetObject() as Type;
            Assert.IsNotNull(proxyType);
            MethodInfo method = proxyType.GetMethod("SomeMethod");
            Assert.IsNotNull(method);

            object[] attrs = method.GetCustomAttributes(typeof(OperationContractAttribute), true);
            Assert.IsNotEmpty(attrs);
            Assert.AreEqual(1, attrs.Length);

            OperationContractAttribute oca = attrs[0] as OperationContractAttribute;
            Assert.AreEqual("MySomeMethod", oca.Name);
        }

        #region Test classes

        public interface IContract
        {
            string SomeMethod(int param);
        }

        public interface IOtherContract
        { }

        public class Service : IContract
        {
            public string SomeMethod(int param)
            {
                return param.ToString();
            }
        }

        public class ServiceWithMultipleInterfaces : Service, IOtherContract
        {
        }

        [ServiceContract(Namespace = "http://Spring.Services.Tests")]
        public class DecoratedService : IContract
        {
            [OperationContract(Name = "MySomeMethod")]
            public string SomeMethod(int param)
            {
                return param.ToString();
            }
        }

        //[ServiceContract(Namespace = "http://Spring.Services.Tests")]
        //public interface IDecoratedContract
        //{
        //    [OperationContract]
        //    string SomeMethod(int param);
        //}

        //public class AnotherService : IDecoratedContract
        //{
        //    public string SomeMethod(int param)
        //    {
        //        return param.ToString();
        //    }
        //}

        #endregion

    }
}
#endif