Example #1
0
        public async Task Async(string csv, ReadRowEnding expected, string valueSep = ",")
        {
            var opts = Options.CreateBuilder(Options.Default).WithReadRowEnding(ReadRowEnding.Detect).WithValueSeparator(valueSep).BuildInternal();

            await RunAsyncReaderVariants <_Test>(
                opts,
                async (config, getReader) =>
            {
                var configForced = config as AsyncCountingAndForcingConfig <_Test>;
                var configCancel = config as AsyncCancelControlConfig <_Test>;
                var cInner       = (ConcreteBoundConfiguration <_Test>)(configForced?.Inner ?? configCancel?.Inner ?? config);

                await using (var str = await getReader(csv))
                {
                    var stateMachine = new ReaderStateMachine();
                    var charLookup   = CharacterLookup.MakeCharacterLookup(cInner.Options, out _);
                    using (var detector = new RowEndingDetector(stateMachine, cInner.Options, MemoryPool <char> .Shared, charLookup, str, cInner.Options.ValueSeparator.AsMemory()))
                    {
                        if (configForced != null)
                        {
                            configForced.Set(detector);
                        }

                        var detect = await detector.DetectAsync(CancellationToken.None);
                        Assert.True(detect.HasValue);
                        Assert.Equal(expected, detect.Value.Ending);
                    }
                }
            },
                cancellable : false
                );
        }
Example #2
0
        public async Task ManyHeadersAsync()
        {
            var config = Configuration.For <_ManyHeaders>(Options.Default.NewBuilder().WithRowEnding(RowEndings.CarriageReturnLineFeed).Build());

            var csv =
                string.Join(
                    ",",
                    new[]
            {
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader1),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader2),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader3),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader4),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader5),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader6),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader7),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader8),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader9),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader10)
            }
                    );

            await RunAsyncReaderVariants <_ManyHeaders>(
                Options.Default,
                async (config, makeReader) =>
            {
                var c = (ConcreteBoundConfiguration <_ManyHeaders>)config;

                using (var str = makeReader(csv))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(c.MemoryPool, c.EscapedValueStartAndStop, c.ValueSeparator, c.EscapeValueEscapeChar, c.CommentChar);
                    using var reader     = new HeadersReader <_ManyHeaders>(c, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                    var res = await reader.ReadAsync(default);
        public void Sync(string csv, RowEndings expected)
        {
            var config = (ConcreteBoundConfiguration <_Test>)Configuration.For <_Test>(Options.Default.NewBuilder().WithReadHeader(ReadHeaders.None).WithRowEnding(RowEndings.Detect).BuildInternal());

            using (var str = new StringReader(csv))
            {
                using (var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar))
                {
                    var detector = new RowEndingDetector <_Test>(config, charLookup, str);
                    var detect   = detector.Detect();
                    Assert.True(detect.HasValue);
                    Assert.Equal(expected, detect.Value.Ending);
                }
            }
        }
Example #4
0
        public void BufferToLarge()
        {
            var config = (ConcreteBoundConfiguration <_BufferToLarge>)Configuration.For <_BufferToLarge>(Options.Default.NewBuilder().WithMemoryPool(new TestMemoryPool <char>(16)).Build());

            // none
            {
                using (var str = new StringReader("foo,fizz,bar,buzz,baz,nope,nada,zilch,what,who,when,where,qwerty,dvorak"))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(MemoryPool <char> .Shared, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                    using (var reader = new HeadersReader <_BufferToLarge>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500)))
                    {
                        Assert.Throws <InvalidOperationException>(() => reader.Read());
                    }
                }
            }
        }
