using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Xunit;

namespace LinqStudy.Test.LinqToObject
{
    /// <summary>
    /// 元素操作
    /// </summary>
    public class ElementTest
    {
        #region First
        /// <summary>
        /// First:获取第一个元素,延迟执行。
        /// </summary>
        [Fact]
        public void First_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
            };

            var queryFrist = peoples.First();
            var firstItemName = queryFrist.Name;

            Assert.Equal("wanggaofeng", firstItemName);
        }

        [Fact]
        public void First_where_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
                new Person(){ Id=3, Name="wangwu", Age=44},
            };

            var queryFrist = peoples.First(q => q.Age > 32);
            var firstItemName = queryFrist.Name;

            Assert.Equal("wanggaofeng", firstItemName);
        }

        [Fact]
        public void First_ArgumentNullException_Test()
        {
            List<Person> peoples = null;

            Action queryFirstAct = () => peoples.First();

            Assert.Throws<ArgumentNullException>(queryFirstAct);
        }

        /// <summary>
        /// 查不到数据时,异常。
        /// </summary>
        [Fact]
        public void First_InvalidOperationException_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
            };

            Action queryFrist =() => peoples.First(q => q.Age > 100);
            

            Assert.Throws<InvalidOperationException>(queryFrist);
        }
        #endregion

        #region FirstOrDefault
        /// <summary>
        /// FirstOrDefault:获取第一个元素或默认值,延迟执行。
        /// </summary>
        [Fact]
        public void FirstOrDefault_Frist()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
            };

            var queryFrist = peoples.FirstOrDefault();
            var firstItemName = queryFrist.Name;

            Assert.Equal("wanggaofeng", firstItemName);
        }

        [Fact]
        public void FirstOrDefault_Default()
        {
            List<Person> peoples = new List<Person>();

            var queryFrist = peoples.FirstOrDefault();
            var firstItem = queryFrist;

            Assert.Null(firstItem);
        }

        [Fact]
        public void FirstOrDefault_Where_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
                new Person(){ Id=3, Name="wangwu", Age=44},
            };

            var queryFrist = peoples.FirstOrDefault(q => q.Age > 32);
            var firstItemName = queryFrist.Name;

            Assert.Equal("wanggaofeng", firstItemName);
        }

        [Fact]
        public void FirstOrDefault_ArgumentNullException_Test()
        {
            List<Person> peoples = null;

            Action queryFirstAct = () => peoples.First();

            Assert.Throws<ArgumentNullException>(queryFirstAct);
        }

        /// <summary>
        /// 查不到数据时,不异常。
        /// </summary>
        [Fact]
        public void FirstOrDefault_No_InvalidOperationException()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
            };

            var defaultItem = peoples.FirstOrDefault(q => q.Age > 100);

            Assert.Null(defaultItem);
        }
        #endregion

        #region Last
        /// <summary>
        /// First:获取最后一个元素,延迟执行。
        /// </summary>
        [Fact]
        public void Last_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
            };

            var lastItem = peoples.Last();
            var lastItemName = lastItem.Name;

            Assert.Equal("lishi", lastItemName);
        }

        [Fact]
        public void Last_where_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
                new Person(){ Id=3, Name="wangwu", Age=44},
            };

            var lastItem = peoples.Last(q => q.Age > 32);
            var lastItemName = lastItem.Name;

            Assert.Equal("wangwu", lastItemName);
        }

        [Fact]
        public void Last_ArgumentNullException_Test()
        {
            List<Person> peoples = null;

            Action queryAction = () => peoples.First();

            Assert.Throws<ArgumentNullException>(queryAction);
        }

        /// <summary>
        /// 查不到数据时,异常。
        /// </summary>
        [Fact]
        public void Last_InvalidOperationException_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
            };

            Action lastAction = () => peoples.Last(q => q.Age > 100);

            Assert.Throws<InvalidOperationException>(lastAction);
        }
        #endregion

        #region LastOrDefault
        /// <summary>
        /// LastOrDefault:获取最后一个元素或默认值,延迟执行。
        /// </summary>
        [Fact]
        public void LastOrDefault_Last()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
            };

            var queryItem = peoples.LastOrDefault();
            var lastItemName = queryItem.Name;

            Assert.Equal("lishi", lastItemName);
        }

        [Fact]
        public void LastOrDefault_Default()
        {
            List<Person> peoples = new List<Person>();

            var queryItem = peoples.LastOrDefault();

            Assert.Null(queryItem);
        }

        [Fact]
        public void LastOrDefault_Where_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
                new Person(){ Id=3, Name="wangwu", Age=44},
            };

            var queryItem = peoples.LastOrDefault(q => q.Age > 32);
            var lastItemName = queryItem.Name;

            Assert.Equal("wangwu", lastItemName);
        }

        [Fact]
        public void LastOrDefault_ArgumentNullException_Test()
        {
            List<Person> peoples = null;

            Action queryLastItme = () => peoples.LastOrDefault();

            Assert.Throws<ArgumentNullException>(queryLastItme);
        }

        /// <summary>
        /// 查不到数据时,不异常。
        /// </summary>
        [Fact]
        public void LastOrDefault_No_InvalidOperationException()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
            };

            var defaultItem = peoples.LastOrDefault(q => q.Age > 100);

            Assert.Null(defaultItem);
        }
        #endregion

        #region Single
        /// <summary>
        /// Single:获取单个元素,延迟执行。
        /// </summary>
        [Fact]
        public void Single_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33}
            };

            var queryItem = peoples.Single();
            var singleName = queryItem.Name;

            Assert.Equal("wanggaofeng", singleName);
        }

        [Fact]
        public void Single_where_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
                new Person(){ Id=3, Name="wangwu", Age=44},
            };

            var singleQuery = peoples.Single(q => q.Age > 33);
            var singleItemName = singleQuery.Name;

            Assert.Equal("wangwu", singleItemName);
        }

        [Fact]
        public void Single_ArgumentNullException_Test()
        {
            List<Person> peoples = null;

            Action singleQueryAction = () => peoples.Single();

            Assert.Throws<ArgumentNullException>(singleQueryAction);
        }

        /// <summary>
        /// 查不到数据时,异常。
        /// </summary>
        [Fact]
        public void Single_QueryEmpty_InvalidOperationException()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
            };

            Action singleQueryAction = () => peoples.Single(q => q.Age > 100);


            Assert.Throws<InvalidOperationException>(singleQueryAction);
        }

        /// <summary>
        /// 查询到多条记录,异常
        /// </summary>
        [Fact]
        public void Single_QueryManyItem_InvalidOperationException()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
            };

            Action singleQueryAction = () => peoples.Single(q => q.Age > 0);


            Assert.Throws<InvalidOperationException>(singleQueryAction);
        }
        #endregion

        #region SingleOrDefault
        /// <summary>
        /// SingleOrDefault:获取单个元素或默认值,延迟执行。
        /// </summary>
        [Fact]
        public void SingleOrDefault_Last()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33}
            };

            var queryItem = peoples.SingleOrDefault();
            var singleItemName = queryItem.Name;

            Assert.Equal("wanggaofeng", singleItemName);
        }

        [Fact]
        public void SingleOrDefault_Default()
        {
            List<Person> peoples = new List<Person>();

            var queryItem = peoples.SingleOrDefault();

            Assert.Null(queryItem);
        }

        [Fact]
        public void SingleOrDefault_Where_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
                new Person(){ Id=3, Name="wangwu", Age=44},
            };

            var queryItem = peoples.SingleOrDefault(q => q.Id > 2);
            var sigleItemName = queryItem.Name;

            Assert.Equal("wangwu", sigleItemName);
        }

        [Fact]
        public void SingleOrDefault_ArgumentNullException()
        {
            List<Person> peoples = null;

            Action queryAction = () => peoples.LastOrDefault();

            Assert.Throws<ArgumentNullException>(queryAction);
        }

        /// <summary>
        /// 查询不到数据,不异常
        /// </summary>
        [Fact]
        public void SingleOrDefault_QueryEmpty_NoArgumentNullException()
        {
            List<Person> peoples = new List<Person>();

            var queryItme = peoples.SingleOrDefault();

            Assert.Null(queryItme);
        }

        /// <summary>
        /// 查到多条数据时,异常。
        /// </summary>
        [Fact]
        public void SingleOrDefault_No_InvalidOperationException()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
            };

            Action singleOrDefalutAction =() => peoples.SingleOrDefault(q => q.Age > 0);

            Assert.Throws<InvalidOperationException>(singleOrDefalutAction);
        }
        #endregion

        #region ElementAt

        /// <summary>
        /// ElementAt:返回集合中给定索引(索引从0开始)处的元素,延迟执行。
        /// </summary>
        [Fact]
        public void ElementAt_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
                new Person(){ Id=3, Name="wangwu", Age=44},
            };

            var queryItem = peoples.ElementAt(0);
            var queryItemName = queryItem.Name;

            Assert.Equal("wanggaofeng", queryItemName);
        }

        /// <summary>
        /// ArgumentNullException异常:数据源为Null时,引发。
        /// </summary>
        [Fact]
        public void ElementAt_ArgumentNullException_Test()
        {
            List<Person> peoples = null;

            Action queryAction = () => peoples.ElementAt(0);

            Assert.Throws<ArgumentNullException>(queryAction);
        }

        /// <summary>
        /// ArgumentOutOfRangeException异常:指定索引超出序列范围时,引发。
        /// </summary>
        [Fact]
        public void ElementAt_ArgumentOutOfRangeException_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33},
                new Person(){ Id=2, Name="lishi", Age=32},
                new Person(){ Id=3, Name="wangwu", Age=44},
            };

            Action queryAction = () => peoples.ElementAt(100);

            Assert.Throws<ArgumentOutOfRangeException>(queryAction);
        }
        #endregion

        #region ElementAtOrDefault
        /// <summary>
        /// ElementAtOrDefault:获取指定索引处的元素或如果超出索引范围时返回默认项;延迟执行。
        /// </summary>
        [Fact]
        public void ElementAtOrDefault_ElementAt()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id=1, Name="wanggaofeng", Age=33}
            };

            var queryItem = peoples.ElementAtOrDefault(0);
            var queryItemName = queryItem.Name;

            Assert.Equal("wanggaofeng", queryItemName);
        }

        /// <summary>
        /// 超出索引范围,返回默认项。
        /// 注意:引用和可空类型,返回null
        /// </summary>
        [Fact]
        public void ElementAtOrDefault_Default()
        {
            List<Person> peoples = new List<Person>() { };

            var queryItem = peoples.ElementAtOrDefault(2);

            Assert.Null(queryItem);
        }

        [Fact]
        public void ElementAtOrDefault_ArgumentNullException()
        {
            List<Person> peoples = null;

            Action queryAction = () => peoples.ElementAtOrDefault(0);

            Assert.Throws<ArgumentNullException>(queryAction);
        }

        /// <summary>
        /// 查询不到数据,不异常
        /// </summary>
        [Fact]
        public void ElementAtOrDefault_QueryEmpty_NoArgumentNullException()
        {
            List<Person> peoples = new List<Person>();

            var queryItme = peoples.ElementAtOrDefault(5);

            Assert.Null(queryItme);
        }
        #endregion
    }
}