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

using Xunit;

using TupleStudy;

namespace ValueTupleStudyTest
{
    /// <summary>
    /// ValueTuple 需要.net framework 4.7及以上
    /// .net framework 4.7及以下,需要Nuget引用包System.ValueTuple 库
    /// </summary>
    public class ValueTupleStudyTest
    {
        private ValueTupleStudy valueTupleStudy;

        /// <summary>
        /// 构造函数
        /// </summary>
        public ValueTupleStudyTest()
        {
            valueTupleStudy = new ValueTupleStudy();
        }

        /// <summary>
        /// 使用构造函数创建值元组
        /// </summary>
        [Fact]
        public void CreateValueTuple_Test()
        {
            //创建包含零个元组的值元组
            var zeroTuple = this.valueTupleStudy.CreateValueTuple();
            Assert.IsType<ValueTuple>(zeroTuple);

            //1个元组的值元组
            var oneTuple = valueTupleStudy.CreateValueTuple<int>(1);
            Assert.Equal(1, oneTuple.Item1);
            Assert.Equal("first", new ValueTuple<string>("first").Item1);

            //2个元组的值元组
            var twoTuple = valueTupleStudy.CreateValueTuple<int, int>(1, 2);
            Assert.Equal(1, twoTuple.Item1);
            Assert.Equal(2, twoTuple.Item2);

            //3个元组的值元组
            var threeTuple = valueTupleStudy.CreateValueTuple<int, int, int>(1, 2, 3);
            Assert.Equal(1, threeTuple.Item1);
            Assert.Equal(2, threeTuple.Item2);
            Assert.Equal(3, threeTuple.Item3);


            //4个元组的值元组
            var fourTuple = valueTupleStudy.CreateValueTuple<int, int, int, int>(1, 2, 3, 4);
            Assert.Equal(1, fourTuple.Item1);
            Assert.Equal(2, fourTuple.Item2);
            Assert.Equal(3, fourTuple.Item3);
            Assert.Equal(4, fourTuple.Item4);

            //5个元组的值元组
            var fiveTuple = valueTupleStudy.CreateValueTuple<int, int, int, int, int>(1, 2, 3, 4, 5);
            Assert.Equal(1, fiveTuple.Item1);
            Assert.Equal(2, fiveTuple.Item2);
            Assert.Equal(3, fiveTuple.Item3);
            Assert.Equal(4, fiveTuple.Item4);
            Assert.Equal(5, fiveTuple.Item5);

            //6个元组的值元组
            var sixTuple = valueTupleStudy.CreateValueTuple<int, int, int, int, int, int>(1, 2, 3, 4, 5, 6);
            Assert.Equal(1, sixTuple.Item1);
            Assert.Equal(2, sixTuple.Item2);
            Assert.Equal(3, sixTuple.Item3);
            Assert.Equal(4, sixTuple.Item4);
            Assert.Equal(5, sixTuple.Item5);
            Assert.Equal(6, sixTuple.Item6);

            //7个元组的值元组
            var sevenTuple = valueTupleStudy.CreateValueTuple<int, int, int, int, int, int, int>(1, 2, 3, 4, 5, 6, 7);
            Assert.Equal(1, sevenTuple.Item1);
            Assert.Equal(2, sevenTuple.Item2);
            Assert.Equal(3, sevenTuple.Item3);
            Assert.Equal(4, sevenTuple.Item4);
            Assert.Equal(5, sevenTuple.Item5);
            Assert.Equal(6, sevenTuple.Item6);
            Assert.Equal(7, sevenTuple.Item7);

            //8个及以上元组的值元组:元组嵌套
            var overSevenTuple = valueTupleStudy.CreateValueTuple<int, int, int, int, int, int, int, ValueTuple<int, int, int>>(1, 2, 3, 4, 5, 6, 7, new ValueTuple<int, int, int>(8, 9, 10));
            Assert.Equal(1, overSevenTuple.Item1);
            Assert.Equal(2, overSevenTuple.Item2);
            Assert.Equal(3, overSevenTuple.Item3);
            Assert.Equal(4, overSevenTuple.Item4);
            Assert.Equal(5, overSevenTuple.Item5);
            Assert.Equal(6, overSevenTuple.Item6);
            Assert.Equal(7, overSevenTuple.Item7);

            //元组嵌套:
            //注意 构造方法创建的可以直接用 Item8 Item9等来引用,静态方法创建的,则要用  valueTuple.Item8.Item1 这种方式。
            Assert.Equal(8, overSevenTuple.Item8);
            Assert.Equal(9, overSevenTuple.Item9);
            Assert.Equal(10, overSevenTuple.Item10);

            //16个以上,要审视程序设计,是否确实需要使用ValueTuple,最好改成设计成类
        }

