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

ParadoxGameConverters / Fronter.NET / 14576273413

21 Apr 2025 03:35PM UTC coverage: 18.195% (-0.09%) from 18.281%
14576273413

Pull #866

github

web-flow
Merge 3641d4ae7 into 7b2140fe1
Pull Request #866: Fix 2 methods in Config.cs being too long

73 of 656 branches covered (11.13%)

Branch coverage included in aggregate %.

0 of 53 new or added lines in 1 file covered. (0.0%)

11 existing lines in 1 file now uncovered.

548 of 2757 relevant lines covered (19.88%)

9.29 hits per line

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

28.87
/Fronter.NET/Models/Configuration/Config.cs
1
using Avalonia.Controls.ApplicationLifetimes;
2
using commonItems;
3
using Fronter.Models.Configuration.Options;
4
using Fronter.ViewModels;
5
using log4net;
6
using System;
7
using System.Collections.Generic;
8
using System.Collections.ObjectModel;
9
using System.IO;
10
using System.Linq;
11

12
namespace Fronter.Models.Configuration;
13

14
internal sealed class Config {
15
        public string Name { get; private set; } = string.Empty;
13✔
16
        public string ConverterFolder { get; private set; } = string.Empty;
29✔
17
        public string BackendExePath { get; private set; } = string.Empty; // relative to ConverterFolder
13✔
18
        public string DisplayName { get; private set; } = string.Empty;
13✔
19
        public string SourceGame { get; private set; } = string.Empty;
13✔
20
        public string TargetGame { get; private set; } = string.Empty;
13✔
21
        public string? SentryDsn { get; private set; }
×
22
        public string? ModAutoGenerationSource { get; private set; } = null;
14✔
23
        public ObservableCollection<Mod> AutoLocatedMods { get; } = [];
16✔
24
        public bool CopyToTargetGameModDirectory { get; set; } = true;
6✔
25
        public ushort ProgressOnCopyingComplete { get; set; } = 109;
12✔
26
        public bool UpdateCheckerEnabled { get; private set; } = false;
13✔
27
        public bool CheckForUpdatesOnStartup { get; private set; } = false;
13✔
28
        public string ConverterReleaseForumThread { get; private set; } = string.Empty;
13✔
29
        public string LatestGitHubConverterReleaseUrl { get; private set; } = string.Empty;
13✔
30
        public string PagesCommitIdUrl { get; private set; } = string.Empty;
13✔
31
        public List<RequiredFile> RequiredFiles { get; } = [];
135✔
32
        public List<RequiredFolder> RequiredFolders { get; } = [];
153✔
33
        public List<Option> Options { get; } = [];
192✔
34
        private int optionCounter;
35

36
        private static readonly ILog logger = LogManager.GetLogger("Configuration");
1✔
37

38
        public Config() {
12✔
39
                var parser = new Parser();
6✔
40
                RegisterKeys(parser);
6✔
41
                var fronterConfigurationPath = Path.Combine("Configuration", "fronter-configuration.txt");
6✔
42
                if (File.Exists(fronterConfigurationPath)) {
12!
43
                        parser.ParseFile(fronterConfigurationPath);
6✔
44
                        logger.Info("Frontend configuration loaded.");
6✔
45
                } else {
6✔
46
                        logger.Warn($"{fronterConfigurationPath} not found!");
×
47
                }
×
48

49
                var fronterOptionsPath = Path.Combine("Configuration", "fronter-options.txt");
6✔
50
                if (File.Exists(fronterOptionsPath)) {
12!
51
                        parser.ParseFile(fronterOptionsPath);
6✔
52
                        logger.Info("Frontend options loaded.");
6✔
53
                } else {
6✔
54
                        logger.Warn($"{fronterOptionsPath} not found!");
×
55
                }
×
56

57
                InitializePaths();
6✔
58

59
                LoadExistingConfiguration();
6✔
60
        }
6✔
61

62
        private void RegisterKeys(Parser parser) {
6✔
63
                parser.RegisterKeyword("name", reader => Name = reader.GetString());
12✔
64
                parser.RegisterKeyword("sentryDsn", reader => SentryDsn = reader.GetString());
6✔
65
                parser.RegisterKeyword("converterFolder", reader => ConverterFolder = reader.GetString());
12✔
66
                parser.RegisterKeyword("backendExePath", reader => BackendExePath = reader.GetString());
12✔
67
                parser.RegisterKeyword("requiredFolder", reader => {
30✔
68
                        var newFolder = new RequiredFolder(reader, this);
24✔
69
                        if (!string.IsNullOrEmpty(newFolder.Name)) {
48✔
70
                                RequiredFolders.Add(newFolder);
24✔
71
                        } else {
24✔
72
                                logger.Error("Required Folder has no mandatory field: name!");
×
73
                        }
×
74
                });
30✔
75
                parser.RegisterKeyword("requiredFile", reader => {
12✔
76
                        var newFile = new RequiredFile(reader);
6✔
77
                        if (!string.IsNullOrEmpty(newFile.Name)) {
12✔
78
                                RequiredFiles.Add(newFile);
6✔
79
                        } else {
6✔
80
                                logger.Error("Required File has no mandatory field: name!");
×
81
                        }
×
82
                });
12✔
83
                parser.RegisterKeyword("option", reader => {
60✔
84
                        var newOption = new Option(reader, ++optionCounter);
54✔
85
                        Options.Add(newOption);
54✔
86
                });
60✔
87
                parser.RegisterKeyword("displayName", reader => DisplayName = reader.GetString());
12✔
88
                parser.RegisterKeyword("sourceGame", reader => SourceGame = reader.GetString());
12✔
89
                parser.RegisterKeyword("targetGame", reader => TargetGame = reader.GetString());
12✔
90
                parser.RegisterKeyword("autoGenerateModsFrom", reader => ModAutoGenerationSource = reader.GetString());
12✔
91
                parser.RegisterKeyword("copyToTargetGameModDirectory", reader => {
6✔
92
                        CopyToTargetGameModDirectory = reader.GetString().Equals("true");
×
93
                });
6✔
94
                parser.RegisterKeyword("progressOnCopyingComplete", reader => {
12✔
95
                        ProgressOnCopyingComplete = (ushort)reader.GetInt();
6✔
96
                });
12✔
97
                parser.RegisterKeyword("enableUpdateChecker", reader => {
12✔
98
                        UpdateCheckerEnabled = reader.GetString().Equals("true");
6✔
99
                });
12✔
100
                parser.RegisterKeyword("checkForUpdatesOnStartup", reader => {
12✔
101
                        CheckForUpdatesOnStartup = reader.GetString().Equals("true");
6✔
102
                });
12✔
103
                parser.RegisterKeyword("converterReleaseForumThread", reader => {
12✔
104
                        ConverterReleaseForumThread = reader.GetString();
6✔
105
                });
12✔
106
                parser.RegisterKeyword("latestGitHubConverterReleaseUrl", reader => {
12✔
107
                        LatestGitHubConverterReleaseUrl = reader.GetString();
6✔
108
                });
12✔
109
                parser.RegisterKeyword("pagesCommitIdUrl", reader => PagesCommitIdUrl = reader.GetString());
12✔
110
                parser.IgnoreAndLogUnregisteredItems();
6✔
111
        }
6✔
112

113
        private void RegisterPreloadKeys(Parser parser) {
8✔
114
                parser.RegisterRegex(CommonRegexes.String, (reader, incomingKey) => {
128✔
115
                        var valueStringOfItem = reader.GetStringOfItem();
120✔
116
                        var valueStr = valueStringOfItem.ToString().RemQuotes();
120✔
117
                        var valueReader = new BufferedReader(valueStr);
120✔
118

8✔
119
                        foreach (var folder in RequiredFolders) {
1,800✔
120
                                if (folder.Name.Equals(incomingKey) && Directory.Exists(valueStr)) {
480✔
121
                                        folder.Value = valueStr;
×
122
                                }
×
123
                        }
480✔
124

8✔
125
                        foreach (var file in RequiredFiles) {
720✔
126
                                if (file.Name.Equals(incomingKey) && File.Exists(valueStr)) {
120✔
127
                                        file.Value = valueStr;
×
128
                                }
×
129
                        }
120✔
130
                        foreach (var option in Options) {
3,600✔
131
                                if (option.Name.Equals(incomingKey) && option.CheckBoxSelector is null) {
1,152✔
132
                                        option.SetValue(valueStr);
72✔
133
                                } else if (option.Name.Equals(incomingKey) && option.CheckBoxSelector is not null) {
1,080✔
134
                                        var selections = valueReader.GetStrings();
×
135
                                        var values = selections.ToHashSet(StringComparer.Ordinal);
×
136
                                        option.SetValue(values);
×
137
                                        option.SetCheckBoxSelectorPreloaded();
×
138
                                }
×
139
                        }
1,080✔
140
                        if (incomingKey.Equals("selectedMods")) {
128✔
141
                                var theList = valueReader.GetStrings();
8✔
142
                                var matchingMods = AutoLocatedMods.Where(m => theList.Contains(m.FileName, StringComparer.Ordinal));
8✔
143
                                foreach (var mod in matchingMods) {
24✔
144
                                        mod.Enabled = true;
×
145
                                }
×
146
                        }
8✔
147
                });
128✔
148
                parser.RegisterRegex(CommonRegexes.Catchall, ParserHelpers.IgnoreAndLogItem);
8✔
149
        }
8✔
150

151
        private void InitializePaths() {
6✔
152
                if (!OperatingSystem.IsWindows()) {
12!
153
                        return;
6✔
154
                }
155

156
                string documentsDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
×
157
                InitializeFolders(documentsDir);
×
158
                InitializeFiles(documentsDir);
×
159
        }
6✔
160

161
        private void InitializeFolders(string documentsDir) {
×
162
                foreach (var folder in RequiredFolders) {
×
163
                        string? initialValue = null;
×
164

165
                        if (!string.IsNullOrEmpty(folder.Value)) {
×
166
                                continue;
×
167
                        }
168

169
                        if (folder.SearchPathType.Equals("windowsUsersFolder")) {
×
170
                                initialValue = Path.Combine(documentsDir, folder.SearchPath);
×
171
                        } else if (folder.SearchPathType.Equals("storeFolder")) {
×
172
                                string? possiblePath = null;
×
173
                                if (uint.TryParse(folder.SteamGameId, out uint steamId)) {
×
174
                                        possiblePath = CommonFunctions.GetSteamInstallPath(steamId);
×
175
                                }
×
176
                                if (possiblePath is null && long.TryParse(folder.GOGGameId, out long gogId)) {
×
177
                                        possiblePath = CommonFunctions.GetGOGInstallPath(gogId);
×
178
                                }
×
179

180
                                if (possiblePath is null) {
×
181
                                        continue;
×
182
                                }
183

184
                                initialValue = possiblePath;
×
185
                                if (!string.IsNullOrEmpty(folder.SearchPath)) {
×
186
                                        initialValue = Path.Combine(initialValue, folder.SearchPath);
×
187
                                }
×
188
                        } else if (folder.SearchPathType.Equals("direct")) {
×
189
                                initialValue = folder.SearchPath;
×
190
                        }
×
191

192
                        if (Directory.Exists(initialValue)) {
×
193
                                folder.Value = initialValue;
×
194
                        }
×
195

196
                        if (folder.Name.Equals(ModAutoGenerationSource)) {
×
197
                                AutoLocateMods();
×
198
                        }
×
199
                }
×
200
        }
×
201

202
        private void InitializeFiles(string documentsDir) {
×
203
                foreach (var file in RequiredFiles) {
×
204
                        string? initialDirectory = null;
×
205
                        string? initialValue = null;
×
206

207
                        if (!string.IsNullOrEmpty(file.Value)) {
×
208
                                initialDirectory = CommonFunctions.GetPath(file.Value);
×
209
                        } else if (file.SearchPathType.Equals("windowsUsersFolder")) {
×
210
                                initialDirectory = Path.Combine(documentsDir, file.SearchPath);
×
211
                                if (!string.IsNullOrEmpty(file.FileName)) {
×
212
                                        initialValue = Path.Combine(initialDirectory, file.FileName);
×
213
                                }
×
214
                        } else if (file.SearchPathType.Equals("converterFolder")) {
×
215
                                var currentDir = Directory.GetCurrentDirectory();
×
216
                                initialDirectory = Path.Combine(currentDir, file.SearchPath);
×
217
                                if (!string.IsNullOrEmpty(file.FileName)) {
×
218
                                        initialValue = Path.Combine(initialDirectory, file.FileName);
×
219
                                }
×
220
                        }
×
221

222
                        if (string.IsNullOrEmpty(file.Value) && File.Exists(initialValue)) {
×
223
                                file.Value = initialValue;
×
224
                        }
×
225

226
                        if (Directory.Exists(initialDirectory)) {
×
227
                                file.InitialDirectory = initialDirectory;
×
228
                        }
×
229
                }
×
230
        }
×
231

232
        public void LoadExistingConfiguration() {
8✔
233
                var parser = new Parser();
8✔
234
                RegisterPreloadKeys(parser);
8✔
235
                var converterConfigurationPath = Path.Combine(ConverterFolder, "configuration.txt");
8✔
236
                if (string.IsNullOrEmpty(ConverterFolder) || !File.Exists(converterConfigurationPath)) {
8!
237
                        return;
×
238
                }
239

240
                logger.Info("Previous configuration located, preloading selections...");
8✔
241
                parser.ParseFile(converterConfigurationPath);
8✔
242
        }
8✔
243

244
        public bool ExportConfiguration() {
×
245
                SetSavingStatus("CONVERTSTATUSIN");
×
246

247
                if (string.IsNullOrEmpty(ConverterFolder)) {
×
248
                        logger.Error("Converter folder is not set!");
×
249
                        SetSavingStatus("CONVERTSTATUSPOSTFAIL");
×
250
                        return false;
×
251
                }
252
                if (!Directory.Exists(ConverterFolder)) {
×
253
                        logger.Error("Could not find converter folder!");
×
254
                        SetSavingStatus("CONVERTSTATUSPOSTFAIL");
×
255
                        return false;
×
256
                }
257

258
                var outConfPath = Path.Combine(ConverterFolder, "configuration.txt");
×
259
                try {
×
260
                        using var writer = new StreamWriter(outConfPath);
×
NEW
261
                        WriteRequiredFolders(writer);
×
NEW
262
                        WriteRequiredFiles(writer);
×
263

264
                        if (ModAutoGenerationSource is not null) {
×
NEW
265
                                WriteSelectedMods(writer);
×
266
                        }
×
267

NEW
268
                        WriteOptions(writer);
×
269

270
                        SetSavingStatus("CONVERTSTATUSPOSTSUCCESS");
×
271
                        return true;
×
272
                } catch (Exception ex) {
×
273
                        logger.Error($"Could not open configuration.txt! Error: {ex}");
×
274
                        SetSavingStatus("CONVERTSTATUSPOSTFAIL");
×
275
                        return false;
×
276
                }
277
        }
×
278

279
        private void WriteSelectedMods(StreamWriter writer)
NEW
280
        {
×
NEW
281
                writer.WriteLine("selectedMods = {");
×
NEW
282
                foreach (var mod in AutoLocatedMods) {
×
NEW
283
                        if (mod.Enabled) {
×
NEW
284
                                writer.WriteLine($"\t\"{mod.FileName}\"");
×
NEW
285
                        }
×
NEW
286
                }
×
NEW
287
                writer.WriteLine("}");
×
NEW
288
        }
×
289

290
        private void WriteOptions(StreamWriter writer)
NEW
291
        {
×
NEW
292
                foreach (var option in Options) {
×
NEW
293
                        if (option.CheckBoxSelector is not null) {
×
NEW
294
                                writer.Write($"{option.Name} = {{ ");
×
NEW
295
                                foreach (var value in option.GetValues()) {
×
NEW
296
                                        writer.Write($"\"{value}\" ");
×
NEW
297
                                }
×
NEW
298
                                writer.WriteLine("}");
×
NEW
299
                        } else {
×
NEW
300
                                writer.WriteLine($"{option.Name} = \"{option.GetValue()}\"");
×
NEW
301
                        }
×
NEW
302
                }
×
NEW
303
        }
×
304

305
        private void WriteRequiredFiles(StreamWriter writer)
NEW
306
        {
×
NEW
307
                foreach (var file in RequiredFiles) {
×
NEW
308
                        if (!file.Outputtable) {
×
NEW
309
                                continue;
×
310
                        }
311
                        // In the file path, replace backslashes with forward slashes.
NEW
312
                        string pathToWrite = file.Value.Replace('\\', '/');
×
NEW
313
                        writer.WriteLine($"{file.Name} = \"{pathToWrite}\"");
×
NEW
314
                }
×
NEW
315
        }
×
316

317
        private void WriteRequiredFolders(StreamWriter writer)
NEW
318
        {
×
NEW
319
                foreach (var folder in RequiredFolders) {
×
320
                        // In the folder path, replace backslashes with forward slashes.
NEW
321
                        string pathToWrite = folder.Value.Replace('\\', '/');
×
NEW
322
                        writer.WriteLine($"{folder.Name} = \"{pathToWrite}\"");
×
NEW
323
                }
×
NEW
324
        }
×
325

326
        private static void SetSavingStatus(string locKey) {
×
327
                if (Avalonia.Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) {
×
UNCOV
328
                        return;
×
329
                }
330

331
                if (desktop.MainWindow?.DataContext is MainWindowViewModel mainWindowDataContext) {
×
332
                        mainWindowDataContext.SaveStatus = locKey;
×
333
                }
×
UNCOV
334
        }
×
335

336
        public void AutoLocateMods() {
×
337
                logger.Debug("Clearing previously located mods...");
×
338
                AutoLocatedMods.Clear();
×
UNCOV
339
                logger.Debug("Autolocating mods...");
×
340

341
                // Do we have a mod path?
342
                string? modPath = null;
×
343
                foreach (var folder in RequiredFolders) {
×
344
                        if (folder.Name.Equals(ModAutoGenerationSource)) {
×
345
                                modPath = folder.Value;
×
346
                        }
×
347
                }
×
348
                if (modPath is null) {
×
349
                        logger.Warn("No folder found as source for mods autolocation.");
×
UNCOV
350
                        return;
×
351
                }
352

353
                // Does it exist?
354
                if (!Directory.Exists(modPath)) {
×
355
                        logger.Warn($"Mod path \"{modPath}\" does not exist or can not be accessed!");
×
UNCOV
356
                        return;
×
357
                }
358

359
                // Are we looking at documents directory?
360
                var combinedPath = Path.Combine(modPath, "mod");
×
361
                if (Directory.Exists(combinedPath)) {
×
362
                        modPath = combinedPath;
×
363
                }
×
UNCOV
364
                logger.Debug($"Mods autolocation path set to: \"{modPath}\"");
×
365

366
                // Are there mods inside?
367
                List<string> validModFiles = GetValidModFiles(modPath);
×
368

369
                if (validModFiles.Count == 0) {
×
370
                        logger.Debug($"No mod files could be found in \"{modPath}\"");
×
UNCOV
371
                        return;
×
372
                }
373

374
                foreach (var modFile in validModFiles) {
×
UNCOV
375
                        var path = Path.Combine(modPath, modFile);
×
376
                        Mod theMod;
377
                        try {
×
378
                                theMod = new Mod(path);
×
379
                        } catch (IOException ex) {
×
380
                                logger.Warn($"Failed to parse mod file {modFile}: {ex.Message}");
×
UNCOV
381
                                continue;
×
382
                        }
383
                        if (string.IsNullOrEmpty(theMod.Name)) {
×
384
                                logger.Warn($"Mod at \"{path}\" has no defined name, skipping.");
×
UNCOV
385
                                continue;
×
386
                        }
387
                        AutoLocatedMods.Add(theMod);
×
388
                }
×
389
                logger.Debug($"Autolocated {AutoLocatedMods.Count} mods");
×
NEW
390
        }
×
391

NEW
392
        private static List<string> GetValidModFiles(string modPath) {
×
NEW
393
                var validModFiles = new List<string>();
×
NEW
394
                foreach (var file in SystemUtils.GetAllFilesInFolder(modPath)) {
×
NEW
395
                        var lastDot = file.LastIndexOf('.');
×
NEW
396
                        if (lastDot == -1) {
×
NEW
397
                                continue;
×
398
                        }
399

NEW
400
                        var extension = CommonFunctions.GetExtension(file);
×
NEW
401
                        if (!extension.Equals("mod")) {
×
NEW
402
                                continue;
×
403
                        }
404

NEW
405
                        validModFiles.Add(file);
×
NEW
406
                }
×
407

NEW
408
                return validModFiles;
×
UNCOV
409
        }
×
410
}
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