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

loresoft / EntityFrameworkCore.Generator / 27827701138

19 Jun 2026 01:10PM UTC coverage: 71.692% (-0.07%) from 71.762%
27827701138

push

github

pwelter34
Handle exceptions in commands

985 of 1863 branches covered (52.87%)

Branch coverage included in aggregate %.

14 of 52 new or added lines in 3 files covered. (26.92%)

1 existing line in 1 file now uncovered.

4217 of 5393 relevant lines covered (78.19%)

1276.45 hits per line

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

0.0
/src/EntityFrameworkCore.Generator/ColorConsoleFormatter.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Globalization;
4
using System.Text;
5

6
using Microsoft.Extensions.Logging;
7
using Microsoft.Extensions.Logging.Abstractions;
8
using Microsoft.Extensions.Logging.Console;
9
using Microsoft.Extensions.Options;
10

11
namespace EntityFrameworkCore.Generator;
12

13
public class ColorConsoleFormatter(IOptionsMonitor<SimpleConsoleFormatterOptions> options)
14
    : ConsoleFormatter(FormatterName)
×
15
{
16
    public const string FormatterName = "colorFormatter";
17

18
    protected SimpleConsoleFormatterOptions FormatterOptions { get; } = options.CurrentValue;
19

20
    public override void Write<TState>(in LogEntry<TState> logEntry, IExternalScopeProvider? scopeProvider, TextWriter textWriter)
21
    {
22
        var message = logEntry.Formatter(logEntry.State, logEntry.Exception);
×
23
        if (string.IsNullOrEmpty(message))
×
24
            return;
×
25

26
        if (!string.IsNullOrEmpty(FormatterOptions.TimestampFormat))
×
27
        {
28
            var timestamp = DateTimeOffset.Now.ToString(FormatterOptions.TimestampFormat);
×
29
            textWriter.Write(timestamp);
×
30
        }
31

32
        WriteWithColor(
×
33
            writer: textWriter,
×
34
            value: GetLevelText(logEntry.LogLevel),
×
35
            color: GetLevelColor(logEntry.LogLevel));
×
36

37
        textWriter.Write(": ");
×
38
        WriteMessage(textWriter, message, logEntry.State);
×
39
        textWriter.WriteLine();
×
40

41
        if (logEntry.Exception is not null)
×
42
        {
43
            WriteWithColor(textWriter, logEntry.Exception.ToString(), ConsoleColor.Red);
×
44
            textWriter.WriteLine();
×
45
        }
46
    }
×
47

48

49
    private void WriteWithColor(TextWriter writer, string value, ConsoleColor color)
50
    {
51
        if (FormatterOptions.ColorBehavior == LoggerColorBehavior.Disabled)
×
52
            writer.Write(value);
×
53
        else
54
            writer.WriteWithColor(value, background: null, foreground: color);
×
55
    }
×
56

57
    private void WriteMessage<TState>(TextWriter writer, string message, TState state)
58
    {
59
        if (FormatterOptions.ColorBehavior == LoggerColorBehavior.Disabled
×
60
            || !TryGetTemplateValues(state, out var messageTemplate, out var values)
×
61
            || values.Count == 0)
×
62
        {
63
            writer.Write(message);
×
64
            return;
×
65
        }
66

67
        var template = messageTemplate.AsSpan();
×
68
        var valueIndex = 0;
×
69
        var literalStart = 0;
×
70

71
        for (var index = 0; index < template.Length; index++)
×
72
        {
73
            var current = template[index];
×
74
            if (current == '{')
×
75
            {
76
                if (index + 1 < template.Length && template[index + 1] == '{')
×
77
                {
78
                    writer.Write(template[literalStart..index]);
×
79
                    writer.Write('{');
×
80
                    index++;
×
81
                    literalStart = index + 1;
×
82

83
                    continue;
×
84
                }
85

86
                var closeIndex = template[(index + 1)..].IndexOf('}');
×
87
                if (closeIndex < 0 || valueIndex >= values.Count)
×
88
                    continue;
89

90
                closeIndex += index + 1;
×
91

92
                writer.Write(template[literalStart..index]);
×
93

94
                var placeholder = template[(index + 1)..closeIndex];
×
95
                var value = FormatValue(values[valueIndex].Value, placeholder);
×
96

97
                WriteWithColor(writer, value, ConsoleColor.Cyan);
×
98

99
                valueIndex++;
×
100
                index = closeIndex;
×
101
                literalStart = index + 1;
×
102
            }
103
            else if (current == '}' && index + 1 < template.Length && template[index + 1] == '}')
×
104
            {
105
                writer.Write(template[literalStart..index]);
×
106
                writer.Write('}');
×
107

108
                index++;
×
109
                literalStart = index + 1;
×
110
            }
111
        }
112

113
        if (literalStart < template.Length)
×
114
            writer.Write(template[literalStart..]);
×
115
    }
×
116

117
    private static bool TryGetTemplateValues<TState>(
118
        TState state,
119
        out string messageTemplate,
120
        out List<KeyValuePair<string, object?>> values)
121
    {
122
        messageTemplate = string.Empty;
×
123
        values = [];
×
124

125
        if (state is not IEnumerable<KeyValuePair<string, object?>> properties)
×
126
            return false;
×
127

128
        foreach (var property in properties)
×
129
        {
130
            if (property.Key == "{OriginalFormat}" && property.Value is string originalFormat)
×
131
            {
132
                messageTemplate = originalFormat;
×
133
                continue;
×
134
            }
135

136
            values.Add(property);
×
137
        }
138

139
        return !string.IsNullOrEmpty(messageTemplate);
×
140
    }
141

142
    private static string FormatValue(object? value, ReadOnlySpan<char> placeholder)
143
    {
144
        var formatStart = placeholder.IndexOfAny(',', ':');
×
145
        var argument = FormatArgument(value);
×
146

147
        if (formatStart < 0)
×
148
            return Convert.ToString(argument, CultureInfo.InvariantCulture) ?? string.Empty;
×
149

150
        try
151
        {
152
            return string.Format(CultureInfo.InvariantCulture, $"{{0{placeholder[formatStart..]}}}", argument);
×
153
        }
154
        catch (FormatException)
×
155
        {
156
            return Convert.ToString(argument, CultureInfo.InvariantCulture) ?? string.Empty;
×
157
        }
158
    }
×
159

160
    private static object FormatArgument(object? value)
161
    {
162
        if (value is null)
×
163
            return "(null)";
×
164

165
        if (value is string)
×
166
            return value;
×
167

168
        if (value is not System.Collections.IEnumerable enumerable)
×
169
            return value;
×
170

171
        var builder = new StringBuilder();
×
172
        foreach (var item in enumerable)
×
173
        {
174
            if (builder.Length > 0)
×
175
                builder.Append(", ");
×
176

177
            builder.Append(item ?? "(null)");
×
178
        }
179

180
        return builder.ToString();
×
181
    }
182

183
    private static string GetLevelText(LogLevel level)
184
        => level switch
×
185
        {
×
186
            LogLevel.Trace => "T",
×
187
            LogLevel.Debug => "D",
×
188
            LogLevel.Information => "I",
×
189
            LogLevel.Warning => "W",
×
190
            LogLevel.Error => "E",
×
191
            LogLevel.Critical => "F",
×
NEW
192
            _ => "T"
×
193
        };
×
194

195
    private static ConsoleColor GetLevelColor(LogLevel level)
196
        => level switch
×
197
        {
×
198
            LogLevel.Trace => ConsoleColor.DarkGray,
×
199
            LogLevel.Debug => ConsoleColor.DarkCyan,
×
200
            LogLevel.Information => ConsoleColor.Green,
×
201
            LogLevel.Warning => ConsoleColor.Yellow,
×
202
            LogLevel.Error => ConsoleColor.Red,
×
203
            LogLevel.Critical => ConsoleColor.Magenta,
×
204
            _ => ConsoleColor.Gray
×
205
        };
×
206
}
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