Skip to content

Commit

Permalink
Make this work for glib>=2.73: only set the log writer once.
Browse files Browse the repository at this point in the history
  • Loading branch information
rhx committed Jun 15, 2024
1 parent 736205b commit 56c5715
Showing 1 changed file with 66 additions and 36 deletions.
102 changes: 66 additions & 36 deletions Tests/GLibTests/GLibTests.swift
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
#if os(Linux)
import Glibc
import Glibc
#else
import Darwin
import Darwin
#endif

import XCTest
import CGLib
@testable import GLib

let logWrapper = LogWriterWrapper()

#if os(macOS)
let semaphore = DispatchSemaphore(value: 1)
#endif

class GLibTests: XCTestCase {

/// check that we can get the current date and time
Expand Down Expand Up @@ -35,9 +41,12 @@ class GLibTests: XCTestCase {
guard let dir = try Dir.open(path: existing_path, flags: 0) else {
XCTFail() ; return
}

defer { dir.close() }
let first: String! = dir.readName() // get the first entry

let first: String? = dir.readName() // get the first entry
XCTAssertNotNil(first)
guard let first = first else { return }
XCTAssertFalse(first.isEmpty)
dir.rewind() // go back
let first_again = dir.readName() // get first entry again
Expand Down Expand Up @@ -124,18 +133,23 @@ class GLibTests: XCTestCase {
XCTAssertFalse(context.pending())
}

// FIXME: macOS concurrency interferes with testing multiple different log hooks
#if !os(macOS)
func testLog() {
#if os(macOS)
semaphore.wait()
defer { semaphore.signal() }
#endif
var logResult = false
var logWriterResult = false
let old = withUnsafeMutablePointer(to: &logResult) {
(result: UnsafeMutablePointer<Bool>) -> GLogFunc in
logSetWriterFunc(func: {
guard LogLevelFlags($0) == .debug, let fields = $1,
let resultPtr = $3?.assumingMemoryBound(to: Bool.self) else { return .unhandled }
resultPtr.pointee = strcmp(fields[0].value.assumingMemoryBound(to: CChar.self), "testLog") == 0
return .handled
}, userData: gpointer(result), userDataFree: { _ in })
logWrapper.logClosure = {
let fields = $1
XCTAssertEqual($0, .debug)
XCTAssertEqual($2, 3)
guard $2 == 3 else { return }
logWriterResult = strcmp(fields[1].value.assumingMemoryBound(to: CChar.self), "testLogWriter") == 0
}
g_log("testLogWriter")
return g_log_set_default_handler({
guard $0 == nil, LogLevelFlags($1) == .debug,
let message = $2,
Expand All @@ -145,19 +159,19 @@ class GLibTests: XCTestCase {
}
g_log("testLog")
g_log_set_default_handler(old, nil)
logWrapper.logClosure = printLog
XCTAssertTrue(logWriterResult)
XCTAssertTrue(logResult)
}

func testLogLevel() {
#if os(macOS)
semaphore.wait()
defer { semaphore.signal() }
#endif
var logResult = false
let old = withUnsafeMutablePointer(to: &logResult) {
(result: UnsafeMutablePointer<Bool>) -> GLogFunc in
logSetWriterFunc(func: {
guard LogLevelFlags($0) == .critical, let fields = $1,
let resultPtr = $3?.assumingMemoryBound(to: Bool.self) else { return .unhandled }
resultPtr.pointee = strcmp(fields[0].value.assumingMemoryBound(to: CChar.self), "testLogLevel") == 0
return .handled
}, userData: gpointer(result), userDataFree: { _ in })
return g_log_set_default_handler({
guard $0 == nil, LogLevelFlags($1) == .critical,
let message = $2,
Expand All @@ -171,49 +185,42 @@ class GLibTests: XCTestCase {
}

func testLogDomain() {
#if os(macOS)
semaphore.wait()
defer { semaphore.signal() }
#endif
var logResult = false
let old = withUnsafeMutablePointer(to: &logResult) {
(result: UnsafeMutablePointer<Bool>) -> GLogFunc in
logSetWriterFunc(func: {
guard LogLevelFlags($0) == .debug, let fields = $1,
let resultPtr = $3?.assumingMemoryBound(to: Bool.self) else { return .unhandled }
resultPtr.pointee = strcmp(fields[0].value.assumingMemoryBound(to: CChar.self), "test") == 0
&& strcmp(fields[2].value.assumingMemoryBound(to: CChar.self), "testDomain") == 0
return .handled
}, userData: gpointer(result), userDataFree: { _ in })
return g_log_set_default_handler({
guard let domain = $0, LogLevelFlags($1) == .debug,
let message = $2,
let resultPtr = $3?.assumingMemoryBound(to: Bool.self) else { return }
resultPtr.pointee =
strcmp(domain, "testDomain") == 0 &&
strcmp(message, "test") == 0
strcmp(domain, "testDomain") == 0 &&
strcmp(message, "test") == 0
}, gpointer(result))
}
g_log(domain: "testDomain", "test")
g_log_set_default_handler(old, nil)
XCTAssertTrue(logResult)
}
#endif

func testLogDomainLevel() {
#if os(macOS)
semaphore.wait()
defer { semaphore.signal() }
#endif
var logResult = false
let old = withUnsafeMutablePointer(to: &logResult) {
(result: UnsafeMutablePointer<Bool>) -> GLogFunc in
logSetWriterFunc(func: {
guard LogLevelFlags($0) == .message, let fields = $1,
let resultPtr = $3?.assumingMemoryBound(to: Bool.self) else { return .unhandled }
resultPtr.pointee = strcmp(fields[0].value.assumingMemoryBound(to: CChar.self), "%%s") == 0
&& strcmp(fields[2].value.assumingMemoryBound(to: CChar.self), "testDomainLevel") == 0
return .handled
}, userData: gpointer(result), userDataFree: { _ in })
return g_log_set_default_handler({
guard let domain = $0, LogLevelFlags($1) == .message,
let message = $2,
let resultPtr = $3?.assumingMemoryBound(to: Bool.self) else { return }
resultPtr.pointee =
strcmp(domain, "testDomainLevel") == 0 &&
strcmp(message, "%s") == 0
strcmp(domain, "testDomainLevel") == 0 &&
strcmp(message, "%s") == 0
}, gpointer(result))
}
g_log(domain: "testDomainLevel", "%s", level: .message)
Expand Down Expand Up @@ -436,3 +443,26 @@ class GLibTests: XCTestCase {
XCTAssertNotEqual(array1.ptr, array2.ptr)
}
}

class LogWriterWrapper {
var logClosure: (LogLevelFlags, UnsafePointer<GLogField>, gsize) -> Void = printLog

init() {
let opaqueSelf = Unmanaged.passRetained(self).toOpaque()
logSetWriterFunc(func: {
guard let fields = $1, let opaqueSelf = $3, opaqueSelf == Unmanaged.passUnretained(logWrapper).toOpaque() else { return .unhandled }
let this = Unmanaged<LogWriterWrapper>.fromOpaque(opaqueSelf).takeRetainedValue()
this.logClosure(LogLevelFlags($0), fields, $2)
return .handled
}, userData: gpointer(opaqueSelf), userDataFree: { _ in })
}
}

private let printLog: (LogLevelFlags, UnsafePointer<GLogField>, gsize) -> Void = {
let fields = $1
print("\($0):", terminator: " ")
for i in 0..<Int($2) {
print("\(String(cString: fields[i].value.assumingMemoryBound(to: CChar.self)))", terminator: " ")
}
print("")
}

0 comments on commit 56c5715

Please sign in to comment.