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

LBreedlove / Queuebal.Expressions / 15764743049

19 Jun 2025 07:05PM UTC coverage: 89.113% (-0.7%) from 89.808%
15764743049

push

github

web-flow
Add range and declare_and_assign expressions (#3)

* Add range and declare_and_assign expressions

* Fix DeclareAndAssign expression

268 of 291 branches covered (92.1%)

Branch coverage included in aggregate %.

31 of 48 new or added lines in 3 files covered. (64.58%)

1590 of 1794 relevant lines covered (88.63%)

192.94 hits per line

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

84.85
/Queuebal.Json.Data/DataProvider.cs
1
using Queuebal.Json;
2

3
namespace Queuebal.Json.Data;
4

5

6
/// <summary>Provides disposable access to a data provider scope.</summary>
7
public class DataProviderScopeAccess : IDisposable
8
{
9
    /// <summary>Is the scope access disposed of yet.</summary>
10
    private int _disposed = 0;
11✔
11

12
    /// <summary>The DataProvider the scope was added to.</summary>
13
    private readonly DataProvider _dataProvider;
14

15
    /// <summary>The DataProviderScope that was added to the DataProvider.</summary>
16
    private readonly DataProviderScope _scope;
17

18
    /// <summary>
19
    /// Initializes a new instance of the DataProviderScopeAccess object, and pushes
20
    /// the scope onto the scope stack of the given DataProvider.
21
    /// </summary>
22
    /// <param name="dataProvider">The DataProvider to add the scope to.</param>
23
    /// <param name="scope">The scope to add to the DataProvider.</param>
24
    public DataProviderScopeAccess(DataProvider dataProvider, DataProviderScope scope)
11✔
25
    {
11✔
26
        _dataProvider = dataProvider;
11✔
27
        _scope = scope;
11✔
28

29
        _dataProvider.PushScope(scope);
11✔
30
    }
11✔
31

32
    ~DataProviderScopeAccess()
33
    {
×
34
        Dispose(false);
×
35
    }
×
36

37
    /// <summary>
38
    /// Gets the scope that was added to the DataProvider.
39
    /// </summary>
40
    public DataProviderScope Scope => _scope;
1✔
41

42
    /// <summary>
43
    /// Disposes of the DataProviderScopeAccess and removes the DataProviderScope from the DataProvider.
44
    /// </summary>
45
    public void Dispose()
46
    {
9✔
47
        Dispose(true);
9✔
48
    }
8✔
49

50
    /// <summary>
51
    /// Disposes of the DataProviderScopeAccess and removes the DataProviderScope from the DataProvider.
52
    /// </summary>
53
    private void Dispose(bool disposing)
54
    {
9✔
55
        if (Interlocked.CompareExchange(ref _disposed, 1, 0) != 0)
9✔
56
        {
×
57
            return;
×
58
        }
59

60
        if (disposing)
9✔
61
        {
9✔
62
            _dataProvider.RemoveScope(_scope);
9✔
63
        }
8✔
64
    }
8✔
65
}
66

67

68
/// <summary>
69
/// Defines a Scope for a DataProvider to store values in.
70
/// </summary>
71
public class DataProviderScope
72
{
73
    /// <summary>
74
    /// The name of the scope.
75
    /// </summary>
76
    private readonly string _scopeName;
77

78
    /// <summary>
79
    /// A map of values contained in the scope.
80
    /// </summary>
81
    private readonly Dictionary<string, JSONValue> _values = new();
110✔
82

83
    /// <summary>
84
    /// Initializes a new instance of a DataProviderScope, with the specified name.
85
    /// </summary>
86
    /// <param name="scopeName">The name of the new scope.</param>
87
    public DataProviderScope(string scopeName, Dictionary<string, JSONValue>? values = null)
110✔
88
    {
110✔
89
        _scopeName = scopeName;
110✔
90
        if (values != null)
110✔
91
        {
13✔
92
            foreach (var item in values)
67✔
93
            {
14✔
94
                _values.Add(item.Key, item.Value);
14✔
95
            }
14✔
96
        }
13✔
97
    }
110✔
98

99
    /// <summary>
100
    /// Gets the name of the DataProviderScope.
101
    /// </summary>
102
    public string Name => _scopeName;
10✔
103

104
    /// <summary>
105
    /// Sets the value for the specified key in the scope.
106
    /// </summary>
107
    /// <param name="key">The name of the variable to set.</param>
108
    /// <param name="newValue">The new value of the key.</param>
109
    /// <returns>true if the key was found, otherwise false.</returns>
110
    public bool SetValue(string key, JSONValue newValue)
NEW
111
    {
×
NEW
112
        if (_values.ContainsKey(key))
×
NEW
113
        {
×
NEW
114
            _values[key] = newValue;
×
NEW
115
            return true;
×
116
        }
117

NEW
118
        return false;
×
NEW
119
    }
×
120

121
    /// <summary>
122
    /// Adds a JSONValue to the scope.
123
    /// </summary>
124
    /// <param name="key">The key for the new value.</param>
125
    /// <param name="value">The value to add.</param>
126
    /// <returns>The current scope.</returns>
127
    /// <remarks>If a value with the given key already exists, it will be overwritten.</remarks>
128
    public DataProviderScope AddValue(string key, JSONValue value)
129
    {
26✔
130
        _values[key] = value;
26✔
131
        return this;
26✔
132
    }
26✔
133

134
    /// <summary>
135
    /// Adds a collection of JSONValue's to the scope.
136
    /// </summary>
137
    /// <param name="values">The values to add to the scope.</param>
138
    /// <returns>The current scope.</returns>
139
    /// <remarks>If a value with the given key already exists, it will be overwritten.</remarks>
140
    public DataProviderScope AddValues(Dictionary<string, JSONValue> values)
141
    {
2✔
142
        foreach (var keyValue in values)
14✔
143
        {
4✔
144
            AddValue(keyValue.Key, keyValue.Value);
4✔
145
        }
4✔
146

147
        return this;
2✔
148
    }
2✔
149

150
    /// <summary>
151
    /// Attempts to get the value with the specified key.
152
    /// </summary>
153
    /// <param name="key">The key of the value to lookup.</param>
154
    /// <returns>The value stored in the key, if the value is found, otherwise null.</returns>
155
    public JSONValue? GetValue(string key) =>
156
        _values.TryGetValue(key, out var value) ? value : null;
52✔
157
}
158

159

160
/// <summary>
161
/// Provides access to data stored in memory, using a stack of DataProviderScopes to
162
/// store and access values.
163
/// </summary>
164
public class DataProvider
165
{
166
    private readonly DataProviderScope _rootScope = new DataProviderScope("__root");
97✔
167
    private readonly List<DataProviderScope> _scopes = new();
97✔
168
    private readonly Dictionary<string, List<DataProviderScope>> _scopesMap = new();
97✔
169
    private DataProviderScope _currentScope;
170

171
    /// <summary>Initializes a new instance of the DataProvider class.</summary>
172
    public DataProvider()
97✔
173
    {
97✔
174
        _currentScope = _rootScope;
97✔
175
        _scopes.Add(_rootScope);
97✔
176
    }
97✔
177

178
    /// <summary>
179
    /// Sets the named variable in the first scope that contains the variable.
180
    /// If the variable is not found in any scope, a KeyNotFoundException is thrown.
181
    /// </summary>
182
    /// <param name="key">The name of the variable to set.</param>
183
    /// <param name="value">The value of the variable.</param>
184
    /// <returns>The new value of the variable.</returns>
185
    public JSONValue SetValue(string key, JSONValue newValue)
NEW
186
    {
×
NEW
187
        for (int idx = _scopes.Count - 1; idx >= 0; idx--)
×
NEW
188
        {
×
NEW
189
            var scope = _scopes[idx];
×
NEW
190
            if (scope.SetValue(key, newValue))
×
NEW
191
            {
×
192
                // If the value was set, return the new value.
NEW
193
                return newValue;
×
194
            }
NEW
195
        }
×
196

NEW
197
        throw new KeyNotFoundException($"The variable '{key}' was not found in any scope.");
×
NEW
198
    }
×
199

200
    /// <summary>
201
    /// Adds a value to the root scope.
202
    /// </summary>
203
    /// <param name="key">The key of the value to add.</param>
204
    /// <param name="value">The value to add.</param>
205
    /// <returns>The current DataProvider.</returns>
206
    /// <remarks>If a value with the given key already exists, it will be overwritten.</remarks>
207
    public DataProvider AddRootValue(string key, JSONValue value)
208
    {
6✔
209
        _rootScope.AddValue(key, value);
6✔
210
        return this;
6✔
211
    }
6✔
212

213
    /// <summary>
214
    /// Adds a dictionary of values to the root scope.
215
    /// </summary>
216
    /// <param name="values">The values to add to the root scope.</param>
217
    /// <returns>The current DataProvider.</returns>
218
    /// <remarks>If a value with the given key already exists, it will be overwritten.</remarks>
219
    public DataProvider AddRootValues(Dictionary<string, JSONValue> values)
220
    {
1✔
221
        _rootScope.AddValues(values);
1✔
222
        return this;
1✔
223
    }
1✔
224

225
    /// <summary>Adds a value to the current scope.</summary>
226
    /// <remarks>If a value with the given key already exists, it will be overwritten.</remarks>
227
    public DataProvider AddValue(string key, JSONValue value)
228
    {
14✔
229
        _currentScope.AddValue(key, value);
14✔
230
        return this;
14✔
231
    }
14✔
232

233
    /// <summary>
234
    /// Adds a dictionary of values to the current scope.
235
    /// </summary>
236
    /// <param name="values">The values to add to the current scope.</param>
237
    /// <returns>The current DataProvider.</returns>
238
    /// <remarks>If a value with the given key already exists, it will be overwritten.</remarks>
239
    public DataProvider AddValues(Dictionary<string, JSONValue> values)
240
    {
1✔
241
        _currentScope.AddValues(values);
1✔
242
        return this;
1✔
243
    }
1✔
244

245
    /// <summary>
246
    /// Adds a value to the scope that is the parent of the current scope.
247
    /// </summary>
248
    /// <param name="key">The name of the variable to add.</param>
249
    /// <param name="value">The value to assign to the variable.</param>
250
    /// <returns>The current DataProvider.</returns>
251
    /// <remarks>If the currentScope is the rootScope, the key/value will be added to the currentScope.</remarks>
252
    /// <remarks>If a value with the given key already exists, it will be overwritten.</remarks>
253
    public DataProvider AddParentValue(string key, JSONValue value)
254
    {
2✔
255
        if (_scopes.Count == 1)
2✔
256
        {
1✔
257
            // if we're at the rootScope, add the value here.
258
            _rootScope.AddValue(key, value);
1✔
259
            return this;
1✔
260
        }
261

262
        // get the second from the last element - the last element is currentScope, the second to the last is our parentScope.
263
        var scope = _scopes[^2];
1✔
264
        scope.AddValue(key, value);
1✔
265
        return this;
1✔
266
    }
2✔
267

268
    /// <summary>
269
    /// Adds a scope to the top of the scope stack.
270
    /// </summary>
271
    /// <param name="scope">The scope to add.</param>
272
    /// <returns>The current DataProvider.</returns>
273
    public DataProvider PushScope(DataProviderScope scope)
274
    {
14✔
275
        _scopes.Add(scope);
14✔
276
        _currentScope = scope;
14✔
277
        return this;
14✔
278
    }
14✔
279

280
    /// <summary>
281
    /// Removes the last scope added to the scopes stack.
282
    /// </summary>
283
    /// <returns>The current DataProvider.</returns>
284
    public DataProvider PopScope()
285
    {
4✔
286
        // we don't want to pop the root scope, so make sure there's
287
        // more than one scope registered.
288
        if (_scopes.Count > 1)
4✔
289
        {
2✔
290
            _scopes.RemoveAt(_scopes.Count - 1);
2✔
291
        }
2✔
292

293
        _currentScope = _scopes[^1];
4✔
294
        return this;
4✔
295
    }
4✔
296

297
    /// <summary>
298
    /// Removes the specified DataProviderScope from the stack of scopes.
299
    /// </summary>
300
    /// <param name="scope">The scope to remove.</param>
301
    /// <returns>The current DataProvider.</returns>
302
    public DataProvider RemoveScope(DataProviderScope scope)
303
    {
10✔
304
        // we expect the scope to be at the top of the stack, so check there first.
305
        if (scope == _rootScope)
10✔
306
        {
1✔
307
            throw new InvalidOperationException("Cannot remove the root scope from the DataProvider.");
1✔
308
        }
309

310
        if (_scopes[^1] == scope)
9✔
311
        {
7✔
312
            _scopes.RemoveAt(_scopes.Count - 1);
7✔
313
            return this;
7✔
314
        }
315

316
        if (!_scopes.Remove(scope))
2✔
317
        {
1✔
318
            throw new InvalidOperationException("The specified scope does not belong to the current DataProvider");
1✔
319
        }
320

321
        return this;
1✔
322
    }
8✔
323

324
    /// <summary>
325
    /// Adds a new scope to the scopes stack and returns an IDisposable
326
    /// to pop the scope off the stack when the caller is done using it.
327
    /// </summary>
328
    /// <param name="scopeName">The scope to add to the </param>
329
    /// <param name="values"></param>
330
    /// <returns></returns>
331
    public DataProviderScopeAccess WithScope(string scopeName, Dictionary<string, JSONValue>? values = null)
332
    {
10✔
333
        var scope = new DataProviderScope(scopeName, values);
10✔
334
        return new DataProviderScopeAccess(this, scope);
10✔
335
    }
10✔
336

337
    /// <summary>
338
    /// Attempts to get the value from the rootScope, with the specified key.
339
    /// </summary>
340
    /// <param name="key">The key of the value to retrieve.</param>
341
    /// <returns>A JSONValue containing the value, if the key is found, otherwise null.</returns>
342
    public JSONValue? GetRootValue(string key)
343
    {
1✔
344
        return _rootScope.GetValue(key);
1✔
345
    }
1✔
346

347
    /// <summary>
348
    /// Attempts to get the value from the current scope, with the specified key.
349
    /// The current scope is the last scope added to the stack.
350
    /// </summary>
351
    /// <param name="key">The name of the value to search for.</param>
352
    /// <returns>A JSONValue containing the value, if the key is found, otherwise null.</returns>
353
    public JSONValue? GetValueInCurrentScope(string key)
354
    {
2✔
355
        return _currentScope.GetValue(key);
2✔
356
    }
2✔
357

358
    /// <summary>
359
    /// Attempts to find the value with the specified key. The search
360
    /// is performed from the top of the scope stack to the root. If
361
    /// scopeName is provided, only scopes with the matching name will
362
    /// be searched.
363
    /// </summary>
364
    /// <param name="key">The key of the value to retrieve.</param>
365
    /// <param name="scopeName">The name of the scopes to include in the search.</param>
366
    /// <returns>A JSONValue if the value is found, otherwise null.</returns>
367
    public JSONValue? GetValue(string key, string? scopeName = null)
368
    {
49✔
369
        for (int idx = _scopes.Count - 1; idx >= 0; idx--)
110✔
370
        {
53✔
371
            var scope = _scopes[idx];
53✔
372
            if (scopeName == null || scopeName == scope.Name)
53✔
373
            {
49✔
374
                var value = scope.GetValue(key);
49✔
375
                if (value != null)
49✔
376
                {
47✔
377
                    return value;
47✔
378
                }
379
            }
2✔
380
        }
6✔
381

382
        return null;
2✔
383
    }
49✔
384
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc