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

ParadoxGameConverters / ImperatorToCK3 / 18510562823

14 Oct 2025 09:26PM UTC coverage: 48.963%. First build
18510562823

Pull #2771

github

web-flow
Merge 51e00a258 into 34d237707
Pull Request #2771: Catch unhandled exceptions from other threads

2389 of 5731 branches covered (41.69%)

Branch coverage included in aggregate %.

18 of 39 new or added lines in 1 file covered. (46.15%)

8588 of 16688 relevant lines covered (51.46%)

4768.5 hits per line

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

47.83
/ImperatorToCK3/Program.cs
1
using commonItems;
2
using ImperatorToCK3.Exceptions;
3
using log4net.Core;
4
using System;
5
using System.Globalization;
6
using System.Linq;
7
using System.Threading.Tasks;
8

9
namespace ImperatorToCK3;
10
public static class Program {
11
        public static int Main(string[] args) {
2✔
12
                RegisterGlobalExceptionHandlers();
2✔
13
                
14
                try {
2✔
15
                        SetInvariantCulture();
2✔
16

17
                        var converterVersion = new ConverterVersion();
2✔
18
                        converterVersion.LoadVersion("configurables/version.txt");
2✔
19
                        Logger.Info(converterVersion.ToString());
2✔
20
                        if (args.Length > 0) {
3✔
21
                                Logger.Warn("ImperatorToCK3 takes no parameters.\n" +
1✔
22
                                            "It uses configuration.txt, configured manually or by the frontend.");
1✔
23
                        }
1✔
24
                        Converter.ConvertImperatorToCK3(converterVersion);
2✔
25
                        return 0;
×
26
                } catch (Exception ex) {
4✔
27
                        // If the exception is an AggregateException, we want the original inner exception's stack trace.
28
                        if (ex is AggregateException aggregateEx) {
2!
29
                                ex = aggregateEx.Flatten().InnerExceptions.FirstOrDefault() ?? ex;
×
30
                        }
×
31

32
                        Logger.Log(Level.Fatal, ex is UserErrorException ? ex.Message : $"{ex.GetType()}: {ex.Message}");
2!
33
                        if (ex.StackTrace is not null) {
4✔
34
                                Logger.Debug(ex.StackTrace);
2✔
35
                        }
2✔
36

37
                        // Return exit code 1 for user errors. They should not be reported to Sentry.
38
                        if (ex is UserErrorException) {
2!
39
                                return 1;
×
40
                        }
41
                        return -1;
2✔
42
                }
43
        }
2✔
44

45
        private static void RegisterGlobalExceptionHandlers() {
2✔
46
                // Catch any unhandled exceptions from other threads.
47
                AppDomain.CurrentDomain.UnhandledException += (sender, eventArgs) => {
2✔
NEW
48
                        if (eventArgs.ExceptionObject is Exception ex) {
×
49
                                // If the exception is an AggregateException, we want the original inner exception's stack trace.
2✔
NEW
50
                                if (ex is AggregateException aggregateEx) {
×
NEW
51
                                        ex = aggregateEx.Flatten().InnerExceptions.FirstOrDefault() ?? ex;
×
NEW
52
                                }
×
53

2✔
NEW
54
                                Logger.Log(Level.Fatal, ex is UserErrorException ? ex.Message : $"{ex.GetType()}: {ex.Message}");
×
NEW
55
                                if (ex.StackTrace is not null) {
×
NEW
56
                                        Logger.Debug(ex.StackTrace);
×
NEW
57
                                }
×
NEW
58
                        } else {
×
NEW
59
                                Logger.Log(Level.Fatal, "An unhandled exception occurred, but it could not be identified.");
×
NEW
60
                        }
×
NEW
61
                        Environment.Exit(-1); // Ensure the process exits with a non-zero code.
×
62
                };
2✔
63
                TaskScheduler.UnobservedTaskException += (sender, eventArgs) => {
2✔
NEW
64
                        Exception ex = eventArgs.Exception;
×
65
                        // If the exception is an AggregateException, we want the original inner exception's stack trace.
2✔
NEW
66
                        if (ex is AggregateException aggregateEx) {
×
NEW
67
                                ex = aggregateEx.Flatten().InnerExceptions.FirstOrDefault() ?? ex;
×
NEW
68
                        }
×
69

2✔
NEW
70
                        Logger.Log(Level.Fatal, ex is UserErrorException ? ex.Message : $"{ex.GetType()}: {ex.Message}");
×
NEW
71
                        if (ex.StackTrace is not null) {
×
NEW
72
                                Logger.Debug(ex.StackTrace);
×
NEW
73
                        }
×
NEW
74
                        Environment.Exit(-1); // Ensure the process exits with a non-zero code.
×
75
                };
2✔
76
        }
2✔
77

78
        private static void SetInvariantCulture() {
2✔
79
                CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
2✔
80
                CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
2✔
81
                CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
2✔
82
                CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture;
2✔
83
        }
2✔
84
}
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