< Summary

Class:Itinero.Instructions.ToText.SubstituteText
Assembly:Itinero.Instructions
File(s):/home/runner/work/routing2/routing2/src/Itinero.Instructions/ToText/SubstituteText.cs
Covered lines:70
Uncovered lines:21
Coverable lines:91
Total lines:144
Line coverage:76.9% (70 of 91)
Covered branches:39
Total branches:55
Branch coverage:70.9% (39 of 55)
Tag:230_15134869466

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)100%4100%
ToText(...)68.62%5172.72%
ToString()100%10%
SubstitutedValueCount()100%1100%

File(s)

/home/runner/work/routing2/routing2/src/Itinero.Instructions/ToText/SubstituteText.cs

#LineLine coverage
 1using System.Collections.Generic;
 2using System.Linq;
 3using System.Text;
 4using Itinero.Instructions.Types;
 5using Itinero.Network.Attributes;
 6
 7namespace Itinero.Instructions.ToText;
 8
 9/***
 10 * Instruction to text changes an instruction object into text based on simple substitution.
 11 * It uses reflection to create a dictionary of all available fields, which are substituted
 12 */
 13internal class SubstituteText : IInstructionToText
 14{
 15    private readonly string _context;
 16    private readonly bool _crashOnMissingKey;
 17
 18    private readonly Dictionary<string, IInstructionToText>?
 19        _extensions; // extra "fields" to convert this into a string
 20
 21    private readonly Box<IInstructionToText>? _nestedToText;
 22    private readonly IEnumerable<(string textOrVarName, bool substitute)> _text;
 23
 17524    public SubstituteText(
 17525        IEnumerable<(string textOrVarName, bool substitute)> text,
 17526        Box<IInstructionToText>? nestedToText = null,
 17527        string context = "context not set",
 17528        Dictionary<string, IInstructionToText>? extensions = null,
 17529        bool crashOnMissingKey = true
 17530    )
 17531    {
 17532        var allTexts = new List<(string textOrVarName, bool substitute)>();
 96733        foreach (var (txt, subs) in text)
 22134        {
 22135            allTexts.Add((subs ? txt.ToLower() : txt, subs));
 22136        }
 37
 17538        _text = allTexts;
 17539        _nestedToText = nestedToText;
 17540        _context = context;
 17541        _extensions = extensions;
 17542        _crashOnMissingKey = crashOnMissingKey;
 17543    }
 44
 45    public string? ToText(BaseInstruction instruction)
 19146    {
 19147        var subsValues = new Dictionary<string, object>();
 48
 313549        foreach (var f in instruction.GetType().GetProperties())
 128150        {
 128151            if (!f.CanRead)
 052            {
 053                continue;
 54            }
 55
 128156            subsValues[f.Name.ToLower()] = f.GetValue(instruction);
 128157        }
 58
 19159        var resultText = new StringBuilder();
 103460        foreach (var (text, substitute) in _text)
 23261        {
 23262            if (substitute)
 11263            {
 11264                var firstChar = text.ToCharArray()[0];
 11265                if (firstChar == '.' || firstChar == '+' || firstChar == '-')
 766                {
 767                    var key = text.Substring(1);
 768                    var index = 0;
 769                    switch (firstChar)
 70                    {
 71                        case '+':
 272                            index = instruction.ShapeIndexEnd;
 273                            break;
 74                        case '-':
 075                            index = instruction.ShapeIndex - 1;
 076                            break;
 77                        case '.':
 578                            index = instruction.ShapeIndex;
 579                            break;
 80                    }
 81
 782                    if (index >= instruction.Route?.Meta?.Count)
 083                    {
 084                        return null;
 85                    }
 86
 787                    var segment = instruction.Route?.Meta?[index]?.Attributes;
 788                    if (segment == null || !segment.TryGetValue(key, out var v))
 389                    {
 390                        if (_crashOnMissingKey)
 091                        {
 092                            throw new KeyNotFoundException("The segment does not contain a key  " + text +
 093                                                           ". The context is " + _context);
 94                        }
 95
 396                        return null;
 97                    }
 98
 499                    resultText.Append(v);
 4100                }
 105101                else if (subsValues.TryGetValue(text, out var newValue))
 98102                {
 98103                    if (newValue is BaseInstruction instr)
 0104                    {
 0105                        resultText.Append(_nestedToText.Content.ToText(instr));
 0106                    }
 107                    else
 98108                    {
 98109                        resultText.Append(newValue);
 98110                    }
 98111                }
 7112                else if (_extensions != null && _extensions.TryGetValue(text, out var subs))
 7113                {
 7114                    resultText.Append(subs.ToText(instruction));
 7115                }
 0116                else if (_crashOnMissingKey)
 0117                {
 0118                    throw new KeyNotFoundException(
 0119                        $"The instruction of type {instruction.Type} does not contain a field or extension with name {te
 120                }
 121                else
 0122                {
 0123                    return null;
 124                }
 109125            }
 126            else
 120127            {
 120128                resultText.Append(text);
 120129            }
 229130        }
 131
 188132        return resultText.ToString();
 191133    }
 134
 135    public override string ToString()
 0136    {
 0137        return string.Join("", _text.Select(txt => txt.textOrVarName));
 0138    }
 139
 140    public int SubstitutedValueCount()
 14141    {
 28142        return _text.Count(v => v.substitute);
 14143    }
 144}