Merge branch 'feature/code_reorganization' into develop

This commit is contained in:
Wojciech Nagrodzki 2019-10-30 22:34:37 +01:00
commit 3bc845ee28
Signed by: wnagrodzki
GPG key ID: E9D0EB0302264569
9 changed files with 155 additions and 142 deletions

View file

@ -15,14 +15,15 @@
2EBF4B4B2122AF53008E4117 /* ConsoleLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4B482122AF53008E4117 /* ConsoleLogger.swift */; };
2EBF4B4C2122AF53008E4117 /* NullLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4B492122AF53008E4117 /* NullLogger.swift */; };
2EBF4B572122B598008E4117 /* DiskLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4B542122B598008E4117 /* DiskLogger.swift */; };
2EBF4B582122B598008E4117 /* FileWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4B552122B598008E4117 /* FileWriter.swift */; };
2EBF4B592122B598008E4117 /* FileRotate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4B562122B598008E4117 /* FileRotate.swift */; };
2EBF4B582122B598008E4117 /* SizeLimitedFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4B552122B598008E4117 /* SizeLimitedFile.swift */; };
2EBF4B592122B598008E4117 /* Logrotate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EBF4B562122B598008E4117 /* Logrotate.swift */; };
2ED077D721329CA30058EEFC /* LoggetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED077D621329CA30058EEFC /* LoggetTests.swift */; };
2ED077D92132A4820058EEFC /* AgregateLoggerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED077D82132A4820058EEFC /* AgregateLoggerTests.swift */; };
2ED077DB2132B0320058EEFC /* FileSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED077DA2132B0320058EEFC /* FileSystem.swift */; };
2ED103E12135C61100EB3683 /* FileRotateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED103E02135C61100EB3683 /* FileRotateTests.swift */; };
2ED103E32135D3FB00EB3683 /* FileWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED103E22135D3FB00EB3683 /* FileWriterTests.swift */; };
2ED077DB2132B0320058EEFC /* OSFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED077DA2132B0320058EEFC /* OSFileManager.swift */; };
2ED103E12135C61100EB3683 /* LogrotateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED103E02135C61100EB3683 /* LogrotateTests.swift */; };
2ED103E32135D3FB00EB3683 /* SizeLimitedFileTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED103E22135D3FB00EB3683 /* SizeLimitedFileTests.swift */; };
2ED103E52138553B00EB3683 /* DiskLoggerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED103E42138553B00EB3683 /* DiskLoggerTests.swift */; };
2ED83781236A19A60008C01F /* OSFileHandle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ED83780236A19A60008C01F /* OSFileHandle.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -58,14 +59,15 @@
2EBF4B482122AF53008E4117 /* ConsoleLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConsoleLogger.swift; sourceTree = "<group>"; };
2EBF4B492122AF53008E4117 /* NullLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NullLogger.swift; sourceTree = "<group>"; };
2EBF4B542122B598008E4117 /* DiskLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiskLogger.swift; sourceTree = "<group>"; };
2EBF4B552122B598008E4117 /* FileWriter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileWriter.swift; sourceTree = "<group>"; };
2EBF4B562122B598008E4117 /* FileRotate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileRotate.swift; sourceTree = "<group>"; };
2EBF4B552122B598008E4117 /* SizeLimitedFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SizeLimitedFile.swift; sourceTree = "<group>"; };
2EBF4B562122B598008E4117 /* Logrotate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logrotate.swift; sourceTree = "<group>"; };
2ED077D621329CA30058EEFC /* LoggetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggetTests.swift; sourceTree = "<group>"; };
2ED077D82132A4820058EEFC /* AgregateLoggerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgregateLoggerTests.swift; sourceTree = "<group>"; };
2ED077DA2132B0320058EEFC /* FileSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileSystem.swift; sourceTree = "<group>"; };
2ED103E02135C61100EB3683 /* FileRotateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileRotateTests.swift; sourceTree = "<group>"; };
2ED103E22135D3FB00EB3683 /* FileWriterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileWriterTests.swift; sourceTree = "<group>"; };
2ED077DA2132B0320058EEFC /* OSFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSFileManager.swift; sourceTree = "<group>"; };
2ED103E02135C61100EB3683 /* LogrotateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogrotateTests.swift; sourceTree = "<group>"; };
2ED103E22135D3FB00EB3683 /* SizeLimitedFileTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SizeLimitedFileTests.swift; sourceTree = "<group>"; };
2ED103E42138553B00EB3683 /* DiskLoggerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiskLoggerTests.swift; sourceTree = "<group>"; };
2ED83780236A19A60008C01F /* OSFileHandle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSFileHandle.swift; sourceTree = "<group>"; };
2EDA8AE8213ACCFF00FE5840 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -95,8 +97,8 @@
2ED077D621329CA30058EEFC /* LoggetTests.swift */,
2ED077D82132A4820058EEFC /* AgregateLoggerTests.swift */,
2ED103E42138553B00EB3683 /* DiskLoggerTests.swift */,
2ED103E22135D3FB00EB3683 /* FileWriterTests.swift */,
2ED103E02135C61100EB3683 /* FileRotateTests.swift */,
2ED103E22135D3FB00EB3683 /* SizeLimitedFileTests.swift */,
2ED103E02135C61100EB3683 /* LogrotateTests.swift */,
2E58D35E21316C3500BEF81A /* Info.plist */,
);
path = UnitTests;
@ -146,9 +148,10 @@
isa = PBXGroup;
children = (
2EBF4B542122B598008E4117 /* DiskLogger.swift */,
2EBF4B552122B598008E4117 /* FileWriter.swift */,
2EBF4B562122B598008E4117 /* FileRotate.swift */,
2ED077DA2132B0320058EEFC /* FileSystem.swift */,
2EBF4B552122B598008E4117 /* SizeLimitedFile.swift */,
2EBF4B562122B598008E4117 /* Logrotate.swift */,
2ED077DA2132B0320058EEFC /* OSFileManager.swift */,
2ED83780236A19A60008C01F /* OSFileHandle.swift */,
);
path = DiskLogger;
sourceTree = "<group>";
@ -246,10 +249,10 @@
buildActionMask = 2147483647;
files = (
2E58D35D21316C3500BEF81A /* LogStringConvertibleTests.swift in Sources */,
2ED103E32135D3FB00EB3683 /* FileWriterTests.swift in Sources */,
2ED103E32135D3FB00EB3683 /* SizeLimitedFileTests.swift in Sources */,
2ED103E52138553B00EB3683 /* DiskLoggerTests.swift in Sources */,
2ED077D92132A4820058EEFC /* AgregateLoggerTests.swift in Sources */,
2ED103E12135C61100EB3683 /* FileRotateTests.swift in Sources */,
2ED103E12135C61100EB3683 /* LogrotateTests.swift in Sources */,
2ED077D721329CA30058EEFC /* LoggetTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -258,14 +261,15 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2EBF4B582122B598008E4117 /* FileWriter.swift in Sources */,
2EBF4B582122B598008E4117 /* SizeLimitedFile.swift in Sources */,
2ED83781236A19A60008C01F /* OSFileHandle.swift in Sources */,
2EBF4B572122B598008E4117 /* DiskLogger.swift in Sources */,
2EBF4B4C2122AF53008E4117 /* NullLogger.swift in Sources */,
2EBF4B3E2122AA34008E4117 /* Logger.swift in Sources */,
2EBF4B4B2122AF53008E4117 /* ConsoleLogger.swift in Sources */,
2ED077DB2132B0320058EEFC /* FileSystem.swift in Sources */,
2ED077DB2132B0320058EEFC /* OSFileManager.swift in Sources */,
2EBF4B4A2122AF53008E4117 /* AgregateLogger.swift in Sources */,
2EBF4B592122B598008E4117 /* FileRotate.swift in Sources */,
2EBF4B592122B598008E4117 /* Logrotate.swift in Sources */,
2EBF4B452122ACD6008E4117 /* LogStringConvertible.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View file

@ -24,23 +24,6 @@
import Foundation
/// Write failed as allowed size limit would be exceeded.
public struct SizeLimitedFileQuotaReached: Error {}
/// Allows writing to a file while respecting allowed size limit.
protocol SizeLimitedFile {
/// Synchronously writes `data` at the end of the file.
///
/// - Parameter data: The data to be written.
/// - Throws: Throws an error if no free space is left on the file system, or if any other writing error occurs.
/// Throws `SizeLimitedFileQuotaReached` if allowed size limit would be exceeded.
func write(_ data: Data) throws
/// Writes all in-memory data to permanent storage and closes the file.
func synchronizeAndCloseFile()
}
protocol SizeLimitedFileFactory {
/// Returns newly initialized SizeLimitedFile instance.
@ -52,20 +35,6 @@ protocol SizeLimitedFileFactory {
func makeInstance(fileURL: URL, fileSizeLimit: UInt64) throws -> SizeLimitedFile
}
/// Allows log files rotation.
protocol Logrotate {
/// Rotates log files `rotations` number of times.
///
/// First deletes file at `<fileURL>.<rotations>`.
/// Next moves files located at:
///
/// `<fileURL>, <fileURL>.1, <fileURL>.2 ... <fileURL>.<rotations - 1>`
///
/// to `<fileURL>.1, <fileURL>.2 ... <fileURL>.<rotations>`
func rotate() throws
}
protocol LogrotateFactory {
/// Returns newly initialized Logrotate instance.
@ -82,7 +51,7 @@ public final class DiskLogger: Logger {
private let fileURL: URL
private let fileSizeLimit: UInt64
private let rotations: Int
private let fileSystem: FileSystem
private let fileManager: OSFileManager
private let sizeLimitedFileFactory: SizeLimitedFileFactory
private let logrotateFactory: LogrotateFactory
private let formatter: DateFormatter
@ -97,14 +66,14 @@ public final class DiskLogger: Logger {
/// - fileSizeLimit: Maximum size log file can reach in bytes. Attempt to exceeding that limit triggers log files rotation.
/// - rotations: Number of times log files are rotated before being removed.
public convenience init(fileURL: URL, fileSizeLimit: UInt64, rotations: Int) {
self.init(fileURL: fileURL, fileSizeLimit: fileSizeLimit, rotations: rotations, fileSystem: FileManager.default, sizeLimitedFileFactory: FileWriterFactory(), logrotateFactory: FileRotateFactory())
self.init(fileURL: fileURL, fileSizeLimit: fileSizeLimit, rotations: rotations, fileManager: FileManager.default, sizeLimitedFileFactory: SizeLimitedFileFactoryImpl(), logrotateFactory: LogrotateFactoryImpl())
}
init(fileURL: URL, fileSizeLimit: UInt64, rotations: Int, fileSystem: FileSystem, sizeLimitedFileFactory: SizeLimitedFileFactory, logrotateFactory: LogrotateFactory) {
init(fileURL: URL, fileSizeLimit: UInt64, rotations: Int, fileManager: OSFileManager, sizeLimitedFileFactory: SizeLimitedFileFactory, logrotateFactory: LogrotateFactory) {
self.fileURL = fileURL
self.fileSizeLimit = fileSizeLimit
self.rotations = rotations
self.fileSystem = fileSystem
self.fileManager = fileManager
self.sizeLimitedFileFactory = sizeLimitedFileFactory
self.logrotateFactory = logrotateFactory
formatter = DateFormatter()
@ -144,8 +113,8 @@ public final class DiskLogger: Logger {
private func openSizeLimitedFile() throws {
guard sizeLimitedFile == nil else { return }
if fileSystem.itemExists(at: fileURL) == false {
_ = fileSystem.createFile(at: fileURL)
if fileManager.itemExists(at: fileURL) == false {
_ = fileManager.createFile(at: fileURL)
}
sizeLimitedFile = try sizeLimitedFileFactory.makeInstance(fileURL: fileURL, fileSizeLimit: fileSizeLimit)
}
@ -166,27 +135,20 @@ public final class DiskLogger: Logger {
}
}
private class FileRotateFactory: LogrotateFactory {
private class LogrotateFactoryImpl: LogrotateFactory {
func makeInstance(fileURL: URL, rotations: Int) -> Logrotate {
return FileRotate(fileURL: fileURL, rotations: rotations, fileSystem: FileManager.default)
return LogrotateImpl(fileURL: fileURL, rotations: rotations, fileManager: FileManager.default)
}
}
private class FileWriterFactory: SizeLimitedFileFactory {
private class SizeLimitedFileFactoryImpl: SizeLimitedFileFactory {
func makeInstance(fileURL: URL, fileSizeLimit: UInt64) throws -> SizeLimitedFile {
return try FileWriter(fileURL: fileURL, fileSizeLimit: fileSizeLimit, fileFactory: FileHandleFactory())
return try SizeLimitedFileImpl(fileURL: fileURL, fileSizeLimit: fileSizeLimit, fileFactory: FileHandleFactoryImpl())
}
}
private class FileHandleFactory: FileFactory {
func makeInstance(forWritingTo: URL) throws -> File {
private class FileHandleFactoryImpl: FileHandleFactory {
func makeInstance(forWritingTo: URL) throws -> OSFileHandle {
return try FileHandle(forWritingTo: forWritingTo)
}
}
extension FileHandle: File {
func swift_write(_ data: Data) throws {
try __write(data, error: ())
}
}

View file

@ -24,26 +24,40 @@
import Foundation
final class FileRotate {
/// Allows log files rotation.
protocol Logrotate {
/// Rotates log files `rotations` number of times.
///
/// First deletes file at `<fileURL>.<rotations>`.
/// Next moves files located at:
///
/// `<fileURL>, <fileURL>.1, <fileURL>.2 ... <fileURL>.<rotations - 1>`
///
/// to `<fileURL>.1, <fileURL>.2 ... <fileURL>.<rotations>`
func rotate() throws
}
final class LogrotateImpl {
private let fileURL: URL
private let rotations: Int
private let fileSystem: FileSystem
private let fileManager: OSFileManager
/// Initializes new Logrotate instance.
///
/// - Parameters:
/// - fileURL: URL of the log file.
/// - rotations: Number of times log files are rotated before being removed.
init(fileURL: URL, rotations: Int, fileSystem: FileSystem) {
init(fileURL: URL, rotations: Int, fileManager: OSFileManager) {
precondition(rotations > 0)
self.fileURL = fileURL
self.rotations = rotations
self.fileSystem = fileSystem
self.fileManager = fileManager
}
}
extension FileRotate: Logrotate {
extension LogrotateImpl: Logrotate {
func rotate() throws {
let range = 1...rotations
@ -54,12 +68,12 @@ extension FileRotate: Logrotate {
let toDelete = rotatedURLs.last!
let toMove = zip(allURLs, rotatedURLs).reversed()
if fileSystem.itemExists(at: toDelete) {
try fileSystem.removeItem(at: toDelete)
if fileManager.itemExists(at: toDelete) {
try fileManager.removeItem(at: toDelete)
}
for (oldURL, newURL) in toMove {
guard fileSystem.itemExists(at: oldURL) else { continue }
try fileSystem.moveItem(at: oldURL, to: newURL)
guard fileManager.itemExists(at: oldURL) else { continue }
try fileManager.moveItem(at: oldURL, to: newURL)
}
}
}

View file

@ -0,0 +1,23 @@
//
// OSFileHandle.swift
// Logger
//
// Created by Wojciech Nagrodzki on 30/10/2019.
// Copyright © 2019 Wojciech Nagrodzki. All rights reserved.
//
import Foundation
protocol OSFileHandle {
func seekToEndOfFile() -> UInt64
func swift_write(_ data: Data) throws
func synchronizeFile()
func closeFile()
}
extension FileHandle: OSFileHandle {
func swift_write(_ data: Data) throws {
try __write(data, error: ())
}
}

View file

@ -24,14 +24,14 @@
import Foundation
public protocol FileSystem {
public protocol OSFileManager {
func itemExists(at URL: URL) -> Bool
func removeItem(at URL: URL) throws
func moveItem(at srcURL: URL, to dstURL: URL) throws
func createFile(at URL: URL) -> Bool
}
extension FileManager: FileSystem {
extension FileManager: OSFileManager {
public func itemExists(at URL: URL) -> Bool {
return fileExists(atPath: URL.path)

View file

@ -24,38 +24,48 @@
import Foundation
protocol File {
func seekToEndOfFile() -> UInt64
func swift_write(_ data: Data) throws
func synchronizeFile()
func closeFile()
protocol FileHandleFactory {
func makeInstance(forWritingTo: URL) throws -> OSFileHandle
}
protocol FileFactory {
func makeInstance(forWritingTo: URL) throws -> File
/// Write failed as allowed size limit would be exceeded.
public struct SizeLimitedFileQuotaReached: Error {}
/// Allows writing to a file while respecting allowed size limit.
protocol SizeLimitedFile {
/// Synchronously writes `data` at the end of the file.
///
/// - Parameter data: The data to be written.
/// - Throws: Throws an error if no free space is left on the file system, or if any other writing error occurs.
/// Throws `SizeLimitedFileQuotaReached` if allowed size limit would be exceeded.
func write(_ data: Data) throws
/// Writes all in-memory data to permanent storage and closes the file.
func synchronizeAndCloseFile()
}
/// Allows writing to a file while respecting allowed size limit.
final class FileWriter {
final class SizeLimitedFileImpl {
private let file: File
private let file: OSFileHandle
private let sizeLimit: UInt64
private var currentSize: UInt64
/// Initializes new FileWriter instance.
/// Initializes new SizeLimitedFileImpl instance.
///
/// - Parameters:
/// - fileURL: URL of the file.
/// - fileSizeLimit: Maximum size the file can reach in bytes.
/// - Throws: An error that may occur while the file is being opened for writing.
init(fileURL: URL, fileSizeLimit: UInt64, fileFactory: FileFactory) throws {
init(fileURL: URL, fileSizeLimit: UInt64, fileFactory: FileHandleFactory) throws {
file = try fileFactory.makeInstance(forWritingTo: fileURL)
self.sizeLimit = fileSizeLimit
currentSize = file.seekToEndOfFile()
}
}
extension FileWriter: SizeLimitedFile {
extension SizeLimitedFileImpl: SizeLimitedFile {
func write(_ data: Data) throws {
let dataSize = UInt64(data.count)

View file

@ -33,13 +33,13 @@ class DiskLoggerTests: XCTestCase {
let expectation = XCTestExpectation(description: "write(_:) was called on SizeLimitedFile")
expectation.expectedFulfillmentCount = 1
let filesystem = FileSystemStub()
let fimeManager = FileManagerStub()
let sizeLimitedFileFactory = SizeLimitedFileMockFactory(writeCall: expectation)
let logrotateFactory = LogrotateMockFactory()
let logger = DiskLogger(fileURL: logURL,
fileSizeLimit: 1024,
rotations: 1,
fileSystem: filesystem,
fileManager: fimeManager,
sizeLimitedFileFactory: sizeLimitedFileFactory,
logrotateFactory: logrotateFactory)
@ -61,13 +61,13 @@ class DiskLoggerTests: XCTestCase {
let expectation = XCTestExpectation(description: "write(_:) was called on SizeLimitedFile")
expectation.expectedFulfillmentCount = 2
let filesystem = FileSystemStub()
let fimeManager = FileManagerStub()
let sizeLimitedFileFactory = SizeLimitedFileMockFactory(writeCall: expectation)
let logrotateFactory = LogrotateMockFactory()
let logger = DiskLogger(fileURL: logURL,
fileSizeLimit: 91,
rotations: 1,
fileSystem: filesystem,
fileManager: fimeManager,
sizeLimitedFileFactory: sizeLimitedFileFactory,
logrotateFactory: logrotateFactory)
@ -90,13 +90,13 @@ class DiskLoggerTests: XCTestCase {
let expectation = XCTestExpectation(description: "write(_:) was called on SizeLimitedFile")
expectation.expectedFulfillmentCount = 2
let filesystem = FileSystemStub()
let fimeManager = FileManagerStub()
let sizeLimitedFileFactory = UnwritableFileStubFactory(writeCall: expectation)
let logrotateFactory = LogrotateMockFactory()
let logger = DiskLogger(fileURL: logURL,
fileSizeLimit: 91,
rotations: 1,
fileSystem: filesystem,
fileManager: fimeManager,
sizeLimitedFileFactory: sizeLimitedFileFactory,
logrotateFactory: logrotateFactory)
@ -116,7 +116,7 @@ class DiskLoggerTests: XCTestCase {
}
}
private class FileSystemStub: FileSystem {
private class FileManagerStub: OSFileManager {
func itemExists(at URL: URL) -> Bool {
return false
}

View file

@ -25,7 +25,7 @@
import XCTest
@testable import Logger
class FileRotateTests: XCTestCase {
class LogrotateTests: XCTestCase {
let logURL = URL(fileURLWithPath: "/var/log/application.log")
let log1URL = URL(fileURLWithPath: "/var/log/application.log.1")
@ -33,98 +33,98 @@ class FileRotateTests: XCTestCase {
let log3URL = URL(fileURLWithPath: "/var/log/application.log.3")
func test_1rotation_0files() {
let fileSystem = FileSystemMock(files: [])
let logrotate = FileRotate(fileURL: logURL, rotations: 1, fileSystem: fileSystem)
let fimeManager = FileManagerMock(files: [])
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 1, fileManager: fimeManager)
try? logrotate.rotate()
let actual = fileSystem.files
let actual = fimeManager.files
let expected = Set<URL>()
XCTAssertEqual(actual, expected)
}
func test_1rotation_1file() {
let fileSystem = FileSystemMock(files: [logURL])
let logrotate = FileRotate(fileURL: logURL, rotations: 1, fileSystem: fileSystem)
let fimeManager = FileManagerMock(files: [logURL])
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 1, fileManager: fimeManager)
try? logrotate.rotate()
let actual = fileSystem.files
let actual = fimeManager.files
let expected = Set<URL>([log1URL])
XCTAssertEqual(actual, expected)
}
func test_1rotation_2files() {
let fileSystem = FileSystemMock(files: [logURL, log1URL])
let logrotate = FileRotate(fileURL: logURL, rotations: 1, fileSystem: fileSystem)
let fimeManager = FileManagerMock(files: [logURL, log1URL])
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 1, fileManager: fimeManager)
try? logrotate.rotate()
let actual = fileSystem.files
let actual = fimeManager.files
let expected = Set<URL>([log1URL])
XCTAssertEqual(actual, expected)
}
func test_1rotation_3files() {
let fileSystem = FileSystemMock(files: [logURL, log1URL, log2URL])
let logrotate = FileRotate(fileURL: logURL, rotations: 1, fileSystem: fileSystem)
let fimeManager = FileManagerMock(files: [logURL, log1URL, log2URL])
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 1, fileManager: fimeManager)
try? logrotate.rotate()
let actual = fileSystem.files
let actual = fimeManager.files
let expected = Set<URL>([log1URL, log2URL])
XCTAssertEqual(actual, expected)
}
func test_2rotations_0files() {
let fileSystem = FileSystemMock(files: [])
let logrotate = FileRotate(fileURL: logURL, rotations: 2, fileSystem: fileSystem)
let fimeManager = FileManagerMock(files: [])
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 2, fileManager: fimeManager)
try? logrotate.rotate()
let actual = fileSystem.files
let actual = fimeManager.files
let expected = Set<URL>()
XCTAssertEqual(actual, expected)
}
func test_2rotations_1file() {
let fileSystem = FileSystemMock(files: [logURL])
let logrotate = FileRotate(fileURL: logURL, rotations: 2, fileSystem: fileSystem)
let fimeManager = FileManagerMock(files: [logURL])
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 2, fileManager: fimeManager)
try? logrotate.rotate()
let actual = fileSystem.files
let actual = fimeManager.files
let expected = Set<URL>([log1URL])
XCTAssertEqual(actual, expected)
}
func test_2rotations_2files() {
let fileSystem = FileSystemMock(files: [logURL, log1URL])
let logrotate = FileRotate(fileURL: logURL, rotations: 2, fileSystem: fileSystem)
let fimeManager = FileManagerMock(files: [logURL, log1URL])
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 2, fileManager: fimeManager)
try? logrotate.rotate()
let actual = fileSystem.files
let actual = fimeManager.files
let expected = Set<URL>([log1URL, log2URL])
XCTAssertEqual(actual, expected)
}
func test_2rotations_3files() {
let fileSystem = FileSystemMock(files: [logURL, log1URL, log2URL])
let logrotate = FileRotate(fileURL: logURL, rotations: 2, fileSystem: fileSystem)
let fimeManager = FileManagerMock(files: [logURL, log1URL, log2URL])
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 2, fileManager: fimeManager)
try? logrotate.rotate()
let actual = fileSystem.files
let actual = fimeManager.files
let expected = Set<URL>([log1URL, log2URL])
XCTAssertEqual(actual, expected)
}
func test_2rotations_4files() {
let fileSystem = FileSystemMock(files: [logURL, log1URL, log2URL, log3URL])
let logrotate = FileRotate(fileURL: logURL, rotations: 2, fileSystem: fileSystem)
let fimeManager = FileManagerMock(files: [logURL, log1URL, log2URL, log3URL])
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 2, fileManager: fimeManager)
try? logrotate.rotate()
let actual = fileSystem.files
let actual = fimeManager.files
let expected = Set<URL>([log1URL, log2URL, log3URL])
XCTAssertEqual(actual, expected)
}
func testErrorPropagation() {
let fileSystem = BrokenFileSystem()
let logrotate = FileRotate(fileURL: logURL, rotations: 1, fileSystem: fileSystem)
let fimeManager = BrokenFileSystem()
let logrotate = LogrotateImpl(fileURL: logURL, rotations: 1, fileManager: fimeManager)
XCTAssertThrowsError(try logrotate.rotate(), "An error when removing or moving an item") { (error) in
XCTAssertTrue(error is BrokenFileSystem.IOError)
@ -132,7 +132,7 @@ class FileRotateTests: XCTestCase {
}
}
private class FileSystemMock: FileSystem {
private class FileManagerMock: OSFileManager {
private(set) var files = Set<URL>()
@ -159,7 +159,7 @@ private class FileSystemMock: FileSystem {
}
}
private class BrokenFileSystem: FileSystem {
private class BrokenFileSystem: OSFileManager {
struct IOError: Error { }

View file

@ -25,20 +25,20 @@
import XCTest
@testable import Logger
class FileWriterTests: XCTestCase {
class SizeLimitedFileTests: XCTestCase {
let logURL = URL(fileURLWithPath: "/var/log/application.log")
func testFileOpeningFailure() {
let factory = UnopenableFileFactory()
XCTAssertThrowsError(try FileWriter(fileURL: logURL, fileSizeLimit: 0, fileFactory: factory), "file open failure") { (error) in
XCTAssertThrowsError(try SizeLimitedFileImpl(fileURL: logURL, fileSizeLimit: 0, fileFactory: factory), "file open failure") { (error) in
XCTAssertTrue(error is UnopenableFileFactory.OpenFileError)
}
}
func testKeepingFileSizeLimit() throws {
let factory = FileMockFactory()
let writer = try FileWriter(fileURL: logURL, fileSizeLimit: 1, fileFactory: factory)
let writer = try SizeLimitedFileImpl(fileURL: logURL, fileSizeLimit: 1, fileFactory: factory)
let data = Data([0])
try writer.write(data)
@ -47,7 +47,7 @@ class FileWriterTests: XCTestCase {
func testExceedingFileSizeLimit() throws {
let factory = FileMockFactory()
let writer = try FileWriter(fileURL: logURL, fileSizeLimit: 1, fileFactory: factory)
let writer = try SizeLimitedFileImpl(fileURL: logURL, fileSizeLimit: 1, fileFactory: factory)
let data = Data([0, 0])
XCTAssertThrowsError(try writer.write(data), "file size limit exceeded") { (error) in
@ -59,31 +59,31 @@ class FileWriterTests: XCTestCase {
func testSynchronizingAndClosingFile() throws {
let factory = FileMockFactory()
let writer = try FileWriter(fileURL: logURL, fileSizeLimit: 1, fileFactory: factory)
let writer = try SizeLimitedFileImpl(fileURL: logURL, fileSizeLimit: 1, fileFactory: factory)
writer.synchronizeAndCloseFile()
XCTAssertTrue(factory.mock.synchronizeFileCallCount == 1 && factory.mock.closeFileCallCount == 1)
}
}
private class UnopenableFileFactory: FileFactory {
private class UnopenableFileFactory: FileHandleFactory {
struct OpenFileError: Error {}
func makeInstance(forWritingTo: URL) throws -> File {
func makeInstance(forWritingTo: URL) throws -> OSFileHandle {
throw OpenFileError()
}
}
private class FileMockFactory: FileFactory {
private class FileMockFactory: FileHandleFactory {
let mock = FileMock()
func makeInstance(forWritingTo: URL) throws -> File {
func makeInstance(forWritingTo: URL) throws -> OSFileHandle {
return mock
}
}
private class FileMock: File {
private class FileMock: OSFileHandle {
private(set) var writtenData = Data()
private(set) var synchronizeFileCallCount = 0