< Summary

Information
Class: ValidateLib.TabularData.Parsing.RowReader
Assembly: validatelib.dll
File(s): C:\skola_karlovka\RP\code\csv-validator\CSV_Validator\ValidateLib\TabularData\Parsing\RowReader.cs
Line coverage
74%
Covered lines: 32
Uncovered lines: 11
Coverable lines: 43
Total lines: 144
Line coverage: 74.4%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

C:\skola_karlovka\RP\code\csv-validator\CSV_Validator\ValidateLib\TabularData\Parsing\RowReader.cs

#LineLine coverage
 1using System.Text;
 2
 3namespace ValidateLib.TabularData.Parsing
 4{
 5    /// <summary>
 6    /// Reads one row from the CSV file with specific flags.
 7    /// Implements algorithm: https://www.w3.org/TR/2015/REC-tabular-data-model-20151217/#dfn-read-a-row
 8    /// </summary>
 9    public class RowReader : Reader
 10    {
 11        private QuotedCharReader quotedCharReader;
 112        public RowReader(Flags flags) : base(flags)
 13        {
 114            quotedCharReader = new QuotedCharReader(flags);
 115        }
 16
 17        public string? ReadRow(CustomStreamReader reader)
 18        {
 119            StringBuilder rowContent = new StringBuilder();
 20
 21            while (true)
 22            {
 123                int nextChar = reader.ReadChar();
 124                if (IsEndOfFile(nextChar))
 25                {
 126                    if (rowContent.ToString() == "")
 127                        return null;
 128                    return rowContent.ToString();
 29                }
 30
 31
 132                char currentChar = (char)nextChar;
 133                if (ProcessChar(reader, rowContent, currentChar))
 134                    return rowContent.ToString();
 35
 36            }
 37        }
 38
 39        /// <summary>
 40        /// Processes one char for the read row method.
 41        /// </summary>
 42        /// <param name="reader"></param>
 43        /// <param name="rowContent"></param>
 44        /// <param name="currentChar"></param>
 45        /// <returns>True if the line has already been read</returns>
 46        bool ProcessChar(CustomStreamReader reader, StringBuilder rowContent, char currentChar)
 47        {
 148            if (currentChar == flags.escapeCharacter)
 49            {
 150                return HandleEscapeChar(reader, rowContent);
 51            }
 152            else if (currentChar == flags.quoteCharacter[0])
 53            {
 154                return HandlePotentialQuoteChar(reader, rowContent, currentChar);
 55            }
 56            else
 57            {
 158                return HandleNewlineOrDefault(reader, rowContent, currentChar);
 59            }
 60        }
 61        /// <summary>
 62        /// Handles case when we read a char that is the same as the first char of quoteChar string.
 63        /// </summary>
 64        /// <param name="reader"></param>
 65        /// <param name="rowContent"></param>
 66        /// <param name="currentChar"></param>
 67        /// <returns> Returns always false as we cannot read unescaped newline character hear</returns>
 68        private bool HandlePotentialQuoteChar(CustomStreamReader reader, StringBuilder rowContent, char currentChar)
 69        {
 70            // Case when the quoteChar is of length one so it has alrady been matched.
 171            if (quoteCharacterLength == 1)
 72            {
 073                rowContent.Append(quotedCharReader.ReadQuotedValue(reader));
 074                return false;
 75            }
 76
 77            // Otherwise proceed to more complex method to determine whether a quote char of length > 1 has been detecte
 178            reader.MoveBack(1);
 179            if (quotedCharReader.VerifyNextCharsAreQuoteChar(reader))
 180                rowContent.Append(quotedCharReader.ReadQuotedValue(reader));
 81            else
 82            {
 083                reader.ReadChar();
 084                rowContent.Append(currentChar);
 85            }
 186            return false;
 87        }
 88
 89        /// <summary>
 90        /// Handles cases of newline or default not special character.
 91        /// </summary>
 92        /// <param name="reader"></param>
 93        /// <param name="rowContent"></param>
 94        /// <param name="currentChar"></param>
 95        /// <returns>True if unescaped newline character has been read</returns>
 96        private bool HandleNewlineOrDefault(CustomStreamReader reader, StringBuilder rowContent, char currentChar)
 97        {
 198            reader.MoveBack(1);
 199            if (IsNextCharsLineTerminator(reader))
 100            {
 1101                return true;
 102            }
 103            else
 104            {
 1105                reader.ReadChar();
 1106                rowContent.Append(currentChar);
 107            }
 1108            return false;
 109        }
 110
 111        /// <summary>
 112        /// Escape char was already detected. Need to process more chars for special cases 2.1 and 2.2 from algorithm
 113        /// https://www.w3.org/TR/2015/REC-tabular-data-model-20151217/#dfn-read-a-row
 114        /// </summary>
 115        /// <param name="reader"></param>
 116        /// <param name="dialect"></param>
 117        /// <param name="rowContent"></param>
 118        /// <returns> Returns always false as we cannot read unescaped newline character hear</returns>
 119        private bool HandleEscapeChar(CustomStreamReader reader, StringBuilder rowContent)
 120        {
 1121            if (quotedCharReader.VerifyNextCharsAreQuoteChar(reader))
 122            {
 0123                rowContent.Append(flags.escapeCharacter);
 0124                rowContent.Append(flags.quoteCharacter);
 125            }
 1126            else if (flags.quoteCharacter != flags.escapeCharacter.ToString())
 127            {
 0128                rowContent.Append(flags.escapeCharacter);
 0129                int nextSymbol = reader.ReadChar();
 130
 0131                if (IsEndOfFile(nextSymbol))
 0132                    throw new Exception("Unexpected end of file after escape char!");
 133
 0134                rowContent.Append((char)nextSymbol);
 135            }
 136            else
 137            {
 1138                rowContent.Append(quotedCharReader.ReadQuotedValue(reader));
 139            }
 140
 1141            return false;
 142        }
 143    }
 144}