Skip to content

Commit

Permalink
Renaming TestTools to TestHarness... (#51)
Browse files Browse the repository at this point in the history
* Renaming TestTools to Testharness and moving them to the main library as a module.
* Adding TestHarnessTests as a module in the TraceLog library.
  • Loading branch information
tonystone committed Jun 26, 2018
1 parent 3dc095c commit 0fa6201
Show file tree
Hide file tree
Showing 8 changed files with 483 additions and 27 deletions.
12 changes: 6 additions & 6 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,27 @@ let package = Package(
name: "TraceLog",
targets: [
/// Module targets
.target(name: "TraceLog", dependencies: [], path: "Sources/TraceLog"),
.target(name: "TraceLogTestTools", dependencies: ["TraceLog"], path: "Tests/TraceLogTestTools"),
.target(name: "TraceLog", dependencies: [], path: "Sources/TraceLog"),
.target(name: "TraceLogTestHarness", dependencies: ["TraceLog"], path: "Sources/TraceLogTestHarness"),

/// Tests
.testTarget(name: "TraceLogTests", dependencies: ["TraceLog", "TraceLogTestTools"], path: "Tests/TraceLogTests")
.testTarget(name: "TraceLogTests", dependencies: ["TraceLog", "TraceLogTestHarness"], path: "Tests/TraceLogTests"),
.testTarget(name: "TraceLogTestHarnessTests", dependencies: ["TraceLog", "TraceLogTestHarness"], path: "Tests/TraceLogTestHarnessTests")
],
swiftLanguageVersions: [4]
)

var productTargets = ["TraceLog"]
var productTargets = ["TraceLog", "TraceLogTestHarness"]

///
/// These platforms can also support Objective-C so we create a module for it.
///
#if os(iOS) || os(macOS) || os(watchOS) || os(tvOS)
package.targets.append(.target(name: "TraceLogObjC", dependencies: ["TraceLog"], path: "Sources/TraceLogObjC"))
package.targets.append(.target(name: "TraceLogObjC", dependencies: ["TraceLog"], path: "Sources/TraceLogObjC"))
package.targets.append(.testTarget(name: "TraceLogObjCTests", dependencies: ["TraceLogObjC"], path: "Tests/TraceLogObjCTests"))

productTargets.append("TraceLogObjC")
#endif

/// Main products section
package.products.append(.library(name: "TraceLog", type: .dynamic, targets: productTargets))
package.products.append(.library(name: "TraceLogTestTools", type: .dynamic, targets: ["TraceLogTestTools"]))
43 changes: 43 additions & 0 deletions Sources/TraceLogTestHarness/BufferReader.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
///
/// BufferReader.swift
///
/// Copyright 2018 Tony Stone
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http:https://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Created by Tony Stone on 6/25/18.
///
import TraceLog

///
/// A test `Reader` implementation that reads the `BufferWriter`s buffer for validating results.
///
public class BufferReader: Reader {

public func logEntry(for writer: BufferWriter, timestamp: Double, level: LogLevel, tag: String, message: String, runtimeContext: RuntimeContext, staticContext: StaticContext) -> LogEntry? {

guard let logEntry = writer.buffer[message]
else { return nil }

return LogEntry(timestamp: logEntry.timestamp,
level: logEntry.level,
message: logEntry.message,
tag: logEntry.tag,
file: logEntry.staticContext.file,
function: logEntry.staticContext.function,
line: logEntry.staticContext.line,
processName: logEntry.runtimeContext.processName,
processIdentifier: logEntry.runtimeContext.processIdentifier,
threadIdentifier: Int(logEntry.runtimeContext.threadIdentifier))
}
}
38 changes: 38 additions & 0 deletions Sources/TraceLogTestHarness/BufferWriter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
///
/// BufferWriter.swift
///
/// Copyright 2018 Tony Stone
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http:https://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Created by Tony Stone on 6/25/18.
///
import TraceLog

///
/// A test `Writer` implementation that writes all logged messages to a buffer which can then be queried to analyze the results.
///
public class BufferWriter: Writer {

///
/// A buffer to hold the values written to this writer.
///
public var buffer: [String: (timestamp: Double, level: LogLevel, tag: String, message: String, runtimeContext: RuntimeContext, staticContext: StaticContext)] = [:]

///
/// Required log function for the `Writer`.
///
public func log(_ timestamp: Double, level: LogLevel, tag: String, message: String, runtimeContext: RuntimeContext, staticContext: StaticContext) {
self.buffer[message] = (timestamp, level, tag, message, runtimeContext, staticContext)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,33 +46,26 @@ public class TestHarness<T: Reader> {
///
public let writer: T.WriterType

///
/// Instance of a Reader to use for validating the results of the test.
///
public var reader: T {
return _reader.reader
}

///
/// Boxed version of the reader so it can be stored.
///
private let _reader: _AnyReaderBox<T>
private let reader: _AnyReaderBox<T>

///
/// Initialize a test harness with the specified writer that is under test and a reader to search for the entry so it can be validated.
///
public init(writer: T.WriterType, reader: T) {
self.writer = writer
self._reader = _AnyReaderBox(reader)
self.reader = _AnyReaderBox(reader)
}

///
/// Executes test block (that must contain a call one of TraceLogs log functions) and validates the results.
///
public func testLog(for level: LogLevel, tag tagOrNil: String? = nil, message messageOrNil: String? = nil, _ file: String = #file, _ function: String = #function, _ line: Int = #line,
public func testLog(for level: LogLevel, tag tagOrNil: String? = nil, message messageOrNil: String? = nil, file: String = #file, function: String = #function, line: Int = #line,
testBlock: (String, String, String, String, Int) -> Void, validationBlock: (_ writer: T.WriterType, _ result: LogEntry?, _ expected: LogEntry)-> Void) {

self._testLog(for: level, tag: tagOrNil, message: messageOrNil, file, function, line, testBlock: { (timestamp, level, tag, message, runtimeContext, staticContext) in
self._testLog(for: level, tag: tagOrNil, message: messageOrNil, file: file, function: function, line: line, testBlock: { (timestamp, level, tag, message, runtimeContext, staticContext) in

testBlock(tag, message, file, function, line)

Expand All @@ -82,10 +75,10 @@ public class TestHarness<T: Reader> {
///
/// Calls the writer directly with the given LogLevel and validates the results.
///
public func testLog(for level: LogLevel, tag tagOrNil: String? = nil, message messageOrNil: String? = nil, _ file: String = #file, _ function: String = #function, _ line: Int = #line,
public func testLog(for level: LogLevel, tag tagOrNil: String? = nil, message messageOrNil: String? = nil, file: String = #file, function: String = #function, line: Int = #line,
validationBlock: (_ writer: T.WriterType, _ result: LogEntry?, _ expected: LogEntry)-> Void) {

self._testLog(for: level, tag: tagOrNil, message: messageOrNil, file, function, line, testBlock: { (timestamp, level, tag, message, runtimeContext, staticContext) in
self._testLog(for: level, tag: tagOrNil, message: messageOrNil, file: file, function: function, line: line, testBlock: { (timestamp, level, tag, message, runtimeContext, staticContext) in

/// Execute the test
self.writer.log(timestamp, level: level, tag: tag, message: message, runtimeContext: runtimeContext, staticContext: staticContext)
Expand All @@ -96,7 +89,7 @@ public class TestHarness<T: Reader> {
///
/// Test a TraceLog log message to a writer.
///
private func _testLog(for level: LogLevel, tag tagOrNil: String? = nil, message messageOrNil: String? = nil, _ file: String = #file, _ function: String = #function, _ line: Int = #line,
private func _testLog(for level: LogLevel, tag tagOrNil: String? = nil, message messageOrNil: String? = nil, file: String = #file, function: String = #function, line: Int = #line,
testBlock: (Double, LogLevel, String, String, RuntimeContext, StaticContext) -> Void, validationBlock: (_ writer: T.WriterType, _ result: LogEntry?, _ expected: LogEntry)-> Void) {

/// This is the time in microseconds since the epoch UTC to match the journals time stamps.
Expand All @@ -111,7 +104,7 @@ public class TestHarness<T: Reader> {
/// Execute the test
testBlock(timestamp, level, tag, message, runtimeContext, staticContext)

let result = self._reader.logEntry(for: writer, timestamp: timestamp, level: level, tag: tag, message: message, runtimeContext: runtimeContext, staticContext: staticContext)
let result = self.reader.logEntry(for: self.writer, timestamp: timestamp, level: level, tag: tag, message: message, runtimeContext: runtimeContext, staticContext: staticContext)

let expected = LogEntry(timestamp: timestamp, level: level, message: message, tag: tag, file: staticContext.file, function: staticContext.function, line: staticContext.line, processName: runtimeContext.processName, processIdentifier: runtimeContext.processIdentifier, threadIdentifier: Int(runtimeContext.threadIdentifier))

Expand Down Expand Up @@ -177,10 +170,6 @@ private class _AnyReaderBox<ConcreteReader: Reader>: _AnyReaderBase<ConcreteRead
/// Private boxing class base for use in storing our Reader which has an associated type.
///
private class _AnyReaderBase<T: Writer>: Reader {
init() {
guard type(of: self) != _AnyReaderBase.self
else { fatalError("Cannot initialize, must be subclass") }
}

func logEntry(for writer: T, timestamp: Double, level: LogLevel, tag: String, message: String, runtimeContext: RuntimeContext, staticContext: StaticContext) -> LogEntry? {
fatalError("Must override")
Expand Down Expand Up @@ -218,6 +207,14 @@ private struct TestRuntimeContext: RuntimeContext {
let process = ProcessInfo.processInfo
self.processName = process.processName
self.processIdentifier = Int(process.processIdentifier)
self.threadIdentifier = threadIdentifier

#if os(iOS) || os(macOS) || os(watchOS) || os(tvOS)
var threadID: UInt64 = 0

pthread_threadid_np(pthread_self(), &threadID)
self.threadIdentifier = threadID
#else // FIXME: Linux does not support the pthread_threadid_np function, gettid in s syscall must be used.
self.threadIdentifier = 0
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ import XCTest
///
/// Helper to run the shell and return the output
///
@available(iOS, unavailable)
@available(tvOS, unavailable)
@available(watchOS, unavailable)
public func shell(_ command: String) -> Data {
let task = Process()
task.launchPath = "/bin/bash"
Expand Down
49 changes: 48 additions & 1 deletion Tests/LinuxMain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
import XCTest

@testable import TraceLogTests
@testable import TraceLogTestHarnessTests

XCTMain([
testCase(TraceLogPerformanceTestsSwift.allTests),
testCase(TraceLogTestsSwift.allTests),
testCase(EnvironmentTests.allTests),
testCase(ConfigurationTests.allTests)
testCase(ConfigurationTests.allTests),
testCase(TestHarnessTests.allTests),
testCase(TestUtilitiesTests.allTests)
])

extension TraceLogPerformanceTestsSwift {
Expand Down Expand Up @@ -95,4 +98,48 @@ extension ConfigurationTests {
}
}

extension TestHarnessTests {

static var allTests: [(String, (TestHarnessTests) -> () throws -> Void)] {
return [
("testLogForError", testLogForError),
("testLogForWarning", testLogForWarning),
("testLogForInfo", testLogForInfo),
("testLogForTrace1", testLogForTrace1),
("testLogForTrace2", testLogForTrace2),
("testLogForTrace3", testLogForTrace3),
("testLogForTrace4", testLogForTrace4),

("testLogWithCustomMessage", testLogWithCustomMessage),
("testLogWithCustomTag", testLogWithCustomTag),
("testLogWithCustomFile", testLogWithCustomFile),
("testLogWithCustomFunction", testLogWithCustomFunction),
("testLogWithCustomLine", testLogWithCustomLine),

("testLogTestBlockForError", testLogTestBlockForError),
("testLogTestBlockForWarning", testLogTestBlockForWarning),
("testLogTestBlockForInfo", testLogTestBlockForInfo),
("testLogTestBlockForTrace1", testLogTestBlockForTrace1),
("testLogTestBlockForTrace2", testLogTestBlockForTrace2),
("testLogTestBlockForTrace3", testLogTestBlockForTrace3),
("testLogTestBlockForTrace4", testLogTestBlockForTrace4),

("testLogTestBlockWithCustomMessage", testLogTestBlockWithCustomMessage),
("testLogTestBlockWithCustomTag", testLogTestBlockWithCustomTag),
("testLogTestBlockWithCustomFile", testLogTestBlockWithCustomFile),
("testLogTestBlockWithCustomFunction", testLogTestBlockWithCustomFunction),
("testLogTestBlockWithCustomLine", testLogTestBlockWithCustomLine)
]
}
}

extension TestUtilitiesTests {

static var allTests: [(String, (TestUtilitiesTests) -> () throws -> Void)] {
return [
("testShell", testShell)
]
}
}

#endif
Loading

0 comments on commit 0fa6201

Please sign in to comment.