public async Task RetrieveMeets_GivenDateRange_ShouldOnlyReturnMeetsInRange()
        {
            // Arrange.
            var settings           = Substitute.For <ISettings>();
            var requestMaker       = Substitute.For <IRestRequestMaker>();
            var googleSheetFactory = Substitute.For <IMeetsGoogleSheetFactory>();
            var googleSheet        = Substitute.For <IMeetsGoogleSheet>();
            var dateTimeService    = Substitute.For <IDateTimeService>();
            var logger             = Substitute.For <ILogger>();
            var formatter          = NullFormatter.Instance();

            settings
            .GetValidString(Arg.Any <string>())
            .Returns("SomeSheetId");

            settings
            .GetValidString(Arg.Any <string>())
            .Returns("SomeAppKey");

            googleSheetFactory
            .CreateSheet(
                Arg.Any <Uri>(),
                Arg.Any <IRestRequestMaker>(),
                Arg.Any <ILogger>())
            .Returns(googleSheet);

            var dateField = new MeetField(
                false,
                false,
                "Date",
                "Date",
                0,
                false,
                formatter);

            googleSheet
            .Retrieve()
            .Returns(true);

            googleSheet
            .Fields
            .Returns(new[]
            {
                dateField
            });

            googleSheet
            .ValuesByRow
            .Returns(
                new[]
            {
                new[] { new MeetFieldValue(dateField, "2019-7-15", new ValidatorChain()) },
                new[] { new MeetFieldValue(dateField, "2019-7-31", new ValidatorChain()) },
                new[] { new MeetFieldValue(dateField, "2019-7-1", new ValidatorChain()) }
            });

            var testObject = new MeetsService(
                settings,
                requestMaker,
                googleSheetFactory,
                dateTimeService,
                logger);

            // Act.
            var result = await testObject.RetrieveMeets(
                new DateTime(2019, 7, 15),
                new DateTime(2019, 7, 31));

            // Assert.
            Assert.IsNotNull(result);
            Assert.AreEqual(2, result.Count());
        }
        public void Process_GivenGoogleSheet_ShouldOutputMeetDetails()
        {
            // Arrange.
            var sheet          = Substitute.For <IMeetsGoogleSheet>();
            var validatorChain = new ValidatorChain();
            var formatter      = NullFormatter.Instance();
            var field          = new MeetField(false, false, string.Empty, string.Empty, 0, false, formatter);

            sheet
            .Fields
            .Returns(new[]
            {
                new MeetField(false, false, string.Empty, "Column 1", 0, false, formatter),
                new MeetField(false, false, string.Empty, "Column 2", 0, false, formatter),
                new MeetField(false, false, string.Empty, "Column 3", 0, true, formatter),
                new MeetField(true, false, string.Empty, "Column 4", 0, false, formatter),
                new MeetField(false, true, string.Empty, "Column 5", 0, false, formatter),
            });

            sheet
            .ValuesByRow
            .Returns(new[]
            {
                new[]
                {
                    new MeetFieldValue(field, "R1C1", validatorChain),
                    new MeetFieldValue(field, "R1C2", validatorChain),
                    new MeetFieldValue(field, "R1C3", validatorChain),
                    new MeetFieldValue(field, "R1C4", validatorChain),
                    new MeetFieldValue(field, "R1C5", validatorChain)
                },
                new[]
                {
                    new MeetFieldValue(field, "R2C1", validatorChain),
                    new MeetFieldValue(field, "R2C2", validatorChain),
                    new MeetFieldValue(field, "R2C3", validatorChain),
                    new MeetFieldValue(field, "R2C4", validatorChain),
                    new MeetFieldValue(field, "R2C5", validatorChain)
                },
            });

            sheet
            .FindHeaderIndex("Column 3", Arg.Any <bool>())
            .Returns(2);

            sheet
            .FindHeaderIndex("Column 5", Arg.Any <bool>())
            .Returns(4);

            // Act.
            GoogleSheetToMeetDetailsTransformer.Process(
                sheet,
                out IEnumerable <MeetDetailsModel> models);

            // Assert.
            Assert.IsNotNull(models);

            Assert.AreEqual(2, models.Count());

            Assert.AreEqual("R1C1", models.ElementAt(0).FieldValues.ElementAt(0).Value);
            Assert.AreEqual("R2C5", models.ElementAt(1).FieldValues.ElementAt(4).Value);

            Assert.AreEqual(5, models.ElementAt(0).AllFields.Count());

            Assert.AreEqual("Column 1", models.ElementAt(0).AllFields.ElementAt(0).FriendlyText);
            Assert.AreEqual("Column 5", models.ElementAt(0).AllFields.ElementAt(4).FriendlyText);

            Assert.IsTrue(models.ElementAt(0).AllFields.ElementAt(3).DisplayInHeader);
            Assert.IsTrue(models.ElementAt(0).AllFields.ElementAt(4).IsRequired);
            Assert.IsTrue(models.ElementAt(0).AllFields.ElementAt(2).IsMeetTitle);
        }