Skip to content

Commit 92004cd

Browse files
committed
test(logger): 添加临时日志记录器单元测试
- 测试临时日志记录器的基本功能 - 测试日志事件缓冲和刷新机制 - 测试日志转移功能
1 parent b6c74b7 commit 92004cd

1 file changed

Lines changed: 234 additions & 0 deletions

File tree

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
// ==========================================================================================
2+
// GameFrameX 组织及其衍生项目的版权、商标、专利及其他相关权利
3+
// GameFrameX organization and its derivative projects' copyrights, trademarks, patents, and related rights
4+
// 均受中华人民共和国及相关国际法律法规保护。
5+
// are protected by the laws of the People's Republic of China and relevant international regulations.
6+
//
7+
// 使用本项目须严格遵守相应法律法规及开源许可证之规定。
8+
// Usage of this project must strictly comply with applicable laws, regulations, and open-source licenses.
9+
//
10+
// 本项目采用 MIT 许可证与 Apache License 2.0 双许可证分发,
11+
// This project is dual-licensed under the MIT License and Apache License 2.0,
12+
// 完整许可证文本请参见源代码根目录下的 LICENSE 文件。
13+
// please refer to the LICENSE file in the root directory of the source code for the full license text.
14+
//
15+
// 禁止利用本项目实施任何危害国家安全、破坏社会秩序、
16+
// It is prohibited to use this project to engage in any activities that endanger national security, disrupt social order,
17+
// 侵犯他人合法权益等法律法规所禁止的行为!
18+
// or infringe upon the legitimate rights and interests of others, as prohibited by laws and regulations!
19+
// 因基于本项目二次开发所产生的一切法律纠纷与责任,
20+
// Any legal disputes and liabilities arising from secondary development based on this project
21+
// 本项目组织与贡献者概不承担。
22+
// shall be borne solely by the developer; the project organization and contributors assume no responsibility.
23+
//
24+
// GitHub 仓库:https://github.com/GameFrameX
25+
// GitHub Repository: https://github.com/GameFrameX
26+
// Gitee 仓库:https://gitee.com/GameFrameX
27+
// Gitee Repository: https://gitee.com/GameFrameX
28+
// CNB 仓库:https://cnb.cool/GameFrameX
29+
// CNB Repository: https://cnb.cool/GameFrameX
30+
// 官方文档:https://gameframex.doc.alianblank.com/
31+
// Official Documentation: https://gameframex.doc.alianblank.com/
32+
// ==========================================================================================
33+
34+
using System.Collections.Concurrent;
35+
using GameFrameX.Foundation.Logger;
36+
using Serilog;
37+
using Serilog.Core;
38+
using Serilog.Events;
39+
using Xunit;
40+
41+
namespace GameFrameX.Foundation.Tests.Logger;
42+
43+
public class TempLoggerTests : IDisposable
44+
{
45+
private readonly ConcurrentQueue<LogEvent> _capturedEvents = new();
46+
47+
public TempLoggerTests()
48+
{
49+
}
50+
51+
[Fact]
52+
public void Debug_WithNoLoggerInitialized_ShouldCreateTempLogger()
53+
{
54+
LogHelper.Debug("Test message");
55+
Assert.NotNull(GetTempLoggerField());
56+
}
57+
58+
[Fact]
59+
public void Info_WithNoLoggerInitialized_ShouldCreateTempLogger()
60+
{
61+
LogHelper.Info("Test message");
62+
Assert.NotNull(GetTempLoggerField());
63+
}
64+
65+
[Fact]
66+
public void Warning_WithNoLoggerInitialized_ShouldCreateTempLogger()
67+
{
68+
LogHelper.Warning("Test message");
69+
Assert.NotNull(GetTempLoggerField());
70+
}
71+
72+
[Fact]
73+
public void Error_WithNoLoggerInitialized_ShouldCreateTempLogger()
74+
{
75+
LogHelper.Error("Test message");
76+
Assert.NotNull(GetTempLoggerField());
77+
}
78+
79+
[Fact]
80+
public void Fatal_WithNoLoggerInitialized_ShouldCreateTempLogger()
81+
{
82+
LogHelper.Fatal("Test message");
83+
Assert.NotNull(GetTempLoggerField());
84+
}
85+
86+
[Fact]
87+
public void Debug_WithMessageAndArgs_ShouldFormatMessage()
88+
{
89+
LogHelper.Debug("Value: {Value}", 123);
90+
Assert.NotNull(GetTempLoggerField());
91+
}
92+
93+
[Fact]
94+
public void Info_WithMessageAndArgs_ShouldFormatMessage()
95+
{
96+
LogHelper.Info("User: {User}, Age: {Age}", "John", 25);
97+
Assert.NotNull(GetTempLoggerField());
98+
}
99+
100+
[Fact]
101+
public void SetLogger_WithTempLoggerExisting_ShouldFlushTempLogs()
102+
{
103+
LogHelper.Info("Temp log before initialization");
104+
105+
var capturedEvents = new ConcurrentQueue<LogEvent>();
106+
var testLogger = new LoggerConfiguration()
107+
.WriteTo.Sink(new TestSink(capturedEvents))
108+
.CreateLogger();
109+
110+
LogHelper.SetLogger(testLogger);
111+
112+
LogHelper.Info("Log after initialization");
113+
114+
Assert.Equal(2, capturedEvents.Count);
115+
Assert.Equal("Temp log before initialization", capturedEvents.ElementAt(0).RenderMessage());
116+
Assert.Equal("Log after initialization", capturedEvents.ElementAt(1).RenderMessage());
117+
}
118+
119+
[Fact]
120+
public void SetLogger_WithTempLoggerExisting_ShouldDisposeTempLogger()
121+
{
122+
LogHelper.Info("Temp log");
123+
124+
var testLogger = new LoggerConfiguration()
125+
.WriteTo.Sink(new NullSink())
126+
.CreateLogger();
127+
128+
LogHelper.SetLogger(testLogger);
129+
130+
Assert.Null(GetTempLoggerField());
131+
}
132+
133+
[Fact]
134+
public void SetLogger_WithMultipleLogs_ShouldFlushAllLogs()
135+
{
136+
ResetLoggerState();
137+
138+
LogHelper.Info("Log 1");
139+
LogHelper.Debug("Log 2");
140+
LogHelper.Warning("Log 3");
141+
142+
var capturedEvents = new ConcurrentQueue<LogEvent>();
143+
var testLogger = new LoggerConfiguration()
144+
.MinimumLevel.Verbose()
145+
.WriteTo.Sink(new TestSink(capturedEvents))
146+
.CreateLogger();
147+
148+
LogHelper.SetLogger(testLogger);
149+
150+
Assert.Equal(3, capturedEvents.Count);
151+
}
152+
153+
[Fact]
154+
public void SetLogger_ThenLog_ShouldUseNewLogger()
155+
{
156+
var capturedEvents = new ConcurrentQueue<LogEvent>();
157+
var testLogger = new LoggerConfiguration()
158+
.WriteTo.Sink(new TestSink(capturedEvents))
159+
.CreateLogger();
160+
161+
LogHelper.SetLogger(testLogger);
162+
163+
LogHelper.Info("After SetLogger");
164+
165+
Assert.Single(capturedEvents);
166+
Assert.Equal("After SetLogger", capturedEvents.First().RenderMessage());
167+
}
168+
169+
[Fact]
170+
public void SetLogger_WithNullLogger_ShouldThrowArgumentNullException()
171+
{
172+
Assert.Throws<ArgumentNullException>(() => LogHelper.SetLogger(null!));
173+
}
174+
175+
private static object? GetTempLoggerField()
176+
{
177+
var field = typeof(LogHelper).GetField("_tempLogger", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
178+
return field?.GetValue(null);
179+
}
180+
181+
private static void ResetLoggerState()
182+
{
183+
var tempField = typeof(LogHelper).GetField("_tempLogger", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
184+
var tempLogger = tempField?.GetValue(null);
185+
if (tempLogger is IDisposable disposable)
186+
{
187+
disposable.Dispose();
188+
}
189+
tempField?.SetValue(null, null);
190+
191+
var loggerField = typeof(LogHelper).GetField("_logger", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
192+
loggerField?.SetValue(null, null);
193+
}
194+
195+
public void Dispose()
196+
{
197+
var field = typeof(LogHelper).GetField("_tempLogger", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
198+
var tempLogger = field?.GetValue(null);
199+
if (tempLogger is IDisposable disposable)
200+
{
201+
disposable.Dispose();
202+
}
203+
204+
var loggerField = typeof(LogHelper).GetField("_logger", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
205+
loggerField?.SetValue(null, null);
206+
207+
field?.SetValue(null, null);
208+
loggerField?.SetValue(null, null);
209+
210+
GC.SuppressFinalize(this);
211+
}
212+
213+
private sealed class TestSink : ILogEventSink
214+
{
215+
private readonly ConcurrentQueue<LogEvent> _events;
216+
217+
public TestSink(ConcurrentQueue<LogEvent> events)
218+
{
219+
_events = events;
220+
}
221+
222+
public void Emit(LogEvent logEvent)
223+
{
224+
_events.Enqueue(logEvent);
225+
}
226+
}
227+
228+
private sealed class NullSink : ILogEventSink
229+
{
230+
public void Emit(LogEvent logEvent)
231+
{
232+
}
233+
}
234+
}

0 commit comments

Comments
 (0)