Example #5
0
        public void ManyHeaders()
        {
            var csv =
                string.Join(
                    ",",
                    new[]
            {
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader1),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader2),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader3),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader4),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader5),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader6),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader7),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader8),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader9),
                nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader10)
            }
                    );

            var config = (ConcreteBoundConfiguration <_ManyHeaders>)Configuration.For <_ManyHeaders>(Options.Default.NewBuilder().WithRowEnding(RowEndings.CarriageReturnLineFeed).Build());

            using (var str = new StringReader(csv))
            {
                using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                using var reader     = new HeadersReader <_ManyHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                var res = reader.Read();
                Assert.Collection(
                    ToEnumerable(res.Headers),
                    i => Assert.Equal(nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader1), new string(i.Span)),
                    i => Assert.Equal(nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader2), new string(i.Span)),
                    i => Assert.Equal(nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader3), new string(i.Span)),
                    i => Assert.Equal(nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader4), new string(i.Span)),
                    i => Assert.Equal(nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader5), new string(i.Span)),
                    i => Assert.Equal(nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader6), new string(i.Span)),
                    i => Assert.Equal(nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader7), new string(i.Span)),
                    i => Assert.Equal(nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader8), new string(i.Span)),
                    i => Assert.Equal(nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader9), new string(i.Span)),
                    i => Assert.Equal(nameof(_ManyHeaders.LoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongHeader10), new string(i.Span))
                    );
                Assert.True(res.IsHeader);
            }
        }
        public async Task Async(string csv, RowEndings expected)
        {
            var config = (ConcreteBoundConfiguration <_Test>)Configuration.For <_Test>(Options.Default.NewBuilder().WithReadHeader(ReadHeaders.None).WithRowEnding(RowEndings.Detect).BuildInternal());

            await RunAsyncReaderVariants <_Foo>(
                Options.Default,
                async (_, getReader) =>
            {
                using (var str = getReader(csv))
                {
                    using (var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar))
                    {
                        var detector = new RowEndingDetector <_Test>(config, charLookup, str);
                        var detect   = await detector.DetectAsync(CancellationToken.None);
                        Assert.True(detect.HasValue);
                        Assert.Equal(expected, detect.Value.Ending);
                    }
                }
            }
                );
        }
Example #7
0
        public void JustHeaders()
        {
            var config = (ConcreteBoundConfiguration <_JustHeaders>)Configuration.For <_JustHeaders>();

            // none
            {
                using (var str = new StringReader("fizz"))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                    using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                    var res = reader.Read();
                    Assert.Collection(ToEnumerable(res.Headers), i => Assert.Equal("fizz", new string(i.Span)));
                    Assert.False(res.IsHeader);
                }
            }

            // one, exact
            {
                using (var str = new StringReader("Foo"))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                    using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                    var res = reader.Read();
                    Assert.Collection(ToEnumerable(res.Headers), i => Assert.Equal("Foo", new string(i.Span)));
                    Assert.True(res.IsHeader);
                }
            }

            // one, inexact
            {
                using (var str = new StringReader("Foo,fizz"))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                    using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                    var res = reader.Read();
                    Assert.Collection(
                        ToEnumerable(res.Headers),
                        i => Assert.Equal("Foo", new string(i.Span)),
                        i => Assert.Equal("fizz", new string(i.Span))
                        );
                    Assert.True(res.IsHeader);
                }

                using (var str = new StringReader("fizz,Bar"))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                    using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                    var res = reader.Read();
                    Assert.Collection(
                        ToEnumerable(res.Headers),
                        i => Assert.Equal("fizz", new string(i.Span)),
                        i => Assert.Equal("Bar", new string(i.Span))
                        );
                    Assert.True(res.IsHeader);
                }
            }

            // two, exact
            {
                using (var str = new StringReader("Foo,Bar"))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                    using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                    var res = reader.Read();
                    Assert.Collection(
                        ToEnumerable(res.Headers),
                        i => Assert.Equal("Foo", new string(i.Span)),
                        i => Assert.Equal("Bar", new string(i.Span))
                        );
                    Assert.True(res.IsHeader);
                }

                using (var str = new StringReader("Bar,Foo"))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                    using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                    var res = reader.Read();
                    Assert.Collection(
                        ToEnumerable(res.Headers),
                        i => Assert.Equal("Bar", new string(i.Span)),
                        i => Assert.Equal("Foo", new string(i.Span))
                        );
                    Assert.True(res.IsHeader);
                }
            }

            // two, inexact
            {
                using (var str = new StringReader("Foo,Bar,Fizz"))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                    using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                    var res = reader.Read();
                    Assert.Collection(
                        ToEnumerable(res.Headers),
                        i => Assert.Equal("Foo", new string(i.Span)),
                        i => Assert.Equal("Bar", new string(i.Span)),
                        i => Assert.Equal("Fizz", new string(i.Span))
                        );
                    Assert.True(res.IsHeader);
                }

                using (var str = new StringReader("Bar,Fizz,Foo"))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                    using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                    var res = reader.Read();
                    Assert.Collection(
                        ToEnumerable(res.Headers),
                        i => Assert.Equal("Bar", new string(i.Span)),
                        i => Assert.Equal("Fizz", new string(i.Span)),
                        i => Assert.Equal("Foo", new string(i.Span))
                        );
                    Assert.True(res.IsHeader);
                }
            }
        }
