Skip to content

Commit 15888dc

Browse files
committed
Merge branch 'gitversionupdate' of https://github.com/LogExperts/LogExpert into gitversionupdate
2 parents c7fee7d + 60d363a commit 15888dc

14 files changed

Lines changed: 237 additions & 65 deletions

File tree

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@ Summary of (most) features:
2626

2727
## Download
2828

29-
Follow the [Link](https://github.com/LogExperts/LogExpert/releases/latest) and download the latest package. Just extract it where you want and execute the application or download the Setup and install it
30-
31-
Or Install via chocolatey
32-
33-
```choco install logexpert```
29+
* Follow the [Link](https://github.com/LogExperts/LogExpert/releases/latest) and download the latest package. Just extract it where you want and execute the application or download the Setup and install it
30+
* Install via chocolatey
31+
```choco install logexpert```
32+
* get the Nuget package [Link](https://www.nuget.org/packages/logexpert)
33+
```dotnet add package logexpert --version 1.30.0```
34+
* the ColumnizerLib can also be downloaded via nuget [Link](https://www.nuget.org/packages/ColumnizerLib)
35+
```dotnet add package ColumnizerLib --version 1.21.0```
3436

3537
Requirements
3638

src/Directory.Build.props

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
<Project>
22
<PropertyGroup>
3-
<Version>1.21.0.0</Version>
4-
<AssemblyVersion>1.21.0.0</AssemblyVersion>
5-
<FileVersion>1.21.0.0</FileVersion>
6-
<InformationalVersion>1.20.0.0</InformationalVersion>
3+
<Version>1.31.0.0</Version>
4+
<AssemblyVersion>1.31.0.0</AssemblyVersion>
5+
<FileVersion>1.31.0.0</FileVersion>
6+
<InformationalVersion>1.31.0.0</InformationalVersion>
77
<Authors>Hirogen, zarunbal, RandallFlagg, TheNicker</Authors>
8-
<Company>Log Expert</Company>
8+
<Company>LogExperts</Company>
99
<ImplicitUsings>enable</ImplicitUsings>
1010
<Nullable>enable</Nullable>
11-
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
11+
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
1212
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
1313
<AssemblyOriginatorKeyFile>..\Solution Items\Key.snk</AssemblyOriginatorKeyFile>
1414
<PublishAot>false</PublishAot>
@@ -21,8 +21,8 @@
2121
<RepositoryUrl>https://github.com/LogExperts/LogExpert</RepositoryUrl>
2222
<PackageTags>LogExpert, Columnizer, Logging, Windows, Winforms</PackageTags>
2323
<RepositoryType>git</RepositoryType>
24-
<PackageReleaseNotes>https://github.com/LogExperts/LogExpert/releases/tag/v.1.20.0</PackageReleaseNotes>
25-
<PackageVersion>1.21.0.0</PackageVersion>
24+
<PackageReleaseNotes>https://github.com/LogExperts/LogExpert/releases/tag/v.1.31.0</PackageReleaseNotes>
25+
<PackageVersion>1.31.0.0</PackageVersion>
2626
<Optimize Condition="'$(Configuration)' == 'Release'">true</Optimize>
2727
<Product>LogExpert</Product>
2828
<Copyright>Copyright © LogExpert 2025</Copyright>

src/LogExpert.Core/Classes/Log/RolloverFilenameHandler.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,13 @@ public RolloverFilenameHandler(ILogFileInfo logFileInfo, MultiFileOptions option
5252
public LinkedList<string> GetNameList(IPluginRegistry pluginRegistry)
5353
{
5454
LinkedList<string> fileList = new();
55+
5556
var fileName = _filenameBuilder.BuildFileName();
5657
var filePath = _logFileInfo.DirectoryName + _logFileInfo.DirectorySeparatorChar + fileName;
57-
fileList.AddFirst(filePath);
58+
_ = fileList.AddFirst(filePath);
59+
5860
var found = true;
61+
5962
while (found)
6063
{
6164
found = false;
@@ -67,11 +70,12 @@ public LinkedList<string> GetNameList(IPluginRegistry pluginRegistry)
6770
filePath = _logFileInfo.DirectoryName + _logFileInfo.DirectorySeparatorChar + fileName;//TODO: Change to Directory.Combine
6871
if (FileExists(filePath, pluginRegistry))
6972
{
70-
fileList.AddFirst(filePath);
73+
_ = fileList.AddFirst(filePath);
7174
found = true;
7275
continue;
7376
}
7477
}
78+
7579
// if file with index isn't found or no index is in format pattern, decrement the current date
7680
if (_filenameBuilder.IsDatePattern)
7781
{
@@ -84,7 +88,7 @@ public LinkedList<string> GetNameList(IPluginRegistry pluginRegistry)
8488
filePath = _logFileInfo.DirectoryName + _logFileInfo.DirectorySeparatorChar + fileName;//TODO: Change to Directory.Combine
8589
if (FileExists(filePath, pluginRegistry))
8690
{
87-
fileList.AddFirst(filePath);
91+
_ = fileList.AddFirst(filePath);
8892
found = true;
8993
break;
9094
}
@@ -104,8 +108,14 @@ public LinkedList<string> GetNameList(IPluginRegistry pluginRegistry)
104108
private bool FileExists(string filePath, IPluginRegistry pluginRegistry)
105109
{
106110
var fs = pluginRegistry.FindFileSystemForUri(filePath);
111+
112+
if(fs == null)
113+
{
114+
return false;
115+
}
116+
107117
var info = fs.GetLogfileInfo(filePath);
108-
return info.FileExists;
118+
return info is not null && info.FileExists;
109119
}
110120

111121
#endregion

src/LogExpert.Resources/Resources.Designer.cs

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/LogExpert.Resources/Resources.de.resx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2134,18 +2134,18 @@ LogExpert neu starten, um die Änderungen zu übernehmen?</value>
21342134
<value>TabController ist bereits mit einem DockPanel initialisiert</value>
21352135
</data>
21362136
<data name="SettingsDialog_UI_PortableMode_Title" xml:space="preserve">
2137-
<value>Tragbarer Modus</value>
2137+
<value>Portable Modus</value>
21382138
</data>
21392139
<data name="SettingsDialog_UI_PortableMode_CopySettingsQuestion" xml:space="preserve">
2140-
<value>Der tragbare Modus konnte nicht aktiviert werden: {0}</value>
2140+
<value>Möchten Sie Ihre aktuellen Einstellungen in den Portable-Modus Konfigurationsordner kopieren?</value>
21412141
</data>
21422142
<data name="SettingsDialog_UI_PortableMode_MoveSettingsQuestion" xml:space="preserve">
2143-
<value>Möchten Sie Ihre aktuellen Einstellungen in den tragbaren Konfigurationsordner kopieren?</value>
2143+
<value>Möchten Sie die tragbaren Einstellungen zurück in den Standardkonfigurationsordner (%APPDATA%\LogExpert) verschieben?</value>
21442144
</data>
21452145
<data name="SettingsDialog_UI_PortableMode_ActivationError" xml:space="preserve">
2146-
<value>Einige Dateien konnten nicht migriert werden: {0}</value>
2146+
<value>Der Portable Modus konnte nicht aktiviert werden: {0}</value>
21472147
</data>
21482148
<data name="SettingsDialog_UI_PortableMode_MigrationError" xml:space="preserve">
2149-
<value>Möchten Sie die tragbaren Einstellungen zurück in den Standardkonfigurationsordner (%APPDATA%\LogExpert) verschieben?</value>
2149+
<value>Einige Dateien konnten nicht migriert werden: {0}</value>
21502150
</data>
21512151
</root>

src/LogExpert.Resources/Resources.resx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2146,15 +2146,15 @@ Restart LogExpert to apply changes?</value>
21462146
<value>Portable Mode</value>
21472147
</data>
21482148
<data name="SettingsDialog_UI_PortableMode_CopySettingsQuestion" xml:space="preserve">
2149-
<value>Failed to activate portable mode: {0}</value>
2149+
<value>Do you want to copy your current settings to the portable configuration folder?</value>
21502150
</data>
21512151
<data name="SettingsDialog_UI_PortableMode_MoveSettingsQuestion" xml:space="preserve">
2152-
<value>Do you want to copy your current settings to the portable configuration folder?</value>
2152+
<value>Do you want to move the portable settings back to the default configuration folder (%APPDATA%\LogExpert)?</value>
21532153
</data>
21542154
<data name="SettingsDialog_UI_PortableMode_ActivationError" xml:space="preserve">
2155-
<value>Some files could not be migrated: {0}</value>
2155+
<value>Failed to activate portable mode: {0}</value>
21562156
</data>
21572157
<data name="SettingsDialog_UI_PortableMode_MigrationError" xml:space="preserve">
2158-
<value>Do you want to move the portable settings back to the default configuration folder (%APPDATA%\LogExpert)?</value>
2158+
<value>Some files could not be migrated: {0}</value>
21592159
</data>
21602160
</root>

src/LogExpert.Resources/Resources.zh-CN.resx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2054,15 +2054,15 @@ YY[YY] = 年
20542054
<value>便携模式</value>
20552055
</data>
20562056
<data name="SettingsDialog_UI_PortableMode_CopySettingsQuestion" xml:space="preserve">
2057-
<value>无法激活便携模式:{0}</value>
2057+
<value>您想将当前设置复制到便携式配置文件夹吗?</value>
20582058
</data>
20592059
<data name="SettingsDialog_UI_PortableMode_MoveSettingsQuestion" xml:space="preserve">
2060-
<value>您想将当前设置复制到便携式配置文件夹吗?</value>
2060+
<value>您想要将可移植设置移回默认配置文件夹 (%APPDATA%\LogExpert) 吗?</value>
20612061
</data>
20622062
<data name="SettingsDialog_UI_PortableMode_ActivationError" xml:space="preserve">
2063-
<value>某些文件无法迁移:{0}</value>
2063+
<value>无法激活便携模式:{0}</value>
20642064
</data>
20652065
<data name="SettingsDialog_UI_PortableMode_MigrationError" xml:space="preserve">
2066-
<value>您想要将可移植设置移回默认配置文件夹 (%APPDATA%\LogExpert) 吗?</value>
2066+
<value>某些文件无法迁移:{0}</value>
20672067
</data>
20682068
</root>
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
using ColumnizerLib;
2+
3+
using LogExpert.Core.Classes.Log;
4+
using LogExpert.Core.Entities;
5+
using LogExpert.Core.Interface;
6+
7+
using Moq;
8+
9+
using NUnit.Framework;
10+
11+
namespace LogExpert.Tests;
12+
13+
[TestFixture]
14+
internal class RolloverFilenameHandlerNullTests
15+
{
16+
/// <summary>
17+
/// Verifies that GetNameList does not throw when GetLogfileInfo returns null
18+
/// for rollover file candidates. This simulates the SFTP scenario where
19+
/// constructing SftpLogFileInfo fails for non-existent files.
20+
/// </summary>
21+
[Test]
22+
public void GetNameList_WhenGetLogfileInfoReturnsNull_DoesNotThrow ()
23+
{
24+
// Arrange: Create a mock ILogFileInfo for the "base" file
25+
var baseFileInfo = new Mock<ILogFileInfo>();
26+
_ = baseFileInfo.Setup(f => f.FileName).Returns("app.log");
27+
_ = baseFileInfo.Setup(f => f.DirectoryName).Returns("sftp://host/var/log");
28+
_ = baseFileInfo.Setup(f => f.DirectorySeparatorChar).Returns('/');
29+
_ = baseFileInfo.Setup(f => f.FileExists).Returns(true);
30+
31+
// Arrange: Create a mock IFileSystemPlugin that returns null for rollover files
32+
var mockFs = new Mock<IFileSystemPlugin>();
33+
_ = mockFs.Setup(fs => fs.CanHandleUri(It.IsAny<string>())).Returns(true);
34+
// Return null for any GetLogfileInfo call — simulates constructor failure
35+
_ = mockFs.Setup(fs => fs.GetLogfileInfo(It.IsAny<string>())).Returns((ILogFileInfo)null);
36+
37+
// Arrange: Create a mock IPluginRegistry
38+
var mockRegistry = new Mock<IPluginRegistry>();
39+
_ = mockRegistry.Setup(r => r.FindFileSystemForUri(It.IsAny<string>())).Returns(mockFs.Object);
40+
41+
MultiFileOptions options = new()
42+
{
43+
FormatPattern = "*$J(.)",
44+
MaxDayTry = 5
45+
};
46+
47+
RolloverFilenameHandler handler = new(baseFileInfo.Object, options);
48+
49+
// Act & Assert: Should not throw NullReferenceException
50+
LinkedList<string> result = null;
51+
Assert.DoesNotThrow(() => result = handler.GetNameList(mockRegistry.Object));
52+
53+
// The list should contain only the base file
54+
Assert.That(result, Is.Not.Null);
55+
Assert.That(result.Count, Is.EqualTo(1));
56+
Assert.That(result.First.Value, Does.Contain("app.log"));
57+
}
58+
59+
/// <summary>
60+
/// Verifies that GetNameList does not throw when FindFileSystemForUri returns null.
61+
/// This could happen with an unrecognized URI scheme.
62+
/// </summary>
63+
[Test]
64+
public void GetNameList_WhenFindFileSystemReturnsNull_DoesNotThrow ()
65+
{
66+
// Arrange
67+
var baseFileInfo = new Mock<ILogFileInfo>();
68+
_ = baseFileInfo.Setup(f => f.FileName).Returns("app.log");
69+
_ = baseFileInfo.Setup(f => f.DirectoryName).Returns("custom://host/logs");
70+
_ = baseFileInfo.Setup(f => f.DirectorySeparatorChar).Returns('/');
71+
_ = baseFileInfo.Setup(f => f.FileExists).Returns(true);
72+
73+
var mockRegistry = new Mock<IPluginRegistry>();
74+
_ = mockRegistry.Setup(r => r.FindFileSystemForUri(It.IsAny<string>())).Returns((IFileSystemPlugin)null);
75+
76+
MultiFileOptions options = new()
77+
{
78+
FormatPattern = "*$J(.)",
79+
MaxDayTry = 3
80+
};
81+
82+
RolloverFilenameHandler handler = new(baseFileInfo.Object, options);
83+
84+
// Act & Assert
85+
LinkedList<string> result = null;
86+
Assert.DoesNotThrow(() => result = handler.GetNameList(mockRegistry.Object));
87+
88+
Assert.That(result, Is.Not.Null);
89+
Assert.That(result.Count, Is.EqualTo(1));
90+
}
91+
92+
/// <summary>
93+
/// Verifies that GetNameList correctly finds rollover files when GetLogfileInfo
94+
/// returns a valid ILogFileInfo with FileExists = true. Ensures the null guard
95+
/// does not break the normal happy path.
96+
/// </summary>
97+
[Test]
98+
public void GetNameList_WhenRolloverFilesExist_ReturnsAllFiles ()
99+
{
100+
// Arrange: base file
101+
var baseFileInfo = new Mock<ILogFileInfo>();
102+
_ = baseFileInfo.Setup(f => f.FileName).Returns("app.log");
103+
_ = baseFileInfo.Setup(f => f.DirectoryName).Returns("/var/log");
104+
_ = baseFileInfo.Setup(f => f.DirectorySeparatorChar).Returns('/');
105+
106+
// Arrange: rollover file .log.1 exists, .log.2 does not
107+
var rollover1Info = new Mock<ILogFileInfo>();
108+
_ = rollover1Info.Setup(f => f.FileExists).Returns(true);
109+
110+
var mockFs = new Mock<IFileSystemPlugin>();
111+
_ = mockFs.Setup(fs => fs.CanHandleUri(It.IsAny<string>())).Returns(true);
112+
113+
// First call (for .log.1) returns a file that exists
114+
// Second call (for .log.2) returns null (simulating constructor failure)
115+
_ = mockFs.SetupSequence(fs => fs.GetLogfileInfo(It.IsAny<string>()))
116+
.Returns(rollover1Info.Object)
117+
.Returns((ILogFileInfo)null);
118+
119+
var mockRegistry = new Mock<IPluginRegistry>();
120+
_ = mockRegistry.Setup(r => r.FindFileSystemForUri(It.IsAny<string>())).Returns(mockFs.Object);
121+
122+
MultiFileOptions options = new()
123+
{
124+
FormatPattern = "*$J(.)",
125+
MaxDayTry = 3
126+
};
127+
128+
RolloverFilenameHandler handler = new(baseFileInfo.Object, options);
129+
130+
// Act
131+
var result = handler.GetNameList(mockRegistry.Object);
132+
133+
// Assert: base file + 1 rollover file
134+
Assert.That(result.Count, Is.EqualTo(2));
135+
}
136+
}

src/LogExpert.UI/Controls/LogWindow/LogWindow.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6302,7 +6302,7 @@ public PersistenceData GetPersistenceData ()
63026302
TabName = Text,
63036303
SessionFileName = SessionFileName,
63046304
Columnizer = CurrentColumnizer,
6305-
LineCount = _logFileReader.LineCount
6305+
LineCount = _logFileReader != null ? _logFileReader.LineCount : 0
63066306

63076307

63086308
};

src/LogExpert.UI/Dialogs/SettingsDialog.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,8 @@ private void OnPortableModeCheckedChanged (object sender, EventArgs e)
923923
var markerPath = Path.Join(ConfigManager.PortableConfigDir, ConfigManager.PortableModeSettingsFileName);
924924
if (!File.Exists(markerPath))
925925
{
926-
using (File.Create(markerPath)) { }
926+
using (File.Create(markerPath))
927+
{ }
927928
}
928929

929930
Preferences.PortableMode = true;

0 commit comments

Comments
 (0)