From ebe572e4918dee204f12da248118b9358c6881bb Mon Sep 17 00:00:00 2001 From: Jan Rabe Date: Mon, 1 Jul 2024 08:58:44 +0200 Subject: [PATCH] added a bunch of tests --- .../Extensions/Orchard+Extensions.swift | 1 - .../String+Literals+Extensions.swift | 8 +- Tests/OrchardTests/ConsoleLoggerTests.swift | 100 ++++++++++++++++++ Tests/OrchardTests/Helper/MockLogger.swift | 48 +++++++++ Tests/OrchardTests/Helper/OutputCapture.swift | 20 ++++ .../Helper/String+Extensions.swift | 5 + Tests/OrchardTests/OrchardTests.swift | 92 ++++++++++++++-- 7 files changed, 260 insertions(+), 14 deletions(-) create mode 100644 Tests/OrchardTests/ConsoleLoggerTests.swift create mode 100644 Tests/OrchardTests/Helper/MockLogger.swift create mode 100644 Tests/OrchardTests/Helper/OutputCapture.swift create mode 100644 Tests/OrchardTests/Helper/String+Extensions.swift diff --git a/Sources/Orchard/Extensions/Orchard+Extensions.swift b/Sources/Orchard/Extensions/Orchard+Extensions.swift index 2eeca69..3ea6c84 100644 --- a/Sources/Orchard/Extensions/Orchard+Extensions.swift +++ b/Sources/Orchard/Extensions/Orchard+Extensions.swift @@ -106,7 +106,6 @@ func paddedToString(_ args: [String: any CustomStringConvertible]?, _ opt: JSONS return "" } - let encoder = JSONEncoder() do { let jsonData = try JSONSerialization.data(withJSONObject: args, options: opt) if let jsonString = String(data: jsonData, encoding: .utf8) { diff --git a/Sources/Orchard/Extensions/String+Literals+Extensions.swift b/Sources/Orchard/Extensions/String+Literals+Extensions.swift index 044c049..5b51734 100644 --- a/Sources/Orchard/Extensions/String+Literals+Extensions.swift +++ b/Sources/Orchard/Extensions/String+Literals+Extensions.swift @@ -6,13 +6,7 @@ extension String { return self } - let pathAfterSources = String(self[range.upperBound...]) - - // Split by "/" to get path components and find the first one that follows "Sources/" - let components = pathAfterSources.split(separator: "/") - - // If splitting fails or there is no component after "Sources/", return the modified filename - return pathAfterSources + return String(self[range.upperBound...]) } /// e.g. diff --git a/Tests/OrchardTests/ConsoleLoggerTests.swift b/Tests/OrchardTests/ConsoleLoggerTests.swift new file mode 100644 index 0000000..aacf750 --- /dev/null +++ b/Tests/OrchardTests/ConsoleLoggerTests.swift @@ -0,0 +1,100 @@ +import XCTest +@testable import Orchard + +class ConsoleLoggerTests: XCTestCase { + + var consoleLogger: ConsoleLogger! + var outputCapture: OutputCapture! + + override func setUp() { + super.setUp() + consoleLogger = ConsoleLogger() + outputCapture = OutputCapture() + } + + override func tearDown() { + consoleLogger = nil + outputCapture = nil + super.tearDown() + } + + func testVerboseLogging() { + outputCapture.startCapture() + consoleLogger.verbose("Verbose test", nil, nil, #file, #fileID, #function, #line) + let output = outputCapture.stopCapture() + XCTAssertTrue(output.contains("đŸ”Ŧ")) + XCTAssertTrue(output.contains("Verbose test")) + } + + func testDebugLogging() { + outputCapture.startCapture() + consoleLogger.debug("Debug test", nil, nil, #file, #fileID, #function, #line) + let output = outputCapture.stopCapture() + XCTAssertTrue(output.contains("🔍")) + XCTAssertTrue(output.contains("Debug test")) + } + + func testInfoLogging() { + outputCapture.startCapture() + consoleLogger.info("Info test", nil, nil, #file, #fileID, #function, #line) + let output = outputCapture.stopCapture() + XCTAssertTrue(output.contains("ℹī¸")) + XCTAssertTrue(output.contains("Info test")) + } + + func testWarningLogging() { + outputCapture.startCapture() + consoleLogger.warning("Warning test", nil, nil, #file, #fileID, #function, #line) + let output = outputCapture.stopCapture() + XCTAssertTrue(output.contains("⚠ī¸")) + XCTAssertTrue(output.contains("Warning test")) + } + + func testErrorLogging() { + outputCapture.startCapture() + consoleLogger.error("Error test", nil, nil, #file, #fileID, #function, #line) + let output = outputCapture.stopCapture() + XCTAssertTrue(output.contains("❌")) + XCTAssertTrue(output.contains("Error test")) + } + + func testFatalLogging() { + outputCapture.startCapture() + consoleLogger.fatal("Fatal test", nil, nil, #file, #fileID, #function, #line) + let output = outputCapture.stopCapture() + XCTAssertTrue(output.contains("⚡ī¸")) + XCTAssertTrue(output.contains("Fatal test")) + } + + func testLoggingWithTimestamp() { + consoleLogger.showTimesStamp = true + outputCapture.startCapture() + consoleLogger.info("Timestamp test", nil, nil, #file, #fileID, #function, #line) + let output = outputCapture.stopCapture() + XCTAssertTrue(output.matches("\\d{2}:\\d{2}:\\d{2}\\.\\d{3}:")) + } + + func testLoggingWithoutTimestamp() { + consoleLogger.showTimesStamp = false + outputCapture.startCapture() + consoleLogger.info("No timestamp test", nil, nil, #file, #fileID, #function, #line) + let output = outputCapture.stopCapture() + XCTAssertFalse(output.matches("\\d{2}:\\d{2}:\\d{2}\\.\\d{3}:")) + } + + func testLoggingWithInvocation() { + consoleLogger.showInvocation = true + outputCapture.startCapture() + consoleLogger.info("Invocation test", nil, nil, #file, #fileID, #function, #line) + let output = outputCapture.stopCapture() + XCTAssertTrue(output.contains("/ConsoleLoggerTests.testLoggingWithInvocation")) + } + + func testLoggingWithoutInvocation() { + consoleLogger.showInvocation = false + outputCapture.startCapture() + consoleLogger.info("No invocation test", nil, nil, #file, #fileID, #function, #line) + let output = outputCapture.stopCapture() + XCTAssertFalse(output.contains("/ConsoleLoggerTests.testLoggingWithoutInvocation")) + } +} diff --git a/Tests/OrchardTests/Helper/MockLogger.swift b/Tests/OrchardTests/Helper/MockLogger.swift new file mode 100644 index 0000000..5e270fc --- /dev/null +++ b/Tests/OrchardTests/Helper/MockLogger.swift @@ -0,0 +1,48 @@ +import XCTest +@testable import Orchard + +class MockLogger: Orchard.Logger { + var level: Orchard.Level = .verbose + var tag: String? + var icon: Character? + + var lastLogLevel: Orchard.Level? + var lastMessage: String? + var lastError: Error? + var lastArgs: [String: CustomStringConvertible]? + var lastTag: String? + var lastIcon: Character? + + func log(_ level: Orchard.Level, _ message: String?, _ error: Error?, _ args: [String: CustomStringConvertible]?, _ file: String, _ fileId: String, _ function: String, _ line: Int) { + lastLogLevel = level + lastMessage = message + lastError = error + lastArgs = args + lastTag = tag + lastIcon = icon + } + + func verbose(_ message: String?, _ error: Error?, _ args: [String: CustomStringConvertible]?, _ file: String, _ fileId: String, _ function: String, _ line: Int) { + log(.verbose, message, error, args, file, fileId, function, line) + } + + func debug(_ message: String?, _ error: Error?, _ args: [String: CustomStringConvertible]?, _ file: String, _ fileId: String, _ function: String, _ line: Int) { + log(.debug, message, error, args, file, fileId, function, line) + } + + func info(_ message: String?, _ error: Error?, _ args: [String: CustomStringConvertible]?, _ file: String, _ fileId: String, _ function: String, _ line: Int) { + log(.info, message, error, args, file, fileId, function, line) + } + + func warning(_ message: String?, _ error: Error?, _ args: [String: CustomStringConvertible]?, _ file: String, _ fileId: String, _ function: String, _ line: Int) { + log(.warning, message, error, args, file, fileId, function, line) + } + + func error(_ message: String?, _ error: Error?, _ args: [String: CustomStringConvertible]?, _ file: String, _ fileId: String, _ function: String, _ line: Int) { + log(.error, message, error, args, file, fileId, function, line) + } + + func fatal(_ message: String?, _ error: Error?, _ args: [String: CustomStringConvertible]?, _ file: String, _ fileId: String, _ function: String, _ line: Int) { + log(.fatal, message, error, args, file, fileId, function, line) + } +} diff --git a/Tests/OrchardTests/Helper/OutputCapture.swift b/Tests/OrchardTests/Helper/OutputCapture.swift new file mode 100644 index 0000000..ba46bc8 --- /dev/null +++ b/Tests/OrchardTests/Helper/OutputCapture.swift @@ -0,0 +1,20 @@ +import XCTest +@testable import Orchard + +class OutputCapture { + private var originalStdout: Int32? + private var pipe: Pipe? + + func startCapture() { + originalStdout = dup(FileHandle.standardOutput.fileDescriptor) + pipe = Pipe() + dup2(pipe!.fileHandleForWriting.fileDescriptor, FileHandle.standardOutput.fileDescriptor) + } + + func stopCapture() -> String { + pipe?.fileHandleForWriting.closeFile() + let data = pipe?.fileHandleForReading.readDataToEndOfFile() + dup2(originalStdout!, FileHandle.standardOutput.fileDescriptor) + return String(data: data ?? Data(), encoding: .utf8) ?? "" + } +} diff --git a/Tests/OrchardTests/Helper/String+Extensions.swift b/Tests/OrchardTests/Helper/String+Extensions.swift new file mode 100644 index 0000000..f35da1d --- /dev/null +++ b/Tests/OrchardTests/Helper/String+Extensions.swift @@ -0,0 +1,5 @@ +extension String { + func matches(_ regex: String) -> Bool { + self.range(of: regex, options: .regularExpression) != nil + } +} diff --git a/Tests/OrchardTests/OrchardTests.swift b/Tests/OrchardTests/OrchardTests.swift index ec3a4e6..6e92dea 100644 --- a/Tests/OrchardTests/OrchardTests.swift +++ b/Tests/OrchardTests/OrchardTests.swift @@ -1,12 +1,92 @@ import XCTest @testable import Orchard -final class OrchardTests: XCTestCase { - func testExample() throws { - // XCTest Documentation - // https://developer.apple.com/documentation/xctest +class OrchardTests: XCTestCase { - // Defining Test Cases and Test Methods - // https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods + var mockLogger: MockLogger! + + override func setUp() { + super.setUp() + mockLogger = MockLogger() + Orchard.loggers = [mockLogger] + } + + override func tearDown() { + Orchard.loggers = [] + mockLogger = nil + super.tearDown() + } + + func testVerboseLogging() { + Orchard.v("Verbose message") + XCTAssertEqual(mockLogger.lastLogLevel, .verbose) + XCTAssertEqual(mockLogger.lastMessage, "Verbose message") + } + + func testDebugLogging() { + Orchard.d("Debug message") + XCTAssertEqual(mockLogger.lastLogLevel, .debug) + XCTAssertEqual(mockLogger.lastMessage, "Debug message") + } + + func testInfoLogging() { + Orchard.i("Info message") + XCTAssertEqual(mockLogger.lastLogLevel, .info) + XCTAssertEqual(mockLogger.lastMessage, "Info message") + } + + func testWarningLogging() { + Orchard.w("Warning message") + XCTAssertEqual(mockLogger.lastLogLevel, .warning) + XCTAssertEqual(mockLogger.lastMessage, "Warning message") + } + + func testErrorLogging() { + Orchard.e("Error message") + XCTAssertEqual(mockLogger.lastLogLevel, .error) + XCTAssertEqual(mockLogger.lastMessage, "Error message") + } + + func testFatalLogging() { + Orchard.f("Fatal message") + XCTAssertEqual(mockLogger.lastLogLevel, .fatal) + XCTAssertEqual(mockLogger.lastMessage, "Fatal message") + } + + func testLoggingWithError() { + let error = NSError(domain: "TestDomain", code: 100, userInfo: nil) + Orchard.e("Error occurred", error) + XCTAssertEqual(mockLogger.lastLogLevel, .error) + XCTAssertEqual(mockLogger.lastMessage, "Error occurred") + XCTAssertEqual(mockLogger.lastError as NSError?, error) + } + + func testLoggingWithArgs() { + Orchard.i("User action", ["userId": "123", "action": "login"]) + XCTAssertEqual(mockLogger.lastLogLevel, .info) + XCTAssertEqual(mockLogger.lastMessage, "User action") + XCTAssertEqual(mockLogger.lastArgs?["userId"] as? String, "123") + XCTAssertEqual(mockLogger.lastArgs?["action"] as? String, "login") + } + + func testTagging() { + Orchard.tag("NetworkManager").i("Network request") + XCTAssertEqual(mockLogger.lastTag, "NetworkManager") + XCTAssertEqual(mockLogger.lastMessage, "Network request") + } + + func testIconSetting() { + Orchard.icon("🌐").i("Custom icon log") + XCTAssertEqual(mockLogger.lastIcon, "🌐") + XCTAssertEqual(mockLogger.lastMessage, "Custom icon log") + } + + func testChainedTagAndIcon() { + Orchard.tag("UI").icon("👁ī¸").d("UI update") + XCTAssertEqual(mockLogger.lastTag, "UI") + XCTAssertEqual(mockLogger.lastIcon, "👁ī¸") + XCTAssertEqual(mockLogger.lastMessage, "UI update") } } + +