Example #8
0
        public async Task JustHeadersAsync()
        {
            var config = (ConcreteBoundConfiguration <_JustHeaders>)Configuration.For <_JustHeaders>(Options.Default.NewBuilder().WithRowEnding(RowEndings.CarriageReturnLineFeed).Build());

            // none
            {
                await RunAsyncReaderVariants <_Foo>(
                    Options.Default,
                    async (_, getReader) =>
                {
                    using (var str = getReader("fizz"))
                    {
                        using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                        using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                        var res = await reader.ReadAsync(CancellationToken.None);
                        Assert.Collection(ToEnumerable(res.Headers), i => Assert.Equal("fizz", new string(i.Span)));
                        Assert.False(res.IsHeader);
                    }
                }
                    );
            }

            // one, exact
            {
                await RunAsyncReaderVariants <_Foo>(
                    Options.Default,
                    async (_, getReader) =>
                {
                    using (var str = getReader("Foo"))
                    {
                        using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                        using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                        var res = await reader.ReadAsync(CancellationToken.None);
                        Assert.Collection(ToEnumerable(res.Headers), i => Assert.Equal("Foo", new string(i.Span)));
                        Assert.True(res.IsHeader);
                    }
                }
                    );
            }

            // one, inexact
            {
                await RunAsyncReaderVariants <_Foo>(
                    Options.Default,
                    async (_, getReader) =>
                {
                    using (var str = getReader("Foo,fizz"))
                    {
                        using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                        using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                        var res = await reader.ReadAsync(CancellationToken.None);
                        Assert.Collection(
                            ToEnumerable(res.Headers),
                            i => Assert.Equal("Foo", new string(i.Span)),
                            i => Assert.Equal("fizz", new string(i.Span))
                            );
                        Assert.True(res.IsHeader);
                    }
                }
                    );

                await RunAsyncReaderVariants <_Foo>(
                    Options.Default,
                    async (_, getReader) =>
                {
                    using (var str = getReader("fizz,Bar"))
                    {
                        using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                        using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                        var res = await reader.ReadAsync(CancellationToken.None);
                        Assert.Collection(
                            ToEnumerable(res.Headers),
                            i => Assert.Equal("fizz", new string(i.Span)),
                            i => Assert.Equal("Bar", new string(i.Span))
                            );
                        Assert.True(res.IsHeader);
                    }
                }
                    );
            }

            // two, exact
            {
                await RunAsyncReaderVariants <_Foo>(
                    Options.Default,
                    async (_, getReader) =>
                {
                    using (var str = getReader("Foo,Bar"))
                    {
                        using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                        using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                        var res = await reader.ReadAsync(CancellationToken.None);
                        Assert.Collection(
                            ToEnumerable(res.Headers),
                            i => Assert.Equal("Foo", new string(i.Span)),
                            i => Assert.Equal("Bar", new string(i.Span))
                            );
                        Assert.True(res.IsHeader);
                    }
                }
                    );

                await RunAsyncReaderVariants <_Foo>(
                    Options.Default,
                    async (_, getReader) =>
                {
                    using (var str = getReader("Bar,Foo"))
                    {
                        using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                        using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                        var res = await reader.ReadAsync(CancellationToken.None);
                        Assert.Collection(
                            ToEnumerable(res.Headers),
                            i => Assert.Equal("Bar", new string(i.Span)),
                            i => Assert.Equal("Foo", new string(i.Span))
                            );
                        Assert.True(res.IsHeader);
                    }
                }
                    );
            }

            // two, inexact
            {
                await RunAsyncReaderVariants <_Foo>(
                    Options.Default,
                    async (_, getReader) =>
                {
                    using (var str = getReader("Foo,Bar,Fizz"))
                    {
                        using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                        using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                        var res = await reader.ReadAsync(CancellationToken.None);
                        Assert.Collection(
                            ToEnumerable(res.Headers),
                            i => Assert.Equal("Foo", new string(i.Span)),
                            i => Assert.Equal("Bar", new string(i.Span)),
                            i => Assert.Equal("Fizz", new string(i.Span))
                            );
                        Assert.True(res.IsHeader);
                    }
                }
                    );

                await RunAsyncReaderVariants <_Foo>(
                    Options.Default,
                    async (_, getReader) =>
                {
                    using (var str = getReader("Bar,Fizz,Foo"))
                    {
                        using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                        using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                        var res = await reader.ReadAsync(CancellationToken.None);
                        Assert.Collection(
                            ToEnumerable(res.Headers),
                            i => Assert.Equal("Bar", new string(i.Span)),
                            i => Assert.Equal("Fizz", new string(i.Span)),
                            i => Assert.Equal("Foo", new string(i.Span))
                            );
                        Assert.True(res.IsHeader);
                    }
                }
                    );
            }
        }
