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

using Xunit;
using FluentAssertions;

namespace LinqStudy.Test.LinqToObject
{
    /// <summary>
    /// 生成操作符
    /// </summary>
    public class CreateTest
    {
        /// <summary>
        ///  Empty 返回指定类型的空集,没有任何元素的集合。
        ///  Enumerable的静态方法,常用来做初始种子集合。
        /// </summary>
        [Fact]
        public void Empty_string_Test()
        {
           var ini= Enumerable.Empty<string>();

           Assert.IsType<string[]>(ini);
           Assert.Empty(ini);
        }

        /// <summary>
        /// 注意:返回值为Enumerable<T>,而不是List<T> 
        /// </summary>
        [Fact]
        public void Empty_Class_Test()
        {
            var ini = Enumerable.Empty<Person>();

            Assert.IsType<Person[]>(ini);
            Assert.Empty(ini);
        }

        /// <summary>
        ///  DefaultIfEmpty
        ///  如果数据源没有项,就添加一项,项的值为类型默认值
        /// </summary>
        [Fact]
        public void DefaultIfEmpty_Test()
        {
            var defaultValue= Enumerable.DefaultIfEmpty(Enumerable.Empty<int>());

            Assert.Single(defaultValue);
            Assert.Equal(default(int), defaultValue.First());
        }
        /// <summary>
        /// 数据源为Null时,抛出异常。
        /// </summary>
        [Fact]
        public void DefaultIfEmpty_Class_Test()
        {
            var defaultValue = Enumerable.DefaultIfEmpty(Enumerable.Empty<Person>());

            Assert.Single(defaultValue);
            Assert.Equal(default(Person), defaultValue.First());
        }

        /// <summary>
        /// Range:生成指定范围的整数序列
        /// </summary>
        [Fact]
        public void Range_Test()
        {
            //生成1-100整数序列
            var values = Enumerable.Range(1, 100);

            Assert.Equal(100, values.Count());
            Assert.Equal(1, values.ElementAt(0));
        }

        /// <summary>
        /// Repeat:重复填充序列
        /// 先生成一项,使用浅拷贝技术,重复填充其它项。
        /// 如果是引用对象,所有序列均是对同一对象的引用。
        /// </summary>
        [Fact]
        public void Repeat_Test()
        {
            //生成100项值均为"test@163.com"的字符串序列
            var values = Enumerable.Repeat("test@163.com", 100);

            Array.ForEach(values.ToArray(), (emai) => {
                Assert.Equal("test@163.com", emai);
            });
        }

        /// <summary>
        /// 注意:对象只生成一个,其它使用浅拷贝进行填充,值一样!
        /// </summary>
        [Fact]
        public void Repeat_TestData_Test()
        {
            //生成测试数据:生成了有100项的一个序列,这100项均是对同一个对象的引用,而不是100个对象。

            Random rdm = new Random(DateTime.Now.Ticks.GetHashCode());
            //虽然生成时,用了随机数,但是因对象只生成了一次,其它均是这个对象的浅拷贝,所以100个对象,完全相同:100个对同一对象的引用。
            var persons = Enumerable.Repeat(new Person()
            {
                Id = DateTime.Now.Millisecond,
                Name = "王小明",
                Age = rdm.Next(1, 100)
            }, 100).ToList();

            Assert.Equal(100, persons.Count);

            //所有对象引用相同
            Assert.All(persons, (p) => 
            {
                Assert.Same(persons[0], p);
            });
        }

        /// <summary>
        ///  SequenceEqual: 比较源和目标序列,返回一个bool值,指示所含元素是否相同。
        /// </summary>
        [Fact]
        public void SequenceEqual_Test()
        {
            Person p=new Person(){Id=1,Name="王小明",Age=20};

            var s1=Enumerable.Repeat(p,100);

            var s2=Enumerable.Repeat(p,100);

            Assert.True(s1.SequenceEqual(s2));
        }

        [Fact]
        public void SequenceEqual_No_Test()
        {
            Person p=new Person(){Id=1,Name="王小明",Age=20};

            var s1=Enumerable.Repeat(p,100);

            var s2=Enumerable.Repeat(p,200);

            Assert.False(s1.SequenceEqual(s2));
        }
    }
}