private void RandomInputImpl(string inputCharsString, bool trimWhiteSpace, bool hasFieldsEnclosedInQuotes, Func <Random, char> chooseDelimiter) { // Using a hardcoded seed so our "random" tests are deterministic. const int seed = 0; const int iterations = 1000; var inputChars = inputCharsString.ToArray(); var random = new Random(seed); for (var i = 0; i < iterations; i++) { var inputLength = random.Next(minValue: 1, maxValue: 1000); var input = string.Join(string.Empty, Enumerable.Range(0, inputLength).Select(_ => inputChars[random.Next(0, inputChars.Length)])); var delimiter = chooseDelimiter.Invoke(random); using (var expectedParser = CreateExpectedParser(input, trimWhiteSpace, hasFieldsEnclosedInQuotes)) using (var actualParser = CreateActualParser(input, trimWhiteSpace, hasFieldsEnclosedInQuotes)) { if (delimiter != ',') { expectedParser.SetDelimiters(delimiter.ToString(CultureInfo.InvariantCulture)); actualParser.SetDelimiter(delimiter); } bool endOfData; int logicalLineCounter = 0; string[] previousFields = null; do { logicalLineCounter++; bool actualEndOfData = actualParser.EndOfData; bool expectedEndOfData = expectedParser.EndOfData; endOfData = actualEndOfData || expectedEndOfData; CustomAssert.Equal(expectedEndOfData, actualEndOfData, $"EndOfData mismatch on iteration {i} with delimiter \"{delimiter}\" logical line {logicalLineCounter} for input: {input}"); var actualLineNumber = actualParser.LineNumber; var expectedLineNumber = expectedParser.LineNumber; CustomAssert.Equal(expectedLineNumber, actualLineNumber, $"LineNumber mismatch on iteration {i} with delimiter \"{delimiter}\" on logical line {logicalLineCounter} for before fields: {string.Join(",", previousFields ?? Array.Empty<string>())}"); string[] actualFields; CsvMalformedLineException actualException = null; try { actualFields = actualParser.ReadFields(); } catch (CsvMalformedLineException ex) { actualFields = null; actualException = ex; } string[] expectedFields; MalformedLineException expectedException = null; try { expectedFields = expectedParser.ReadFields(); } catch (MalformedLineException ex) { expectedFields = null; expectedException = ex; } previousFields = expectedFields; if (expectedException != null || actualException != null) { CustomAssert.NotNull(expectedException, $"Expected no exception but was {actualException?.GetType().Name} on iteration {i} with delimiter \"{delimiter}\" on logical line {logicalLineCounter}"); CustomAssert.NotNull(actualException, $"Expected {expectedException?.GetType().Name} but was no exception on iteration {i} with delimiter \"{delimiter}\" on logical line {logicalLineCounter}"); CustomAssert.Equal(expectedParser.ErrorLine, actualParser.ErrorLine, $"ErrorLine mismatch on iteration {i} with delimiter \"{delimiter}\" on logical line {logicalLineCounter}"); // Who know what they're doing for their line numbers. It doesn't really matter if we exactly match probably? //Assert.Equal(expectedParser.ErrorLineNumber, actualParser.ErrorLineNumber, $"ErrorLineNumber mismatch on iteration {i} on line {logicalLineCounter}"); } CustomAssert.Equal(expectedFields, actualFields, $"ReadFields mismatch on iteration {i} with delimiter \"{delimiter}\" on logical line {logicalLineCounter} for input: {input}"); } while (!endOfData); } } }
public void RandomInput( [Values( "1234567890,\n", "1234567890,\n\"", "2,\n\r\"", "abcdefgh,\"\n\r\t ", "a2/\\#,\"'\n\r\t " )] string inputCharsString, [Values(true, false)] bool trimWhiteSpace, [Values(true, false)] bool hasFieldsEnclosedInQuotes ) { // Using a hardcoded seed so our "random" tests are deterministic. const int seed = 0; const int iterations = 1000; var inputChars = inputCharsString.ToArray(); var random = new Random(seed); for (var i = 0; i < iterations; i++) { var inputLength = random.Next(minValue: 1, maxValue: 1000); var input = string.Join(string.Empty, Enumerable.Range(0, inputLength).Select(_ => inputChars[random.Next(0, inputChars.Length)])); using (var expectedParser = CreateExpectedParser(input, trimWhiteSpace, hasFieldsEnclosedInQuotes)) using (var actualParser = CreateActualParser(input, trimWhiteSpace, hasFieldsEnclosedInQuotes)) { bool endOfData; int logicalLineCounter = 0; do { logicalLineCounter++; bool actualEndOfData = actualParser.EndOfData; bool expectedEndOfData = expectedParser.EndOfData; endOfData = actualEndOfData || expectedEndOfData; Assert.AreEqual(expectedEndOfData, actualEndOfData, $"EndOfData mismatch on iteration {i} logical line {logicalLineCounter} for input: {input}"); string[] actualFields; CsvMalformedLineException actualException = null; try { actualFields = actualParser.ReadFields(); } catch (CsvMalformedLineException ex) { actualFields = null; actualException = ex; } string[] expectedFields; MalformedLineException expectedException = null; try { expectedFields = expectedParser.ReadFields(); } catch (MalformedLineException ex) { expectedFields = null; expectedException = ex; } if (expectedException != null || actualException != null) { Assert.IsNotNull(expectedException, $"Expected no exception but was {actualException?.GetType().Name} on iteration {i} on logical line {logicalLineCounter}"); Assert.IsNotNull(actualException, $"Expected {expectedException?.GetType().Name} but was no exception on iteration {i} on logical line {logicalLineCounter}"); Assert.AreEqual(expectedParser.ErrorLine, actualParser.ErrorLine, $"ErrorLine mismatch on iteration {i} on logical line {logicalLineCounter}"); // Who know what they're doing for their line numbers. It doesn't really matter if we exactly match probably? //Assert.AreEqual(expectedParser.ErrorLineNumber, actualParser.ErrorLineNumber, $"ErrorLineNumber mismatch on iteration {i} on line {logicalLineCounter}"); } CollectionAssert.AreEqual(expectedFields, actualFields, $"ReadFields mismatch on iteration {i} on logical line {logicalLineCounter} for input: {input}"); } while (!endOfData); } } }