        /// <summary>
        /// 使用静态Create方法 创建值元组
        /// </summary>
        [Fact]
        public void GetValueTuple_Test()
        {
            //创建包含零个元组的值元组
            var zeroTuple = valueTupleStudy.GetValueTuple();
            Assert.IsType<ValueTuple>(zeroTuple);

            //1个元组的值元组
            var oneTuple = valueTupleStudy.GetValueTuple<int>(1);
            Assert.Equal(1, oneTuple.Item1);
            Assert.Equal("first", new ValueTuple<string>("first").Item1);

            //2个元组的值元组
            var twoTuple = valueTupleStudy.GetValueTuple<int, int>(1, 2);
            Assert.Equal(1, twoTuple.Item1);
            Assert.Equal(2, twoTuple.Item2);

            //3个元组的值元组
            var threeTuple = valueTupleStudy.GetValueTuple<int, int, int>(1, 2, 3);
            Assert.Equal(1, threeTuple.Item1);
            Assert.Equal(2, threeTuple.Item2);
            Assert.Equal(3, threeTuple.Item3);


            //4个元组的值元组
            var fourTuple = valueTupleStudy.GetValueTuple<int, int, int, int>(1, 2, 3, 4);
            Assert.Equal(1, fourTuple.Item1);
            Assert.Equal(2, fourTuple.Item2);
            Assert.Equal(3, fourTuple.Item3);
            Assert.Equal(4, fourTuple.Item4);

            //5个元组的值元组
            var fiveTuple = valueTupleStudy.GetValueTuple<int, int, int, int, int>(1, 2, 3, 4, 5);
            Assert.Equal(1, fiveTuple.Item1);
            Assert.Equal(2, fiveTuple.Item2);
            Assert.Equal(3, fiveTuple.Item3);
            Assert.Equal(4, fiveTuple.Item4);
            Assert.Equal(5, fiveTuple.Item5);

            //6个元组的值元组
            var sixTuple = valueTupleStudy.GetValueTuple<int, int, int, int, int, int>(1, 2, 3, 4, 5, 6);
            Assert.Equal(1, sixTuple.Item1);
            Assert.Equal(2, sixTuple.Item2);
            Assert.Equal(3, sixTuple.Item3);
            Assert.Equal(4, sixTuple.Item4);
            Assert.Equal(5, sixTuple.Item5);
            Assert.Equal(6, sixTuple.Item6);

            //7个元组的值元组
            var sevenTuple = valueTupleStudy.GetValueTuple<int, int, int, int, int, int, int>(1, 2, 3, 4, 5, 6, 7);
            Assert.Equal(1, sevenTuple.Item1);
            Assert.Equal(2, sevenTuple.Item2);
            Assert.Equal(3, sevenTuple.Item3);
            Assert.Equal(4, sevenTuple.Item4);
            Assert.Equal(5, sevenTuple.Item5);
            Assert.Equal(6, sevenTuple.Item6);
            Assert.Equal(7, sevenTuple.Item7);

            //8个及以上元组的值元组:元组嵌套
            var overSevenTuple = valueTupleStudy.GetValueTuple<int, int, int, int, int, int, int, ValueTuple<int, int, int>>(1, 2, 3, 4, 5, 6, 7, new ValueTuple<int, int, int>(8, 9, 10));
            Assert.Equal(1, overSevenTuple.Item1);
            Assert.Equal(2, overSevenTuple.Item2);
            Assert.Equal(3, overSevenTuple.Item3);
            Assert.Equal(4, overSevenTuple.Item4);
            Assert.Equal(5, overSevenTuple.Item5);
            Assert.Equal(6, overSevenTuple.Item6);
            Assert.Equal(7, overSevenTuple.Item7);

            //元组嵌套
            //注意 构造方法创建的可以直接用 Item8 Item9等来引用,静态方法创建的,则要用  valueTuple.Item8.Item1 这种方式。
            Assert.Equal(8, overSevenTuple.Item8.Item1);
            Assert.Equal(9, overSevenTuple.Item8.Item2);
            Assert.Equal(10, overSevenTuple.Item8.Item3);

            //16个以上,要审视程序设计,是否确实需要使用ValueTuple,最好改成设计成类
        }