Example #9
0
        public void TrailingRecords()
        {
            var config = (ConcreteBoundConfiguration <_JustHeaders>)Configuration.For <_JustHeaders>(Options.Default.NewBuilder().WithRowEnding(RowEndings.CarriageReturnLineFeed).Build());

            // none
            {
                using (var str = new StringReader("fizz\r\n0\r\n"))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                    using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                    var res = reader.Read();
                    Assert.Collection(ToEnumerable(res.Headers), i => Assert.Equal("fizz", new string(i.Span)));
                    Assert.False(res.IsHeader);
                }
            }

            // one, exact
            {
                using (var str = new StringReader("Foo\r\nfoo"))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                    using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                    var res = reader.Read();
                    Assert.Collection(ToEnumerable(res.Headers), i => Assert.Equal("Foo", new string(i.Span)));
                    Assert.True(res.IsHeader);
                }
            }

            // one, inexact
            {
                using (var str = new StringReader("Foo,fizz\r\n1,2"))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                    using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                    var res = reader.Read();
                    Assert.Collection(
                        ToEnumerable(res.Headers),
                        i => Assert.Equal("Foo", new string(i.Span)),
                        i => Assert.Equal("fizz", new string(i.Span))
                        );
                    Assert.True(res.IsHeader);
                }

                using (var str = new StringReader("fizz,Bar\r\n2,blah\r\n"))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                    using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                    var res = reader.Read();
                    Assert.Collection(
                        ToEnumerable(res.Headers),
                        i => Assert.Equal("fizz", new string(i.Span)),
                        i => Assert.Equal("Bar", new string(i.Span))
                        );
                    Assert.True(res.IsHeader);
                }
            }

            // two, exact
            {
                using (var str = new StringReader("Foo,Bar\r\nwhatever,something"))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                    using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                    var res = reader.Read();
                    Assert.Collection(
                        ToEnumerable(res.Headers),
                        i => Assert.Equal("Foo", new string(i.Span)),
                        i => Assert.Equal("Bar", new string(i.Span))
                        );
                    Assert.True(res.IsHeader);
                }

                using (var str = new StringReader("Bar,Foo\r\n3,4"))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                    using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                    var res = reader.Read();
                    Assert.Collection(
                        ToEnumerable(res.Headers),
                        i => Assert.Equal("Bar", new string(i.Span)),
                        i => Assert.Equal("Foo", new string(i.Span))
                        );
                    Assert.True(res.IsHeader);
                }
            }

            // two, inexact
            {
                using (var str = new StringReader("Foo,Bar,Fizz\r\na,b,c\r\n"))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                    using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                    var res = reader.Read();
                    Assert.Collection(
                        ToEnumerable(res.Headers),
                        i => Assert.Equal("Foo", new string(i.Span)),
                        i => Assert.Equal("Bar", new string(i.Span)),
                        i => Assert.Equal("Fizz", new string(i.Span))
                        );
                    Assert.True(res.IsHeader);
                }

                using (var str = new StringReader("Bar,Fizz,Foo\r\n1,2,3"))
                {
                    using var charLookup = ReaderStateMachine.MakeCharacterLookup(config.MemoryPool, config.EscapedValueStartAndStop, config.ValueSeparator, config.EscapeValueEscapeChar, config.CommentChar);
                    using var reader     = new HeadersReader <_JustHeaders>(config, charLookup, str, new BufferWithPushback(MemoryPool <char> .Shared, 500));
                    var res = reader.Read();
                    Assert.Collection(
                        ToEnumerable(res.Headers),
                        i => Assert.Equal("Bar", new string(i.Span)),
                        i => Assert.Equal("Fizz", new string(i.Span)),
                        i => Assert.Equal("Foo", new string(i.Span))
                        );
                    Assert.True(res.IsHeader);
                }
            }
        }
