Skip to content

Commit 4bf6892

Browse files
committed
Enable testing via ConsoleLoggerPrinter protocol
1 parent 7c65f5f commit 4bf6892

3 files changed

Lines changed: 128 additions & 55 deletions

File tree

Sources/ConsoleLogger/ConsoleLogger.swift

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ public struct ConsoleLogger<T: LoggerFragment>: LogHandler, Sendable {
1616
/// The ``LoggerFragment`` this logger outputs through.
1717
public var fragment: T
1818

19+
/// The printer used to output log messages. Used for testing purposes only.
20+
package var printer: any ConsoleLoggerPrinter = DefaultConsoleLoggerPrinter()
21+
1922
/// Creates a new ``ConsoleLogger`` instance.
2023
///
2124
/// - Parameters:
@@ -62,7 +65,7 @@ public struct ConsoleLogger<T: LoggerFragment>: LogHandler, Sendable {
6265

6366
/// See `LogHandler[metadataKey:]`.
6467
///
65-
/// This just acts as a getter/setter for the `.metadata` property.
68+
/// This just acts as a getter/setter for the ``ConsoleLogger/metadata`` property.
6669
public subscript(metadataKey key: String) -> Logger.Metadata.Value? {
6770
get { self.metadata[key] }
6871
set { self.metadata[key] = newValue }
@@ -94,7 +97,7 @@ public struct ConsoleLogger<T: LoggerFragment>: LogHandler, Sendable {
9497
)
9598

9699
self.fragment.write(&record, to: &output)
97-
print(output.text)
100+
self.printer.print(output.text)
98101
}
99102
}
100103

@@ -114,3 +117,15 @@ extension Logger.Level {
114117
"\(self)".uppercased()
115118
}
116119
}
120+
121+
/// Defines a printer used to output log messages. Used for testing purposes only.
122+
package protocol ConsoleLoggerPrinter: Sendable {
123+
func print(_ string: String)
124+
}
125+
126+
/// The default ``ConsoleLoggerPrinter`` that prints to standard output. It exists for testing purposes only.
127+
struct DefaultConsoleLoggerPrinter: ConsoleLoggerPrinter {
128+
func print(_ string: String) {
129+
Swift.print(string)
130+
}
131+
}