        /// <summary>
        /// 自定义值元组项的名字
        /// </summary>
        [Fact]
        public void CustomName_ValueTuple_Test()
        {
            //使用var
            var (userId,userName,userAge) = ValueTuple.Create(1, "wanggaofeng", 18);
            Assert.Equal(1, userId);
            Assert.Equal("wanggaofeng", userName);
            Assert.Equal(18, userAge);


            //不使用var, 放()内
            (int id, string name, int age) = ValueTuple.Create(1, "wanggaofeng", 18);
            Assert.Equal(1, id);
            Assert.Equal("wanggaofeng", name);
            Assert.Equal(18, age);
        }

        /// <summary>
        /// 简化值元组的创建方法
        /// </summary>
        [Fact]
        public void SingleCreateValueTuple_Test()
        {
            //自定义名称
            var student = (userId: 1, userName: "wanggaofeng", userAge: 18);
            Assert.Equal(1,student.userId);
            Assert.Equal("wanggaofeng", student.userName);
            Assert.Equal(18, student.userAge);

            //默认名称
            var student2 = (1, "wanggaofeng", 18);
            Assert.Equal(1, student2.Item1);
            Assert.Equal("wanggaofeng", student2.Item2);
            Assert.Equal(18, student2.Item3);

            //方法返回值,方法中已命名
            var student3 = valueTupleStudy.SingleCreateValueTuple();
            Assert.Equal(1, student3.userId);
            Assert.Equal("王高峰", student3.userName);
            Assert.Equal(18, student3.userAge);
        }

        [Fact]
        public void GetNamedValueTuple_Test()
        {
            //使用引用方法的命名
            var student = valueTupleStudy.GetNamedValueTuple();
            Assert.Equal(1, student.userId);
            Assert.Equal("王高峰", student.userName);
            Assert.Equal(18U, student.userAge);

            //接收时重新命名
            var (id, name, age) = valueTupleStudy.GetNamedValueTuple();
            Assert.Equal(1, id);
            Assert.Equal("王高峰", name);
            Assert.Equal(18U, age);

            //不使用命名
            ValueTuple<int, string, uint> tuple = valueTupleStudy.GetNamedValueTuple();
            Assert.Equal(1, tuple.Item1);
            Assert.Equal("王高峰", tuple.Item2);
            Assert.Equal(18U, tuple.Item3);
        }

        [Fact]
        public void GetUnNamedValueTuple_Test()
        {
            //接收时重新命名
            var (userId, userName, userAge) = valueTupleStudy.GetUnNamedValueTuple();

            Assert.Equal(1,userId);
            Assert.Equal("王高峰", userName);
            Assert.Equal(18U, userAge);

            //使用默认
            var student = valueTupleStudy.GetUnNamedValueTuple();
            Assert.Equal(1, student.Item1);
            Assert.Equal("王高峰", student.Item2);
            Assert.Equal(18U, student.Item3);

            ValueTuple<int, string, uint> tuple = valueTupleStudy.GetUnNamedValueTuple();
            Assert.Equal(1, tuple.Item1);
            Assert.Equal("王高峰", tuple.Item2);
            Assert.Equal(18U, tuple.Item3);
        }

        /// <summary>
        /// 接收方法返回元组值时,忽略不需要的荐
        /// </summary>
        [Fact]
        public void IgnoreItem_ValuleTuple_Test()
        {
            //接收时重新命名,并忽略不需要的项:用_表示忽略的项
            var (_, userName, _) = valueTupleStudy.GetUnNamedValueTuple();
            Assert.Equal("王高峰",userName);

            //另一种方法
            (_, string userName2, _) = valueTupleStudy.GetUnNamedValueTuple();
            Assert.Equal("王高峰", userName2);
        }

        /// <summary>
        /// 值元组做为方法参数 测试
        /// </summary>
        [Fact]
        public void ValueTupleAsParameterForMether_Test()
        {
            var para = (userId:1,userName:"wanggaofeng", userAge:18);
            var result = valueTupleStudy.ValueTupleAsParameterForMether(para);
            Assert.True(result);

            var para2 = (1,2,3);
            var result2 = valueTupleStudy.ValueTupleAsParameterForMether(para2);
            Assert.False(result2);
        }

        //发布v1.0
    }
}