| //===----------------- OSLogTestHelper.swift ----------------------------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| import ObjectiveC |
| |
| // This file contains test helpers for testing the compiler diagnostics and optimizations |
| // of the new swift APIs for os log that accept string interpolations. |
| |
| // Some functions defined in this file are marked @_optimize(none) to prevent inlining |
| // of string internals (such as String._StringGuts) which will interfere with |
| // constant evaluation and folding. Note that these functions will be inlined, |
| // constant evaluated, folded and optimized in the context of a caller. TODO: |
| // @_optimize(none) can be removed if (non-mandatory) inlining optimizations can be moved |
| // after serialization. |
| |
| /// A function that acts like a check for whether logging is enabled in `_osLogTestHelper`. |
| @inline(never) |
| @usableFromInline |
| internal func isLoggingEnabled() -> Bool { true } |
| |
| /// A closure that does nothing. Meant to be used as the default assertion of |
| /// `_osLogTestHelper`. |
| public let _noopClosure = { (x : String, y : UnsafeBufferPointer<UInt8>) in return } |
| |
| /// A test helper that constructs a byte buffer and a format string from an |
| /// instance of `OSLogMessage` using the same logic as the new os log APIs, |
| /// and applies a given `assertion` to the constructed format string and |
| /// byte buffer. This function should be used only in tests. |
| /// - Parameters: |
| /// - message: An instance of `OSLogMessage` created from string interpolation |
| /// - assertion: A closure that takes a format string and a pointer to a |
| /// byte buffer and asserts a condition. |
| @_semantics("oslog.requires_constant_arguments") |
| @_transparent |
| @_optimize(none) |
| public // @testable |
| func _osLogTestHelper( |
| _ message: OSLogMessage, |
| assertion: (String, UnsafeBufferPointer<UInt8>) -> Void = _noopClosure |
| ) { |
| // Compute static constants first so that they can be folded by |
| // OSLogOptimization pass. |
| let formatString = message.interpolation.formatString |
| let preamble = message.interpolation.preamble |
| let argumentCount = message.interpolation.argumentCount |
| let bufferSize = message.bufferSize |
| let objectCount = message.interpolation.objectArgumentCount |
| let stringCount = message.interpolation.stringArgumentCount |
| let uint32bufferSize = UInt32(bufferSize) |
| let argumentClosures = message.interpolation.arguments.argumentClosures |
| |
| let formatStringPointer = _getGlobalStringTablePointer(formatString) |
| |
| // Code that will execute at runtime. |
| if (!isLoggingEnabled()) { |
| return |
| } |
| let bufferMemory = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize) |
| // Buffer for storing NSObjects and strings to keep them alive until the |
| // _os_log_impl_test call completes. |
| let objectArguments = createStorage(capacity: objectCount, type: NSObject.self) |
| let stringArgumentOwners = createStorage(capacity: stringCount, type: Any.self) |
| |
| var currentBufferPosition = bufferMemory |
| var objectArgumentsPosition = objectArguments |
| var stringArgumentOwnersPosition = stringArgumentOwners |
| serialize(preamble, at: ¤tBufferPosition) |
| serialize(argumentCount, at: ¤tBufferPosition) |
| argumentClosures.forEach { |
| $0(¤tBufferPosition, |
| &objectArgumentsPosition, |
| &stringArgumentOwnersPosition) |
| } |
| |
| _os_log_impl_test( |
| assertion, |
| formatString, |
| formatStringPointer, |
| bufferMemory, |
| uint32bufferSize) |
| |
| // The following operation extends the lifetime of objectArguments and |
| // stringArgumentOwners till this point. This is necessary because the |
| // assertion is passed internal pointers to the objects/strings stored |
| // in these arrays, as in the actual os log implementation. |
| destroyStorage(objectArguments, count: objectCount) |
| destroyStorage(stringArgumentOwners, count: stringCount) |
| bufferMemory.deallocate() |
| } |
| |
| /// A function that pretends to be _os_log_impl. |
| @inline(never) |
| @usableFromInline |
| internal func _os_log_impl_test( |
| _ assertion: (String, UnsafeBufferPointer<UInt8>) -> Void, |
| _ formatString: String, |
| _ formatStringPointer: UnsafePointer<CChar>, |
| _ bufferMemory: UnsafeMutablePointer<UInt8>, |
| _ bufferSize: UInt32 |
| ) { |
| assertion( |
| formatString, |
| UnsafeBufferPointer( |
| start: UnsafePointer(bufferMemory), |
| count: Int(bufferSize))) |
| } |