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

alunacjones / LSL.VariableReplacer / 69

13 Feb 2026 03:42PM UTC coverage: 99.234% (-0.3%) from 99.576%
69

push

appveyor

alunacjones
fix null issue and enumerable stack overflow

259 of 261 relevant lines covered (99.23%)

57.48 hits per line

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

98.51
/LSL.VariableReplacer/CanAddVariablesExtensions.cs
1
using System;
2
using System.Collections;
3
using System.Collections.Generic;
4
using System.Linq;
5

6
namespace LSL.VariableReplacer;
7

8
/// <summary>
9
/// Extensions for ICanAddVariables
10
/// </summary>
11
public static class CanAddVariablesExtensions
12
{
13
    /// <summary>
14
    /// Adds a dictionary of variables
15
    /// to the configuration
16
    /// </summary>
17
    /// <typeparam name="TSelf"></typeparam>
18
    /// <param name="source"></param>
19
    /// <param name="variableDictionary"></param>
20
    /// <returns></returns>
21
    /// <exception cref="ArgumentException"></exception>
22
    public static TSelf AddVariables<TSelf>(this TSelf source, IDictionary<string, object> variableDictionary)
23
        where TSelf : ICanAddVariables<TSelf> =>
24
            Guard.IsNotNull(variableDictionary, nameof(variableDictionary))
11✔
25
                .Aggregate(source, (agg, i) => agg.AddVariable(i.Key, i.Value));
41✔
26

27
    /// <summary>
28
    /// Adds environment variables to the variables
29
    /// </summary>
30
    /// <typeparam name="TSelf"></typeparam>
31
    /// <param name="source"></param>
32
    /// <param name="environmentVariableFilter">
33
    /// An optional filter that is given the envionment variable
34
    /// key and returns <c>true</c> if it should be included
35
    /// </param>
36
    /// <param name="prefix">
37
    /// A prefix to apply to each variable's key. 
38
    /// The resultant key is <c>Prefix + Environment Variable Key</c>
39
    /// </param>
40
    /// <returns></returns>
41
    public static TSelf AddEnvironmentVariables<TSelf>(this TSelf source, Func<string, bool> environmentVariableFilter = null, string prefix = "ENV_")
42
        where TSelf : ICanAddVariables<TSelf> => 
43
        source.AddEnvironmentVariables(configuration =>
2✔
44
        {
2✔
45
            configuration
4✔
46
                .WithEnvironmentVariableFilter(environmentVariableFilter ?? (key => true))
106✔
47
                .WithPrefix(prefix);
4✔
48
        });
4✔
49

50
    /// <summary>
51
    /// Adds environment variables to the variables
52
    /// </summary>
53
    /// <typeparam name="TSelf"></typeparam>
54
    /// <param name="source"></param>
55
    /// <param name="configurator">A required configurator of the environment variable adder</param>
56
    /// <returns></returns>
57
    public static TSelf AddEnvironmentVariables<TSelf>(this TSelf source, Action<VariablesFromEnvironmentVariablesConfiguration> configurator)
58
        where TSelf : ICanAddVariables<TSelf>
59
    {
60
        var configuration = new VariablesFromEnvironmentVariablesConfiguration();
3✔
61
        Guard.IsNotNull(configurator, nameof(configurator)).Invoke(configuration);
3✔
62
        var validateVariableName = source.GetVariableNameValidator();
3✔
63
        var environmentVariables = Environment.GetEnvironmentVariables();
3✔
64

65
        return environmentVariables
3✔
66
            .Keys
3✔
67
            .OfType<object>()
3✔
68
            .Select(k => k.ToString())
316✔
69
            .Where(k => configuration.InvalidVariableNameFilterIsDisabled || validateVariableName(k).Succeeded)
316✔
70
            .Where(configuration.EnvironmentVariableFilter)
3✔
71
            .Select(key => new { key, value = environmentVariables[key].ToString() })
211✔
72
            .Aggregate(source, (agg, i) => agg.AddVariable($"{configuration.Prefix}{i.key}", i.value));
211✔
73
    }
74

75
    /// <summary>
76
    /// Adds all properties from an object
77
    /// </summary>
78
    /// <remarks>
79
    /// Any object properties will be recursively traversed
80
    /// </remarks>
81
    /// <typeparam name="TSelf"></typeparam>
82
    /// <param name="source"></param>
83
    /// <param name="value"></param>
84
    /// <param name="configurator"></param>
85
    /// <returns></returns>
86
    public static TSelf AddVariablesFromObject<TSelf>(this TSelf source, object value, Action<VariablesFromObjectConfiguration> configurator = null)
87
        where TSelf : ICanAddVariables<TSelf>
88
    {
89
        var configuration = new VariablesFromObjectConfiguration();
7✔
90
        configurator?.Invoke(configuration);
7✔
91

92
        return AddProperties(Guard.IsNotNull(value, nameof(value)), string.Empty);
7✔
93

94
        TSelf AddProperties(object value, string path) =>
95
            value.GetType()
16✔
96
                .GetProperties()
16✔
97
                .Aggregate(source, (agg, property) =>
16✔
98
                {
16✔
99
                    if (configuration.PrimitiveTypeChecker(property.PropertyType))
50✔
100
                    {
16✔
101
                        if (IncludeProperty()) source.AddVariable($"{configuration.Prefix}{MakePath()}", property.GetValue(value));
62✔
102
                        return agg;
40✔
103
                    }
16✔
104

16✔
105
                    var propertyValue = property.GetValue(value);
26✔
106

16✔
107
                    if (propertyValue is null) return agg;
×
108
                    
16✔
109
                    if (propertyValue is IEnumerable enumerable)
26✔
110
                    {
16✔
111
                        var index = 0;
18✔
112
                        foreach (var item in enumerable)
24✔
113
                        {
16✔
114
                            var itemType = item.GetType();
18✔
115
                            if (configuration.PrimitiveTypeChecker(itemType))
18✔
116
                            {
16✔
117
                                source.AddVariable($"{configuration.Prefix}{MakePath($".{index}")}", item);
17✔
118
                            }
16✔
119
                            else
16✔
120
                            {
16✔
121
                                AddProperties(item, MakePath($".{index}"));
17✔
122
                            }
16✔
123
                            index++;
18✔
124
                        }
16✔
125

16✔
126
                        return agg;
18✔
127
                    }
16✔
128

16✔
129
                    AddProperties(property.GetValue(value), MakePath());
24✔
130

16✔
131
                    return agg;
24✔
132

16✔
133
                    string MakePath(string suffix = null) =>
16✔
134
                        path.Length == 0 ? $"{property.Name}{suffix}" : $"{path}{configuration.PropertyPathSeparator}{property.Name}";
48✔
135

16✔
136
                    bool IncludeProperty() =>
16✔
137
                        configuration.PropertyFilter == null || configuration.PropertyFilter(new PropertyFilterContext(property, path));
40✔
138
                });
16✔
139
    }
140
}
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