• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

loresoft / EntityChange / 14044984722

24 Mar 2025 08:13PM UTC coverage: 45.672% (-0.7%) from 46.358%
14044984722

push

github

pwelter34
bug fix

294 of 734 branches covered (40.05%)

Branch coverage included in aggregate %.

5 of 6 new or added lines in 1 file covered. (83.33%)

8 existing lines in 1 file now uncovered.

566 of 1149 relevant lines covered (49.26%)

73.53 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.14
/src/EntityChange/PathStack.cs
1
using System.Collections.Concurrent;
2
using System.IO;
3
using System.Text.Json.Serialization;
4

5
using EntityChange.Extensions;
6

7
namespace EntityChange;
8

9
/// <summary>
10
/// Path stack structure used to compute object graph paths expressions
11
/// </summary>
12
public class PathStack
13
{
14
    private readonly ConcurrentStack<PathValue> _pathStack = [];
34✔
15

16
    /// <summary>
17
    /// Push a property name to the stack
18
    /// </summary>
19
    /// <param name="propertyName">The name of the property</param>
20
    public void PushProperty(string propertyName)
21
        => _pathStack.Push(new(propertyName ?? string.Empty, Separator: '.'));
306!
22

23
    /// <summary>
24
    /// Push an indexer to the stack. Will be converted to string.
25
    /// </summary>
26
    /// <typeparam name="T">The type of the indexer</typeparam>
27
    /// <param name="index">The indexer value. Will be converted to string</param>
28
    public void PushIndex<T>(T index)
29
        => _pathStack.Push(new(index?.ToString() ?? string.Empty, Indexer: true));
31!
30

31
    /// <summary>
32
    /// Push a key indexer to the stack. Will be converted to string.
33
    /// </summary>
34
    /// <typeparam name="T">The type of the key indexer</typeparam>
35
    /// <param name="key">The key indexer value. Will be converted to string.</param>
36
    public void PushKey<T>(T key)
37
        => _pathStack.Push(new(key?.ToString() ?? string.Empty, Indexer: true));
10!
38

39
    /// <summary>
40
    /// Pop the last path off the stack
41
    /// </summary>
42
    public void Pop()
43
        => _pathStack.TryPop(out _);
339✔
44

45
    /// <summary>
46
    /// Clear the path stack
47
    /// </summary>
48
    public void Clear()
49
        => _pathStack.Clear();
27✔
50

51
    /// <summary>
52
    /// Gets the top path name from the stack.
53
    /// </summary>
54
    /// <returns>The top path name</returns>
55
    public string CurrentName()
56
    {
57
        if (_pathStack.IsEmpty)
72✔
58
            return string.Empty;
1✔
59

60
        if (!_pathStack.TryPeek(out var peeked))
71!
NEW
61
            return string.Empty;
×
62

63
        // not an indexer, use as is
64
        if (peeked.Indexer != true)
71✔
65
            return peeked.Name;
49✔
66

67
        // only item, use indexer path
68
        if (_pathStack.Count == 1)
22✔
69
            return $"[{peeked.Name}]";
2✔
70

71
        // add indexers till property is reached
72
        var paths = new List<PathValue>();
20✔
73
        foreach (var path in _pathStack)
102!
74
        {
75
            paths.Add(path);
41✔
76
            if (path.Indexer != true)
41✔
77
                break;
20✔
78
        }
79

80
        // create path expression
81
        return ToPath([.. paths]);
20✔
82
    }
83

84
    /// <summary>
85
    /// Gets the top property name from the stack
86
    /// </summary>
87
    /// <returns>The top property name</returns>
88
    public string CurrentProperty()
89
    {
90
        if (_pathStack.Count == 0)
9!
91
            return string.Empty;
×
92

93
        // find first none indexer path
94
        var lastProperty = _pathStack.FirstOrDefault(p => p.Indexer != true);
23✔
95
        return lastProperty.Name ?? string.Empty;
9✔
96
    }
97

98
    /// <inheritdoc/>
99
    public override string ToString()
100
    {
101
        var array = _pathStack.ToArray();
74✔
102
        return ToPath(array);
74✔
103
    }
104

105

106
    private static string ToPath(PathValue[] values)
107
    {
108
        var sb = StringBuilderCache.Acquire();
94✔
109

110
        // stack is in reverse order
111
        for (int i = values.Length - 1; i >= 0; i--)
518✔
112
        {
113
            var value = values[i];
165✔
114

115
            if (sb.Length > 0 && value.Separator.HasValue)
165✔
116
                sb.Append(value.Separator);
20✔
117

118
            if (value.Indexer == true)
165✔
119
                sb.Append('[').Append(value.Name).Append(']');
56✔
120
            else
121
                sb.Append(value.Name);
109✔
122
        }
123

124
        return StringBuilderCache.ToString(sb);
94✔
125
    }
126

127
    readonly record struct PathValue(string Name, char? Separator = null, bool? Indexer = false);
610✔
128
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc