private void AppendDuplTest(
            string name, int segSize,
            Func <string, IWritableFeed <UtcDateTime, _DatetimeByte_SeqPk1> > newFile,
            Action <IWritableFeed <UtcDateTime, _DatetimeByte_SeqPk1> > update,
            Action <IWritableFeed <UtcDateTime, _DatetimeByte_SeqPk1> > init)
        {
            if (RunMode != Mode.OneTime)
            {
                Assert.Inconclusive("RunMode={0} is not supported", RunMode);
            }

            string fileName = GetBinFileName();

            using (IWritableFeed <UtcDateTime, _DatetimeByte_SeqPk1> f = newFile(fileName))
            {
                if (update != null)
                {
                    update(f);
                }

                init(f);

                IEnumerable <ArraySegment <_DatetimeByte_SeqPk1> > dat =
                    Segments(DuplicatesEvery <_DatetimeByte_SeqPk1>(0, 2, 1), SameValue(segSize));

                f.AppendData(dat);

                TestUtils.CollectionAssertEqual(
                    dat, f.Stream(UtcDateTime.MinValue),
                    "adding dupl start={0}, until={1}, duplEvery={2}, fixedSegments={3} {4}", 0, 2, 1, segSize,
                    name);
            }
        }
        private void TwoValueTest <TInd, T>(IWritableFeed <TInd, T> f, T itm1, T itm2)
            where TInd : IComparable <TInd>
        {
            var item1 = new[] { new ArraySegment <T>(new[] { itm1 }) };
            var item2 = new[] { new ArraySegment <T>(new[] { itm2 }) };

            if (AllowCreate)
            {
                f.AppendData(item1);
                TestUtils.CollectionAssertEqual(item1, f.Stream(), "#1");

                if (f.UniqueIndexes)
                {
                    Assert.Throws <BinaryFileException>(() => f.AppendData(item1), "#2a");
                }
                else
                {
                    f.AppendData(item1);
                    TestUtils.CollectionAssertEqual(Join(item1, item1), f.Stream(), "#2b");

                    f.AppendData(item1, true);
                    TestUtils.CollectionAssertEqual(item1, f.Stream(), "#2c");
                }

                f.AppendData(item2);
                TestUtils.CollectionAssertEqual(Join(item1, item2), f.Stream(), "#3");

                f.AppendData(item2, true);
                TestUtils.CollectionAssertEqual(Join(item1, item2), f.Stream(), "#3a");

                if (f.UniqueIndexes)
                {
                    Assert.Throws <BinaryFileException>(() => f.AppendData(item2), "#4a");
                }
                else
                {
                    f.AppendData(item2);
                    TestUtils.CollectionAssertEqual(Join(item1, item2, item2), f.Stream(), "#4b");
                }

                f.AppendData(item1, true);
            }

            TestUtils.CollectionAssertEqual(item1, f.Stream(), "#final");
        }
        private void Regular <TInd, T>(IWritableFeed <TInd, T> f)
            where TInd : IComparable <TInd>
        {
            if (AllowCreate)
            {
                if (!typeof(T).IsValueType || !typeof(TInd).IsValueType)
                {
                    var dfltItem = new[] { new ArraySegment <T>(new[] { default(T) }) };
                    Assert.Throws <BinaryFileException>(() => f.AppendData(dfltItem));
                }

                f.AppendData(Data <T>(10, 20));
                TestUtils.CollectionAssertEqual(Data <T>(10, 20), f.Stream(), "#1");

                Assert.Throws <BinaryFileException>(() => f.AppendData(Data <T>(5, 30)), "#2");
                Assert.Throws <BinaryFileException>(() => f.AppendData(Data <T>(10, 20)), "#2a");
                Assert.Throws <BinaryFileException>(() => f.AppendData(Data <T>(9, 15)), "#2b");
                Assert.Throws <BinaryFileException>(() => f.AppendData(Data <T>(11, 15)), "#2c");
                Assert.Throws <BinaryFileException>(() => f.AppendData(Data <T>(19, 20)), "#2d");
                Assert.Throws <BinaryFileException>(() => f.AppendData(Data <T>(19, 20)), "#2d");

                if (f.UniqueIndexes)
                {
                    Assert.Throws <BinaryFileException>(() => f.AppendData(Data <T>(20, 20)), "#3");
                    Assert.Throws <BinaryFileException>(() => f.AppendData(Data <T>(20, 30)), "#3a");
                }

                f.AppendData(new[] { new ArraySegment <T>(new T[0], 0, 0) });
                TestUtils.CollectionAssertEqual(Data <T>(10, 20), f.Stream(), "#5");

                f.AppendData(new[] { new ArraySegment <T>(new T[1], 1, 0) });
                TestUtils.CollectionAssertEqual(Data <T>(10, 20), f.Stream(), "#6");

                f.AppendData(new ArraySegment <T> [0]);
                TestUtils.CollectionAssertEqual(Data <T>(10, 20), f.Stream(), "#7");

                f.AppendData(Data <T>(10, 14, 2), true);
                TestUtils.CollectionAssertEqual(Data <T>(10, 14, 2), f.Stream(), "#8");

                f.AppendData(Data <T>(10, 13), true);
                TestUtils.CollectionAssertEqual(Data <T>(10, 13), f.Stream(), "#9");

                f.AppendData(Data <T>(14, 14));
                TestUtils.CollectionAssertEqual(Data <T>(10, 14), f.Stream(), "#10");

                f.AppendData(Data <T>(15, 16));
                TestUtils.CollectionAssertEqual(Data <T>(10, 16), f.Stream(), "#11");

                f.AppendData(Data <T>(10, 10), true);
                TestUtils.CollectionAssertEqual(Data <T>(10, 10), f.Stream(), "#12");

                if (!f.UniqueIndexes)
                {
                    f.AppendData(Data <T>(10, 10));
                    TestUtils.CollectionAssertEqual(
                        Join(Data <T>(10, 10), Data <T>(10, 10)), f.Stream(), "#13");

                    f.AppendData(Data <T>(10, 10), true);
                    TestUtils.CollectionAssertEqual(Data <T>(10, 10), f.Stream(), "#14");

                    f.AppendData(Data <T>(10, 11));
                    TestUtils.CollectionAssertEqual(
                        Join(Data <T>(10, 10), Data <T>(10, 11)), f.Stream(), "#15");
                }

                f.AppendData(Data <T>(5, 10), true);
            }

            TestUtils.CollectionAssertEqual(Data <T>(5, 10), f.Stream(), "#final");
        }
        private void Run(
            string name, int itemCount,
            Func <string, IWritableFeed <UtcDateTime, _DatetimeByte_SeqPk1> > newFile,
            Action <IWritableFeed <UtcDateTime, _DatetimeByte_SeqPk1> > update,
            Action <IWritableFeed <UtcDateTime, _DatetimeByte_SeqPk1> > init)
        {
            string fileName = GetBinFileName();

            IEnumerable <ArraySegment <_DatetimeByte_SeqPk1> > newData = Data(itemCount, 0, itemCount);
            List <_DatetimeByte_SeqPk1> expected = newData.Stream().ToList();

            Assert.AreEqual(itemCount, expected.Count);
            _DatetimeByte_SeqPk1[] expectedRev = expected.ToArray();
            Array.Reverse(expectedRev);
            IWritableFeed <UtcDateTime, _DatetimeByte_SeqPk1>
            f = !AllowCreate
                        ? (IWritableFeed <UtcDateTime, _DatetimeByte_SeqPk1>)
                BinaryFile.Open(fileName, false, LegacyResolver)
                        : newFile(fileName);

            try
            {
                if (update != null)
                {
                    update(f);
                }

                if (AllowCreate)
                {
                    init(f);
                    f.AppendData(newData);
                    f.Dispose();
                    f =
                        (IWritableFeed <UtcDateTime, _DatetimeByte_SeqPk1>)
                        BinaryFile.Open(fileName, false, LegacyResolver);
                }

                TestUtils.CollectionAssertEqual(
                    _empty, f.Stream(UtcDateTime.MinValue, inReverse: true),
                    "nothing before 0 {0}", name);

                TestUtils.CollectionAssertEqual(
                    _empty, f.Stream(UtcDateTime.MaxValue),
                    "nothing after max {0}", name);

                if (itemCount <= 0)
                {
                    Assert.IsTrue(f.IsEmpty, "IsEmpty {0}", name);
                    Assert.AreEqual(default(UtcDateTime), f.FirstIndex, "default FirstInd {0}", name);
                    Assert.AreEqual(default(UtcDateTime), f.LastIndex, "default LastInd {0}", name);
                    TestUtils.CollectionAssertEqual(_empty, f.Stream(UtcDateTime.MinValue), "empty forward {0}", name);
                    TestUtils.CollectionAssertEqual(
                        _empty, f.Stream(UtcDateTime.MinValue, inReverse: true), "empty backward {0}", name);
                    return;
                }

                Assert.IsFalse(f.IsEmpty, "!IsEmpty {0}", name);

                Assert.AreEqual(expected[0].a, f.FirstIndex, name + " first");
                Assert.AreEqual(expected[itemCount - 1].a, f.LastIndex, "last {0}", name);

                TestUtils.CollectionAssertEqual(expected, f.Stream(UtcDateTime.MinValue), "full forward {0}", name);
                TestUtils.CollectionAssertEqual(
                    expectedRev, f.Stream(UtcDateTime.MaxValue, inReverse: true), "full backward {0}", name);

                const int skipStart = 0;
                const int takeStart = 0;

                const int maxSkipCount = 50;

                int maxSkip = Math.Min(maxSkipCount, itemCount);
                for (int skip = skipStart; skip < maxSkip; skip++)
                {
                    int maxTake = Math.Min(maxSkipCount, itemCount - maxSkip + 1);
                    for (int take = takeStart; take < maxTake; take++)
                    {
                        TestUtils.CollectionAssertEqual(
                            expected.Skip(skip).Take(take), f.Stream(expected[skip].a, maxItemCount: take),
                            "skip {1} take {2} {0}", name, skip, take);

                        if (itemCount < take)
                        {
                            TestUtils.CollectionAssertEqual(
                                expected.Skip(skip).Take(take - 1),
                                f.Stream(expected[skip].a.AddSeconds(1), maxItemCount: take - 1),
                                "next tick skip {1} take ({2}-1) {0}", name, skip, take);
                        }

                        if (itemCount < skip)
                        {
                            TestUtils.CollectionAssertEqual(
                                expectedRev.Skip(skip - 1).Take(take),
                                f.Stream(expectedRev[skip].a, maxItemCount: take, inReverse: true),
                                "backward, existing item, skip {1} take {2} {0}", name, skip, take);

                            TestUtils.CollectionAssertEqual(
                                expectedRev.Skip(skip - 1).Take(take),
                                f.Stream(expectedRev[skip].a.AddSeconds(-1), maxItemCount: take, inReverse: true),
                                "backward, non-existing, skip {1} take {2} {0}", name, skip, take);
                        }
                    }
                }
            }
            finally
            {
                f.Dispose();
            }
        }
        private void AppendTest(
            string name, int segSize, int itemCount,
            Func <int, int, int, IEnumerable <ArraySegment <_DatetimeByte_SeqPk1> > > data,
            Func <string, IWritableFeed <UtcDateTime, _DatetimeByte_SeqPk1> > newFile,
            Action <IWritableFeed <UtcDateTime, _DatetimeByte_SeqPk1> > update,
            Action <IWritableFeed <UtcDateTime, _DatetimeByte_SeqPk1> > init)
        {
            if (RunMode != Mode.OneTime)
            {
                Assert.Inconclusive("RunMode={0} is not supported", RunMode);
            }

            string fileName = GetBinFileName();

            using (IWritableFeed <UtcDateTime, _DatetimeByte_SeqPk1> f = newFile(fileName))
            {
                if (update != null)
                {
                    update(f);
                }

                init(f);

                TestUtils.CollectionAssertEqual(
                    _empty, f.Stream(UtcDateTime.MinValue),
                    "initial empty {0}", name);

                int lastStep = 0;
                foreach (int step in new[] { itemCount / 10, itemCount / 5, itemCount / 3, itemCount })
                {
                    var lastBefore = f.LastIndex;
                    f.AppendData(data(segSize, lastStep, step));
                    var lastAfter = f.LastIndex;

                    if (step > 0)
                    {
                        Assert.AreNotEqual(lastBefore, lastAfter);
                    }

                    TestUtils.CollectionAssertEqual(
                        data(itemCount, 0, step),
                        f.Stream(UtcDateTime.MinValue),
                        "adding {0} to {1} {2}", lastStep, step, name);

                    lastStep = step; // +(f.UniqueIndexes ? 0 : 1);
                }

                int halfItemCnt = itemCount / 2;
                if (itemCount >= 2)
                {
                    f.AppendData(data(segSize, 0, halfItemCnt), true);
                    TestUtils.CollectionAssertEqual(
                        data(segSize, 0, halfItemCnt), f.Stream(UtcDateTime.MinValue),
                        "nothing before 0 {0}", name);
                }

                if (halfItemCnt > 2)
                {
                    // ReSharper disable AccessToDisposedClosure
                    Assert.Throws <BinaryFileException>(
                        () => f.AppendData(data(segSize, halfItemCnt - 1, halfItemCnt)));
                    Assert.Throws <BinaryFileException>(
                        () => f.AppendData(data(segSize, halfItemCnt - 1, halfItemCnt + 1)));
                    Assert.Throws <BinaryFileException>(
                        () => f.AppendData(data(segSize, halfItemCnt - 2, halfItemCnt - 1)));
                    Assert.Throws <BinaryFileException>(
                        () => f.AppendData(data(segSize, halfItemCnt - 2, halfItemCnt + 1)));
                    // ReSharper restore AccessToDisposedClosure
                }
            }
        }