Example #10
0
        public void IDisposable()
        {
            var implementors =
                typeof(Options).Assembly
                .GetTypes()
                .Where(t => t.GetInterfaces().Any(x => x == typeof(IDisposable)))
                .Where(t => !t.IsInterface)
                .Where(t => !t.IsAbstract)
                .Where(t => !t.Name.Contains("<"));     // exclude compiler generated classes, let's assume they get it right?

            foreach (var t in implementors)
            {
                if (t == typeof(Reader <>))
                {
                    IDisposable_Reader();
                }
                else if (t == typeof(ReaderStateMachine))
                {
                    IDisposable_ReaderStateMachine();
                }
                else if (t == typeof(Writer <>))
                {
                    IDisposable_Writer();
                }
                else if (t == typeof(BufferWithPushback))
                {
                    IDisposable_BufferWithPushback();
                }
                else if (t == typeof(MaybeInPlaceBuffer <>))
                {
                    IDisposable_MaybeInPlaceBuffer();
                }
                else if (t == typeof(Partial <>))
                {
                    IDisposable_Partial();
                }
                else if (t == typeof(RowEndingDetector <>))
                {
                    IDisposable_RowEndingDetector();
                }
                else if (t == typeof(HeadersReader <>))
                {
                    IDisposable_HeadersReader();
                }
                else if (t == typeof(HeadersReader <> .HeaderEnumerator))
                {
                    IDisposable_HeaderEnumerator();
                }
                else if (t == typeof(ReaderStateMachine.CharacterLookup))
                {
                    IDisposable_CharacterLookup();
                }
                else if (t == typeof(MaxSizedBufferWriter))
                {
                    IDisposable_MaxSizedBufferWriter();
                }
                else if (t == typeof(DynamicReader))
                {
                    IDisposable_DynamicReader();
                }
                else if (t == typeof(DynamicRow))
                {
                    IDisposable_DynamicRow();
                }
                else if (t == typeof(DynamicRowEnumerable <>))
                {
                    IDisposable_DynamicRowEnumerable();
                }
                else if (t == typeof(DynamicRowEnumerator <>))
                {
                    IDisposable_DynamicRowEnumerator();
                }
                else
                {
                    throw new XunitException($"No test configured for .Dispose() on {t.Name}");
                }
            }

            // test for Reader
            void IDisposable_Reader()
            {
                // double dispose does not error
                {
                    var r = MakeReader();
                    r.Dispose();
                    r.Dispose();
                }

                // assert throws after dispose
                {
                    var r = MakeReader();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => ((ITestableDisposable)r).AssertNotDisposed());
                }

                var testCases = 0;

                // figure out how many _public_ methods need testing
                int expectedTestCases;

                {
                    using (var r = MakeReader())
                    {
                        expectedTestCases = GetNumberExpectedDisposableTestCases(r);
                    }
                }

                // EnumerateAll
                {
                    var r = MakeReader();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => r.EnumerateAll());
                    testCases++;
                }

                // ReadAll
                {
                    var r = MakeReader();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => r.ReadAll());
                    testCases++;
                }

                // ReadAll pre-allocated
                {
                    var r = MakeReader();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => r.ReadAll(new List <_IDisposable>()));
                    testCases++;
                }

                // TryRead
                {
                    var r = MakeReader();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => r.TryRead(out _));
                    testCases++;
                }

                // TryReadWithReuse
                {
                    var r = MakeReader();
                    r.Dispose();
                    _IDisposable x = null;
                    Assert.Throws <ObjectDisposedException>(() => r.TryReadWithReuse(ref x));
                    testCases++;
                }

                Assert.Equal(expectedTestCases, testCases);

                // make a reader that's "good to go"
                IReader <_IDisposable> MakeReader()
                {
                    return
                        (Configuration.For <_IDisposable>(Options.Default)
                         .CreateReader(
                             new StringReader("")
                             ));
                }
            }

            // test for ReaderStateMachine
            void IDisposable_ReaderStateMachine()
            {
                // double dispose does not error
                {
                    var r = MakeReader();
                    r.Dispose();
                    r.Dispose();
                }

                // assert throws after dispose
                {
                    var r = MakeReader();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => ((ITestableDisposable)r).AssertNotDisposed());
                }

                var testCases = 0;

                // figure out how many _public_ methods need testing
                int expectedTestCases;

                {
                    using (var r = MakeReader())
                    {
                        expectedTestCases = GetNumberExpectedDisposableTestCases(r);
                    }
                }

                Assert.Equal(expectedTestCases, testCases);

                // make a reader that's "good to go"
                ReaderStateMachine MakeReader()
                {
                    return
                        (new ReaderStateMachine(MemoryPool <char> .Shared, 'a', 'b', 'c', RowEndings.CarriageReturnLineFeed, ReadHeaders.Always, 'd'));
                }
            }

            // test for Writer
            void IDisposable_Writer()
            {
                // double dispose does not error
                {
                    var w = MakeWriter();
                    w.Dispose();
                    w.Dispose();
                }

                // assert throws after dispose
                {
                    var w = MakeWriter();
                    w.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => ((ITestableDisposable)w).AssertNotDisposed());
                }

                var testCases = 0;

                // figure out how many _public_ methods need testing
                int expectedTestCases;

                {
                    using (var w = MakeWriter())
                    {
                        expectedTestCases = GetNumberExpectedDisposableTestCases(w);
                    }
                }

                // Write
                {
                    var w = MakeWriter();
                    w.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => w.Write(new _IDisposable()));
                    testCases++;
                }

                // WriteAll
                {
                    var w = MakeWriter();
                    w.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => w.WriteAll(new[] { new _IDisposable() }));
                    testCases++;
                }

                Assert.Equal(expectedTestCases, testCases);

                // make a writer that's "good to go"
                IWriter <_IDisposable> MakeWriter()
                {
                    return
                        (Configuration.For <_IDisposable>(Options.Default)
                         .CreateWriter(
                             new StringWriter()
                             ));
                }
            }

            // test for BufferWithPushback
            void IDisposable_BufferWithPushback()
            {
                // double dispose does not error
                {
                    var b = MakeBuffer();
                    b.Dispose();
                    b.Dispose();
                }

                // assert throws after dispose
                {
                    var b = MakeBuffer();
                    b.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => ((ITestableDisposable)b).AssertNotDisposed());
                }

                var testCases = 0;

                // figure out how many _public_ methods need testing
                int expectedTestCases;

                {
                    using (var b = MakeBuffer())
                    {
                        expectedTestCases = GetNumberExpectedDisposableTestCases(b);
                    }
                }

                Assert.Equal(expectedTestCases, testCases);

                // make a buffer that's "good to go"
                BufferWithPushback MakeBuffer()
                {
                    return(new BufferWithPushback(MemoryPool <char> .Shared, 64));
                }
            }

            // test for MaybeInPlaceBuffer
            void IDisposable_MaybeInPlaceBuffer()
            {
                // double dispose does not error
                {
                    var b = MakeBuffer();
                    b.Dispose();
                    b.Dispose();
                }

                // assert throws after dispose
                {
                    var b = MakeBuffer();
                    b.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => ((ITestableDisposable)b).AssertNotDisposed());
                }

                var testCases = 0;

                // figure out how many _public_ methods need testing
                int expectedTestCases;

                {
                    using (var b = MakeBuffer())
                    {
                        expectedTestCases = GetNumberExpectedDisposableTestCases(b);
                    }
                }

                Assert.Equal(expectedTestCases, testCases);

                // make a buffer that's "good to go"
                MaybeInPlaceBuffer <char> MakeBuffer()
                {
                    return(new MaybeInPlaceBuffer <char>(MemoryPool <char> .Shared));
                }
            }

            // test for Partial
            void IDisposable_Partial()
            {
                // double dispose does not error
                {
                    var p = MakePartial();
                    p.Dispose();
                    p.Dispose();
                }

                // assert throws after dispose
                {
                    var p = MakePartial();
                    p.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => ((ITestableDisposable)p).AssertNotDisposed());
                }

                var testCases = 0;

                // figure out how many _public_ methods need testing
                int expectedTestCases;

                {
                    using (var p = MakePartial())
                    {
                        expectedTestCases = GetNumberExpectedDisposableTestCases(p);
                    }
                }

                Assert.Equal(expectedTestCases, testCases);

                // make a partial that's "good to go"
                Partial <_IDisposable> MakePartial()
                {
                    return(new Partial <_IDisposable>(MemoryPool <char> .Shared));
                }
            }

            // test for RowEndingDetector
            void IDisposable_RowEndingDetector()
            {
                // double dispose does not error
                {
                    var d = MakeDetector();
                    d.Dispose();
                    d.Dispose();
                }

                // assert throws after dispose
                {
                    var d = MakeDetector();
                    d.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => ((ITestableDisposable)d).AssertNotDisposed());
                }

                var testCases = 0;

                // figure out how many _public_ methods need testing
                int expectedTestCases;

                {
                    using (var d = MakeDetector())
                    {
                        expectedTestCases = GetNumberExpectedDisposableTestCases(d);
                    }
                }

                Assert.Equal(expectedTestCases, testCases);

                // make a partial that's "good to go"
                RowEndingDetector <_IDisposable> MakeDetector()
                {
                    return(new RowEndingDetector <_IDisposable>(
                               (ConcreteBoundConfiguration <_IDisposable>)Configuration.For <_IDisposable>(),
                               ReaderStateMachine.MakeCharacterLookup(MemoryPool <char> .Shared, 'a', 'b', 'c', 'd'),
                               TextReader.Null
                               ));
                }
            }

            // test for HeadersReader
            void IDisposable_HeadersReader()
            {
                // double dispose does not error
                {
                    var r = MakeReader();
                    r.Dispose();
                    r.Dispose();
                }

                // assert throws after dispose
                {
                    var r = MakeReader();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => ((ITestableDisposable)r).AssertNotDisposed());
                }

                var testCases = 0;

                // figure out how many _public_ methods need testing
                int expectedTestCases;

                {
                    using (var r = MakeReader())
                    {
                        expectedTestCases = GetNumberExpectedDisposableTestCases(r);
                    }
                }

                Assert.Equal(expectedTestCases, testCases);

                // make a partial that's "good to go"
                HeadersReader <_IDisposable> MakeReader()
                {
                    var config = (ConcreteBoundConfiguration <_IDisposable>)Configuration.For <_IDisposable>();

                    return
                        (new HeadersReader <_IDisposable>(
                             config,
                             ReaderStateMachine.MakeCharacterLookup(MemoryPool <char> .Shared, 'a', 'b', 'c', 'd'),
                             TextReader.Null,
                             new BufferWithPushback(MemoryPool <char> .Shared, 64)
                             ));
                }
            }

            // test HeaderEnumerator
            void IDisposable_HeaderEnumerator()
            {
                // double dispose does not error
                {
                    var e = MakeEnumerator();
                    e.Dispose();
                    e.Dispose();
                }

                // assert throws after dispose
                {
                    var e = MakeEnumerator();
                    e.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => ((ITestableDisposable)e).AssertNotDisposed());
                }

                var testCases = 0;

                // figure out how many _public_ methods need testing
                int expectedTestCases;

                {
                    using (var e = MakeEnumerator())
                    {
                        expectedTestCases = GetNumberExpectedDisposableTestCases(e);
                    }
                }

                // Current
                {
                    var e = MakeEnumerator();
                    e.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => e.Current);
                    testCases++;
                }

                // MoveNext
                {
                    var e = MakeEnumerator();
                    e.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => e.MoveNext());
                    testCases++;
                }

                // Reset
                {
                    var e = MakeEnumerator();
                    e.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => e.Reset());
                    testCases++;
                }

                Assert.Equal(expectedTestCases, testCases);

                // make a partial that's "good to go"
                HeadersReader <_IDisposable> .HeaderEnumerator MakeEnumerator()
                {
                    return(new HeadersReader <_IDisposable> .HeaderEnumerator(0, ReadOnlyMemory <char> .Empty));
                }
            }

            // test CharacterLookup
            void IDisposable_CharacterLookup()
            {
                // double dispose does not error
                {
                    var l = MakeLookup();
                    l.Dispose();
                    l.Dispose();
                }

                // assert throws after dispose
                {
                    var l = MakeLookup();
                    l.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => ((ITestableDisposable)l).AssertNotDisposed());
                }

                var testCases = 0;

                // figure out how many _public_ methods need testing
                int expectedTestCases;

                {
                    using (var l = MakeLookup())
                    {
                        expectedTestCases = GetNumberExpectedDisposableTestCases(l);
                    }
                }

                Assert.Equal(expectedTestCases, testCases);

                // make a partial that's "good to go"
                ReaderStateMachine.CharacterLookup MakeLookup()
                {
                    return(ReaderStateMachine.MakeCharacterLookup(MemoryPool <char> .Shared, 'a', 'b', 'c', 'd'));
                }
            }

            // test CharacterLookup
            void IDisposable_MaxSizedBufferWriter()
            {
                // double dispose does not error
                {
                    var w = MakeWriter();
                    w.Dispose();
                    w.Dispose();
                }

                // assert throws after dispose
                {
                    var w = MakeWriter();
                    w.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => ((ITestableDisposable)w).AssertNotDisposed());
                }

                var testCases = 0;

                // figure out how many _public_ methods need testing
                int expectedTestCases;

                {
                    using (var w = MakeWriter())
                    {
                        expectedTestCases = GetNumberExpectedDisposableTestCases(w);
                    }
                }

                // Advance
                {
                    var w = MakeWriter();
                    w.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => w.Advance(0));
                    testCases++;
                }

                // GetMemory
                {
                    var w = MakeWriter();
                    w.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => w.GetMemory(0));
                    testCases++;
                }

                // GetSpan
                {
                    var w = MakeWriter();
                    w.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => w.GetSpan(0));
                    testCases++;
                }

                Assert.Equal(expectedTestCases, testCases);

                // make a partial that's "good to go"
                MaxSizedBufferWriter MakeWriter()
                {
                    return(new MaxSizedBufferWriter(MemoryPool <char> .Shared, null));
                }
            }

            // test for DynamicReader
            void IDisposable_DynamicReader()
            {
                // double dispose does not error
                {
                    var r = MakeReader();
                    r.Dispose();
                    r.Dispose();
                }

                // assert throws after dispose
                {
                    var r = MakeReader();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => ((ITestableDisposable)r).AssertNotDisposed());
                }

                var testCases = 0;

                // figure out how many _public_ methods need testing
                int expectedTestCases;

                {
                    using (var r = MakeReader())
                    {
                        expectedTestCases = GetNumberExpectedDisposableTestCases(r);
                    }
                }

                // EnumerateAll
                {
                    var r = MakeReader();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => r.EnumerateAll());
                    testCases++;
                }

                // ReadAll
                {
                    var r = MakeReader();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => r.ReadAll());
                    testCases++;
                }

                // ReadAll pre-allocated
                {
                    var r = MakeReader();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => r.ReadAll(new List <dynamic>()));
                    testCases++;
                }

                // TryRead
                {
                    var r = MakeReader();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => r.TryRead(out _));
                    testCases++;
                }

                // TryReadWithReuse
                {
                    var r = MakeReader();
                    r.Dispose();
                    dynamic x = null;
                    Assert.Throws <ObjectDisposedException>(() => r.TryReadWithReuse(ref x));
                    testCases++;
                }

                Assert.Equal(expectedTestCases, testCases);

                // make a reader that's "good to go"
                IReader <dynamic> MakeReader()
                {
                    return
                        (Configuration.ForDynamic(Options.Default.NewBuilder().WithReadHeader(ReadHeaders.Always).Build())
                         .CreateReader(new StringReader("")));
                }
            }

            // test for DynamicRow
            void IDisposable_DynamicRow()
            {
                // double dispose does not error
                {
                    var r = MakeRow();
                    r.Dispose();
                    r.Dispose();
                }

                // assert throws after dispose
                {
                    var r = MakeRow();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => ((ITestableDisposable)r).AssertNotDisposed());
                }

                var testCases = 0;

                // figure out how many _public_ methods need testing
                int expectedTestCases;

                {
                    using (var r = MakeRow())
                    {
                        expectedTestCases = GetNumberExpectedDisposableTestCases(r);
                    }
                }

                Assert.Equal(expectedTestCases, testCases);

                // make a reader that's "good to go"
                DynamicRow MakeRow()
                {
                    return(new DynamicRow());
                }
            }

            // test for DynamicRowEnumerable
            void IDisposable_DynamicRowEnumerable()
            {
                // double dispose does not error
                {
                    var r = MakeDynamicRowEnumerable();
                    r.Dispose();
                    r.Dispose();
                }

                // assert throws after dispose
                {
                    var r = MakeDynamicRowEnumerable();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => ((ITestableDisposable)r).AssertNotDisposed());
                }

                var testCases = 0;

                // figure out how many _public_ methods need testing
                int expectedTestCases;

                {
                    using (var r = MakeDynamicRowEnumerable())
                    {
                        expectedTestCases = GetNumberExpectedDisposableTestCases(r);
                    }
                }

                // GetEnumerator
                {
                    var r = MakeDynamicRowEnumerable();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => r.GetEnumerator());
                    testCases++;
                }

                Assert.Equal(expectedTestCases, testCases);

                // make a reader that's "good to go"
                DynamicRowEnumerable <_IDisposable> MakeDynamicRowEnumerable()
                {
                    return(new DynamicRowEnumerable <_IDisposable>(new DynamicRow()));
                }
            }

            // test for DynamicRowEnumerator
            void IDisposable_DynamicRowEnumerator()
            {
                // double dispose does not error
                {
                    var r = MakeDynamicRowEnumerator();
                    r.Dispose();
                    r.Dispose();
                }

                // assert throws after dispose
                {
                    var r = MakeDynamicRowEnumerator();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => ((ITestableDisposable)r).AssertNotDisposed());
                }

                var testCases = 0;

                // figure out how many _public_ methods need testing
                int expectedTestCases;

                {
                    using (var r = MakeDynamicRowEnumerator())
                    {
                        expectedTestCases = GetNumberExpectedDisposableTestCases(r);
                    }
                }

                // Current
                {
                    var r = MakeDynamicRowEnumerator();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => r.Current);
                    testCases++;
                }

                // MoveNext
                {
                    var r = MakeDynamicRowEnumerator();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => r.MoveNext());
                    testCases++;
                }

                // Reset
                {
                    var r = MakeDynamicRowEnumerator();
                    r.Dispose();
                    Assert.Throws <ObjectDisposedException>(() => r.Reset());
                    testCases++;
                }

                Assert.Equal(expectedTestCases, testCases);

                // make a reader that's "good to go"
                IEnumerator <string> MakeDynamicRowEnumerator()
                {
                    var opts   = Options.Default.NewBuilder().WithReadHeader(ReadHeaders.Never).Build();
                    var config = Configuration.ForDynamic(opts);

                    var r = config.CreateReader(new StringReader("a,b,c"));

                    r.TryRead(out var row);

                    IEnumerable <string> e = row;
                    var ee = e.GetEnumerator();

                    return(ee);
                }
            }
        }