< Summary

Information
Class: ArturRios.Util.IO.DelimitedText
Assembly: ArturRios.Util
File(s): /home/runner/work/dotnet-util/dotnet-util/src/IO/DelimitedText.cs
Line coverage
100%
Covered lines: 22
Uncovered lines: 0
Coverable lines: 22
Total lines: 68
Line coverage: 100%
Branch coverage
100%
Covered branches: 14
Total branches: 14
Branch coverage: 100%
Method coverage
100%
Covered methods: 1
Fully covered methods: 1
Total methods: 1
Method coverage: 100%
Full method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ToDictionary(...)100%1414100%

File(s)

/home/runner/work/dotnet-util/dotnet-util/src/IO/DelimitedText.cs

#LineLine coverage
 1namespace ArturRios.Util.IO;
 2
 3/// <summary>
 4/// Turns the lines of a delimited text file into a column-per-header dictionary.
 5/// </summary>
 6/// <remarks>
 7/// Shared by <see cref="FileReader"/> and <see cref="FileReaderAsync"/> so the two cannot drift apart.
 8/// </remarks>
 9internal static class DelimitedText
 10{
 11    /// <summary>
 12    /// Maps each header in the first line to the values found beneath it.
 13    /// </summary>
 14    /// <param name="lines">The lines of the file, header first.</param>
 15    /// <param name="separator">Delimiter separating fields.</param>
 16    /// <exception cref="InvalidOperationException">
 17    /// Fewer than two lines were supplied, or a header name occurs more than once.
 18    /// </exception>
 19    internal static Dictionary<string, string[]> ToDictionary(string[] lines, char separator)
 20    {
 2221        if (lines.Length < 2)
 22        {
 423            throw new InvalidOperationException("File must have at least a header and one data line");
 24        }
 25
 1826        var headers = lines[0].Split(separator);
 27
 28        // Later columns would otherwise overwrite earlier ones, quietly returning fewer columns than the
 29        // file has.
 1830        var duplicates = headers
 4431            .GroupBy(header => header, StringComparer.Ordinal)
 4232            .Where(group => group.Count() > 1)
 233            .Select(group => $"'{group.Key}'")
 1834            .ToArray();
 35
 1836        if (duplicates.Length > 0)
 37        {
 238            throw new InvalidOperationException(
 239                $"Header row contains duplicate column names: {string.Join(", ", duplicates)}");
 40        }
 41
 1642        var columnLists = new List<string>[headers.Length];
 43
 10844        for (var i = 0; i < headers.Length; i++)
 45        {
 3846            columnLists[i] = new List<string>(lines.Length - 1);
 47        }
 48
 8449        for (var row = 1; row < lines.Length; row++)
 50        {
 2651            var values = lines[row].Split(separator);
 52
 17653            for (var col = 0; col < headers.Length; col++)
 54            {
 6255                columnLists[col].Add(col < values.Length ? values[col] : string.Empty);
 56            }
 57        }
 58
 1659        var dictionary = new Dictionary<string, string[]>(headers.Length);
 60
 10861        for (var i = 0; i < headers.Length; i++)
 62        {
 3863            dictionary[headers[i]] = [.. columnLists[i]];
 64        }
 65
 1666        return dictionary;
 67    }
 68}