private IEnumerable<ScanForBoundaryTestCase> CreatePartialBoundaryTestCases()
        {
            List<ScanForBoundaryTestCase> testCases = new List<ScanForBoundaryTestCase>();

            // Partial boundaries at various positions in the buffer
            this.CombinatorialEngineProvider.RunCombinations(
                BoundaryStrings.Where(str => str.Length > 1),     // excluding '-' boundary string since partials would be the empty string which this test does not handle
                LeadingLineFeedForBoundary,
                WhitespaceCounts,
                LineFeeds,
                new bool[] { false, true },
                (boundaryString, leadingBoundaryLineFeed, whitespaceCount, lineFeed, isEndBoundary) =>
                {
                    string boundaryToWrite = boundaryString.Substring(0, boundaryString.Length - 1);
                    int leadingLineFeedLength = leadingBoundaryLineFeed ? lineFeed.Length : 0;
                    int partialStartBoundaryLength = leadingLineFeedLength + BatchReaderStreamTestUtils.TwoDashesLength + boundaryToWrite.Length + whitespaceCount + lineFeed.Length;
                    int partialEndBoundaryLength = partialStartBoundaryLength + BatchReaderStreamTestUtils.TwoDashesLength;
                    Func<bool, int> partialBoundaryLength = isEnd => isEnd ? partialEndBoundaryLength : partialStartBoundaryLength;

                    ScanForBoundaryTestCase testCase = new ScanForBoundaryTestCase(lineFeed)
                    {
                        DebugDescription = "Partial boundary '" + boundaryString + "' at the beginning [isEnd = " + isEndBoundary +
                            ", lineFeed = " + StringUtils.LineFeedString(lineFeed) + ", leadingLineFeed = " + leadingBoundaryLineFeed +
                            ", whitespaceCount = " + whitespaceCount + "].",
                        Boundary = boundaryString,
                        PayloadFunc = builder => isEndBoundary
                            ? builder
                                .EndBoundary(boundaryToWrite, leadingBoundaryLineFeed, whitespaceCount)
                                .FillBytes(BatchReaderStreamBufferWrapper.BufferLength, 'b')
                                .ResetMemoryStream()
                            : builder
                                .StartBoundary(boundaryToWrite, leadingBoundaryLineFeed, whitespaceCount)
                                .FillBytes(BatchReaderStreamBufferWrapper.BufferLength, 'b')
                                .ResetMemoryStream(),
                        ExpectedScanResult = BatchReaderStreamBufferWrapper.ODataBatchReaderStreamScanResult.NoMatch,
                        ExpectedIsEndBoundary = false,
                        ExpectedBufferState = new BatchReaderStreamBufferState
                        {
                            ReadPositionInBuffer = 0,
                        }
                    };
                    testCases.Add(testCase);

                    testCase = new ScanForBoundaryTestCase(lineFeed)
                    {
                        DebugDescription = "Partial boundary '" + boundaryString + "' in the middle [isEnd = " + isEndBoundary +
                            ", lineFeed = " + StringUtils.LineFeedString(lineFeed) + ", leadingLineFeed = " + leadingBoundaryLineFeed +
                            ", whitespaceCount = " + whitespaceCount + "].",
                        Boundary = boundaryString,
                        PayloadFunc = builder => isEndBoundary
                            ? builder
                                .FillBytes(10, 'a')
                                .EndBoundary(boundaryToWrite, leadingBoundaryLineFeed, whitespaceCount)
                                .FillBytes(BatchReaderStreamBufferWrapper.BufferLength, 'b')
                                .ResetMemoryStream()
                            : builder
                                .FillBytes(10, 'a')
                                .StartBoundary(boundaryToWrite, leadingBoundaryLineFeed, whitespaceCount)
                                .FillBytes(BatchReaderStreamBufferWrapper.BufferLength, 'b')
                                .ResetMemoryStream(),
                        ExpectedScanResult = BatchReaderStreamBufferWrapper.ODataBatchReaderStreamScanResult.NoMatch,
                        ExpectedIsEndBoundary = false,
                        ExpectedBufferState = new BatchReaderStreamBufferState
                        {
                            ReadPositionInBuffer = 0,
                        }
                    };
                    testCases.Add(testCase);

                    testCase = new ScanForBoundaryTestCase(lineFeed)
                    {
                        DebugDescription = "Partial boundary '" + boundaryString + "' at the end [isEnd = " + isEndBoundary +
                            ", lineFeed = " + StringUtils.LineFeedString(lineFeed) + ", leadingLineFeed = " + leadingBoundaryLineFeed +
                            ", whitespaceCount = " + whitespaceCount + "].",
                        Boundary = boundaryString,
                        PayloadFunc = builder => isEndBoundary
                            ? builder
                                .FillBytes(BatchReaderStreamBufferWrapper.BufferLength - partialBoundaryLength(isEndBoundary), 'a')
                                .EndBoundary(boundaryToWrite, leadingBoundaryLineFeed, whitespaceCount)
                                .FillBytes(BatchReaderStreamBufferWrapper.BufferLength, 'b')
                                .ResetMemoryStream()
                            : builder
                                .FillBytes(BatchReaderStreamBufferWrapper.BufferLength - partialBoundaryLength(isEndBoundary), 'a')
                                .StartBoundary(boundaryToWrite, leadingBoundaryLineFeed, whitespaceCount)
                                .FillBytes(BatchReaderStreamBufferWrapper.BufferLength, 'b')
                                .ResetMemoryStream(),
                        ExpectedScanResult = BatchReaderStreamBufferWrapper.ODataBatchReaderStreamScanResult.PartialMatch,
                        ExpectedIsEndBoundary = false,
                        ExpectedBufferState = new BatchReaderStreamBufferState
                        {
                            ReadPositionInBuffer = 0,
                        }
                    };
                    testCases.Add(testCase);

                });
            return testCases;
        }
        private IEnumerable<ScanForBoundaryTestCase> CreateMissingBoundaryTestCases()
        {
            // TODO: add error tests where none of the expected boundaries can be found
            List<ScanForBoundaryTestCase> testCases = new List<ScanForBoundaryTestCase>();
            this.CombinatorialEngineProvider.RunCombinations(
                LeadingLineFeedForBoundary,
                WhitespaceCounts,
                LineFeeds,
                new bool[] { false, true },
                (leadingBoundaryLineFeed, whitespaceCount, lineFeed, isEndBoundary) =>
                {
                    int leadingLineFeedLength = leadingBoundaryLineFeed ? lineFeed.Length : 0;
                    Func<string, int> startBoundaryLength = boundary => leadingLineFeedLength + BatchReaderStreamTestUtils.TwoDashesLength + boundary.Length + whitespaceCount + lineFeed.Length;
                    Func<string, int> endBoundaryLength = boundary => startBoundaryLength(boundary) + BatchReaderStreamTestUtils.TwoDashesLength;
                    Func<string, bool, int> boundaryLength = (boundary, isEnd) => isEnd ? endBoundaryLength(boundary) : startBoundaryLength(boundary);

                    string batchBoundary = "batch_boundary";
                    string changesetBoundary = "changeset_boundary";
                    string[] boundaries = new string[] { changesetBoundary, batchBoundary };

                    ScanForBoundaryTestCase testCase = new ScanForBoundaryTestCase(lineFeed)
                    {
                        DebugDescription = "Only parent boundary '" + batchBoundary + "' present [isEnd = " + isEndBoundary +
                            ", lineFeed = " + StringUtils.LineFeedString(lineFeed) + ", leadingLineFeed = " + leadingBoundaryLineFeed +
                            ", whitespaceCount = " + whitespaceCount + "].",
                        Boundaries = boundaries,
                        ExpectedIsParentBoundary = true,
                        PayloadFunc = builder => isEndBoundary
                            ? builder
                                .FillBytes(10, 'a')
                                .EndBoundary(batchBoundary, leadingBoundaryLineFeed, whitespaceCount)
                                .FillBytes(BatchReaderStreamBufferWrapper.BufferLength, 'b')
                                .ResetMemoryStream()
                            : builder
                                .FillBytes(10, 'a')
                                .StartBoundary(batchBoundary, leadingBoundaryLineFeed, whitespaceCount)
                                .FillBytes(BatchReaderStreamBufferWrapper.BufferLength, 'b')
                                .ResetMemoryStream(),
                        ExpectedScanResult = BatchReaderStreamBufferWrapper.ODataBatchReaderStreamScanResult.Match,
                        ExpectedStartPosition = 10,
                        ExpectedEndPosition = 10 + boundaryLength(batchBoundary, isEndBoundary) - 1,
                        ExpectedIsEndBoundary = isEndBoundary,
                        ExpectedBufferState = new BatchReaderStreamBufferState
                        {
                            ReadPositionInBuffer = 0
                        }
                    };
                    testCases.Add(testCase);

                    testCase = new ScanForBoundaryTestCase(lineFeed)
                    {
                        DebugDescription = "Parent boundary '" + batchBoundary + "' partially at the end of the buffer [isEnd = " + isEndBoundary +
                            ", lineFeed = " + StringUtils.LineFeedString(lineFeed) + ", leadingLineFeed = " + leadingBoundaryLineFeed +
                            ", whitespaceCount = " + whitespaceCount + "].",
                        Boundaries = boundaries,
                        PayloadFunc = builder => isEndBoundary
                            ? builder
                                .FillBytes(BatchReaderStreamBufferWrapper.BufferLength - 10, 'a')
                                .EndBoundary(batchBoundary, leadingBoundaryLineFeed, whitespaceCount)
                                .ResetMemoryStream()
                            : builder
                                .FillBytes(BatchReaderStreamBufferWrapper.BufferLength - 10, 'a')
                                .StartBoundary(batchBoundary, leadingBoundaryLineFeed, whitespaceCount)
                                .ResetMemoryStream(),
                        ExpectedScanResult = BatchReaderStreamBufferWrapper.ODataBatchReaderStreamScanResult.PartialMatch,
                        ExpectedStartPosition = BatchReaderStreamBufferWrapper.BufferLength - 10,
                        ExpectedEndPosition = -1,
                        ExpectedIsEndBoundary = false,
                        ExpectedBufferState = new BatchReaderStreamBufferState
                        {
                            ReadPositionInBuffer = 0
                        }
                    };
                    testCases.Add(testCase);

                    testCase = new ScanForBoundaryTestCase(lineFeed)
                    {
                        DebugDescription = "Changeset boundary '" + batchBoundary + "' partially at the end of the buffer [isEnd = " + isEndBoundary +
                            ", lineFeed = " + StringUtils.LineFeedString(lineFeed) + ", leadingLineFeed = " + leadingBoundaryLineFeed +
                            ", whitespaceCount = " + whitespaceCount + "].",
                        Boundaries = boundaries,
                        PayloadFunc = builder => isEndBoundary
                            ? builder
                                .FillBytes(BatchReaderStreamBufferWrapper.BufferLength - 10, 'a')
                                .EndBoundary(changesetBoundary, leadingBoundaryLineFeed, whitespaceCount)
                                .EndBoundary(batchBoundary, leadingBoundaryLineFeed, whitespaceCount)
                                .ResetMemoryStream()
                            : builder
                                .FillBytes(BatchReaderStreamBufferWrapper.BufferLength - 10, 'a')
                                .StartBoundary(changesetBoundary, leadingBoundaryLineFeed, whitespaceCount)
                                .StartBoundary(batchBoundary, leadingBoundaryLineFeed, whitespaceCount)
                                .ResetMemoryStream(),
                        ExpectedScanResult = BatchReaderStreamBufferWrapper.ODataBatchReaderStreamScanResult.PartialMatch,
                        ExpectedStartPosition = BatchReaderStreamBufferWrapper.BufferLength - 10,
                        ExpectedEndPosition = -1,
                        ExpectedIsEndBoundary = false,
                        ExpectedBufferState = new BatchReaderStreamBufferState
                        {
                            ReadPositionInBuffer = 0
                        }
                    };
                    testCases.Add(testCase);
                });
            return testCases;
        }
        private IEnumerable<ScanForBoundaryTestCase> CreateBoundaryInTheMiddleTestCases()
        {
            List<ScanForBoundaryTestCase> testCases = new List<ScanForBoundaryTestCase>();
            this.CombinatorialEngineProvider.RunCombinations(
                BoundaryStrings,
                LeadingLineFeedForBoundary,
                WhitespaceCounts,
                LineFeeds,
                new bool[] { false, true },
                (boundaryString, leadingBoundaryLineFeed, whitespaceCount, lineFeed, isEndBoundary) =>
                {
                    int leadingLineFeedLength = leadingBoundaryLineFeed ? lineFeed.Length : 0;
                    int startBoundaryLength = leadingLineFeedLength + BatchReaderStreamTestUtils.TwoDashesLength + boundaryString.Length + whitespaceCount + lineFeed.Length;
                    int endBoundaryLength = startBoundaryLength + BatchReaderStreamTestUtils.TwoDashesLength;
                    Func<bool, int> boundaryLength = isEnd => isEnd ? endBoundaryLength : startBoundaryLength;

                    ScanForBoundaryTestCase testCase = new ScanForBoundaryTestCase(lineFeed)
                    {
                        DebugDescription = "Boundary '" + boundaryString + "' in the middle [isEnd = " + isEndBoundary +
                            ", lineFeed = " + StringUtils.LineFeedString(lineFeed) + ", leadingLineFeed = " + leadingBoundaryLineFeed +
                            ", whitespaceCount = " + whitespaceCount + "].",
                        Boundary = boundaryString,
                        PayloadFunc = builder => isEndBoundary
                            ? builder
                                .FillBytes(10, 'a')
                                .EndBoundary(boundaryString, leadingBoundaryLineFeed, whitespaceCount)
                                .FillBytes(BatchReaderStreamBufferWrapper.BufferLength, 'b')
                                .ResetMemoryStream()
                            : builder
                                .FillBytes(10, 'a')
                                .StartBoundary(boundaryString, leadingBoundaryLineFeed, whitespaceCount)
                                .FillBytes(BatchReaderStreamBufferWrapper.BufferLength, 'b')
                                .ResetMemoryStream(),
                        ExpectedScanResult = BatchReaderStreamBufferWrapper.ODataBatchReaderStreamScanResult.Match,
                        ExpectedStartPosition = 10,
                        ExpectedEndPosition = 10 + boundaryLength(isEndBoundary) - 1,
                        ExpectedIsEndBoundary = isEndBoundary,
                        ExpectedBufferState = new BatchReaderStreamBufferState
                        {
                            ReadPositionInBuffer = 0
                        }
                    };
                    testCases.Add(testCase);
                });
            return testCases;
        }