//===----------------- 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 // //===----------------------------------------------------------------------===// // 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) 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) -> 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 argumentClosures = message.interpolation.arguments.argumentClosures let formatStringPointer = _getGlobalStringTablePointer(formatString) // Code that will execute at runtime. if (!isLoggingEnabled()) { return } // Allocate a byte buffer to store the arguments. The buffer could be stack // allocated as it is local to this function and also its size is a // compile-time constant. let bufferMemory = UnsafeMutablePointer.allocate(capacity: bufferSize) // Array of references to auxiliary storage created during serialization of // strings. This array can be stack allocated. var stringStorageObjects: [AnyObject] = [] var currentBufferPosition = bufferMemory serialize(preamble, at: ¤tBufferPosition) serialize(argumentCount, at: ¤tBufferPosition) argumentClosures.forEach { $0(¤tBufferPosition, &stringStorageObjects) } _os_log_impl_test( assertion, formatString, formatStringPointer, bufferMemory, UInt32(bufferSize)) // The following operation extends the lifetime of argumentClosures, // stringStorageObjects, and also of the objects stored in them, 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. _fixLifetime(argumentClosures) _fixLifetime(stringStorageObjects) bufferMemory.deallocate() } /// A function that pretends to be _os_log_impl. @inline(never) @usableFromInline internal func _os_log_impl_test( _ assertion: (String, UnsafeBufferPointer) -> Void, _ formatString: String, _ formatStringPointer: UnsafePointer, _ bufferMemory: UnsafeMutablePointer, _ bufferSize: UInt32 ) { assertion( formatString, UnsafeBufferPointer( start: UnsafePointer(bufferMemory), count: Int(bufferSize))) }