Tests/ConsoleLoggerTests/LoggerFragmentBuilderTests.swift

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,30 @@ import Testing
66
struct LoggerFragmentBuilderTests {
77
@Test("Simple Fragment")
88
func simpleFragment() throws {
9+
let printer = TestingConsoleLoggerPrinter()
910
let logger = Logger(label: "codes.vapor.console") { label in
10-
ConsoleLogger(label: label) {
11+
var consoleLogger = ConsoleLogger(label: label) {
1112
SpacedFragment {
1213
"ConsoleLogger"
1314
LabelFragment()
1415
LevelFragment()
1516
MessageFragment()
1617
}
1718
}
19+
consoleLogger.printer = printer
20+
return consoleLogger
1821
}
1922

2023
logger.info("Test message")
2124

22-
//#expect(console.testOutputQueue.first == "ConsoleLogger [ codes.vapor.console ] [ INFO ] Test message\n")
25+
#expect(printer.testOutputQueue.first == "ConsoleLogger [ codes.vapor.console ] [ INFO ] Test message")
2326
}
2427

2528
@Test("Conditional Fragment", arguments: [true, false])
2629
func conditionalFragment(includeTimestamp: Bool) throws {
30+
let printer = TestingConsoleLoggerPrinter()
2731
let logger = Logger(label: "codes.vapor.console") { label in
28-
ConsoleLogger(label: label) {
32+
var consoleLogger = ConsoleLogger(label: label) {
2933
SpacedFragment {
3034
if includeTimestamp {
3135
TimestampFragment()
@@ -34,21 +38,24 @@ struct LoggerFragmentBuilderTests {
3438
MessageFragment()
3539
}
3640
}
41+
consoleLogger.printer = printer
42+
return consoleLogger
3743
}
3844

3945
logger.info("Test message")
4046

4147
if includeTimestamp {
42-
//#expect(console.testOutputQueue.first?.contains("[ INFO ] Test message") == true)
48+
#expect(printer.testOutputQueue.first?.contains("[ INFO ] Test message") == true)
4349
} else {
44-
//#expect(console.testOutputQueue.first == "[ INFO ] Test message\n")
50+
#expect(printer.testOutputQueue.first == "[ INFO ] Test message")
4551
}
4652
}
4753

4854
@Test("Array Fragment")
4955
func arrayFragment() throws {
56+
let printer = TestingConsoleLoggerPrinter()
5057
let logger = Logger(label: "codes.vapor.console") { label in
51-
ConsoleLogger(label: label) {
58+
var consoleLogger = ConsoleLogger(label: label) {
5259
SpacedFragment {
5360
for i in 1...2 {
5461
"[PREFIX\(i)]"
@@ -57,30 +64,36 @@ struct LoggerFragmentBuilderTests {
5764
MessageFragment()
5865
}
5966
}
67+
consoleLogger.printer = printer
68+
return consoleLogger
6069
}
6170

6271
logger.info("Test message")
6372

64-
//#expect(console.testOutputQueue.first == "[PREFIX1] [ INFO ] [PREFIX2] [ INFO ] Test message\n")
73+
#expect(printer.testOutputQueue.first == "[PREFIX1] [ INFO ] [PREFIX2] [ INFO ] Test message")
6574
}
6675

6776
@Test("Empty Block")
6877
func emptyBlock() throws {
78+
let printer = TestingConsoleLoggerPrinter()
6979
let logger = Logger(label: "codes.vapor.console") { label in
70-
ConsoleLogger(label: label) {
80+
var consoleLogger = ConsoleLogger(label: label) {
7181
// Empty block
7282
}
83+
consoleLogger.printer = printer
84+
return consoleLogger
7385
}
7486

7587
logger.info("Test message")
7688

77-
//#expect(console.testOutputQueue.first == "\n")
89+
#expect(printer.testOutputQueue.first == "")
7890
}
7991

8092
@Test("Complex Conditional Fragment", arguments: [Logger.Level.error, .warning, .info])
8193
func complexConditionalFragment(level: Logger.Level) throws {
94+
let printer = TestingConsoleLoggerPrinter()
8295
let logger = Logger(label: "codes.vapor.console") { label in
83-
ConsoleLogger(label: label) {
96+
var consoleLogger = ConsoleLogger(label: label) {
8497
if level >= .error {
8598
"X"
8699
} else if level >= .warning {
@@ -92,23 +105,26 @@ struct LoggerFragmentBuilderTests {
92105
LevelFragment().separated(" ")
93106
MessageFragment().separated(" ")
94107
}
108+
consoleLogger.printer = printer
109+
return consoleLogger
95110
}
96111

97112
logger.info("Test message")
98113

99114
if level >= .error {
100-
//#expect(console.testOutputQueue.first == "X [ INFO ] Test message\n")
115+
#expect(printer.testOutputQueue.first == "X [ INFO ] Test message")
101116
} else if level >= .warning {
102-
//#expect(console.testOutputQueue.first == "! [ INFO ] Test message\n")
117+
#expect(printer.testOutputQueue.first == "! [ INFO ] Test message")
103118
} else {
104-
//#expect(console.testOutputQueue.first == "i [ INFO ] Test message\n")
119+
#expect(printer.testOutputQueue.first == "i [ INFO ] Test message")
105120
}
106121
}
107122

108123
@Test("Default built with LoggerFragmentBuilder")
109124
func defaultFragment() throws {
125+
let loggerBuilderPrinter = TestingConsoleLoggerPrinter()
110126
let loggerBuilder = Logger(label: "codes.vapor.console") { label in
111-
ConsoleLogger(label: label) {
127+
var consoleLogger = ConsoleLogger(label: label) {
112128
// This is the default logger fragment, but built using LoggerFragmentBuilder
113129
SpacedFragment {
114130
LabelFragment().maxLevel(.trace)
@@ -118,16 +134,20 @@ struct LoggerFragmentBuilderTests {
118134
SourceLocationFragment().maxLevel(.debug)
119135
}
120136
}
137+
consoleLogger.printer = loggerBuilderPrinter
138+
return consoleLogger
121139
}
122140

141+
let defaultLoggerPrinter = TestingConsoleLoggerPrinter()
123142
let defaultLogger = Logger(label: "codes.vapor.console") { label in
124-
ConsoleLogger(label: label)
143+
var consoleLogger = ConsoleLogger(label: label)
144+
consoleLogger.printer = defaultLoggerPrinter
145+
return consoleLogger
125146
}
126147

127-
loggerBuilder.info("Test message", metadata: ["key": "value"])
128-
defaultLogger.info("Test message", metadata: ["key": "value"])
148+
loggerBuilder.info("Test message", metadata: ["key": "value"], line: 1)
149+
defaultLogger.info("Test message", metadata: ["key": "value"], line: 1)
129150

130-
// Drop the last 5 characters which are the source location line number that can differ
131-
//#expect(console.testOutputQueue[0].dropLast(5) == console.testOutputQueue[1].dropLast(5))
151+
#expect(loggerBuilderPrinter.testOutputQueue[0] == defaultLoggerPrinter.testOutputQueue[0])
132152
}
133153
}

0 commit comments

Comments
 (0)