mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
604 lines
17 KiB
Swift
604 lines
17 KiB
Swift
//===--- LoggingWrappers.swift.gyb ----------------------------*- swift -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import StdlibUnittest
|
|
|
|
public protocol WrapperType {
|
|
associatedtype Base
|
|
init(_: Base)
|
|
var base: Base {get set}
|
|
}
|
|
|
|
public protocol LoggingType : WrapperType {
|
|
associatedtype Log : AnyObject
|
|
}
|
|
|
|
extension LoggingType {
|
|
public var log: Log.Type {
|
|
return Log.self
|
|
}
|
|
|
|
public var selfType: Any.Type {
|
|
return self.dynamicType
|
|
}
|
|
}
|
|
|
|
public class GeneratorLog {
|
|
public static func dispatchTester<G: GeneratorType>(
|
|
g: G
|
|
) -> LoggingGenerator<LoggingGenerator<G>> {
|
|
return LoggingGenerator(LoggingGenerator(g))
|
|
}
|
|
public static var next = TypeIndexed(0)
|
|
}
|
|
|
|
public struct LoggingGenerator<Base: GeneratorType>
|
|
: GeneratorType, LoggingType {
|
|
|
|
public typealias Log = GeneratorLog
|
|
|
|
public init(_ base: Base) {
|
|
self.base = base
|
|
}
|
|
|
|
public mutating func next() -> Base.Element? {
|
|
Log.next[selfType] += 1
|
|
return base.next()
|
|
}
|
|
|
|
public var base: Base
|
|
}
|
|
|
|
/// Data container to keep track of how many times each `Base` type calls methods
|
|
/// of RangeReplaceableCollectionType.
|
|
///
|
|
/// Each static variable is a mapping of Type -> Number of calls.
|
|
public class RangeReplaceableCollectionLog {
|
|
public static var init_ = TypeIndexed(0)
|
|
public static var initWithSequence = TypeIndexed(0)
|
|
public static var append = TypeIndexed(0)
|
|
public static var appendContentsOf = TypeIndexed(0)
|
|
public static var insert = TypeIndexed(0)
|
|
public static var removeAll = TypeIndexed(0)
|
|
public static var removeAtIndex = TypeIndexed(0)
|
|
public static var _customRemoveLast = TypeIndexed(0)
|
|
public static var _customRemoveLastN = TypeIndexed(0)
|
|
public static var removeRange = TypeIndexed(0)
|
|
public static var removeFirst = TypeIndexed(0)
|
|
public static var removeFirstN = TypeIndexed(0)
|
|
public static var replaceRange = TypeIndexed(0)
|
|
public static var reserveCapacity = TypeIndexed(0)
|
|
public static var insertContentsOf = TypeIndexed(0)
|
|
|
|
public static func dispatchTester<C: RangeReplaceableCollectionType>(
|
|
rrc: C
|
|
) -> LoggingRangeReplaceableCollection<LoggingRangeReplaceableCollection<C>> {
|
|
return LoggingRangeReplaceableCollection(
|
|
LoggingRangeReplaceableCollection(rrc)
|
|
)
|
|
}
|
|
}
|
|
|
|
/// Interposes between RangeReplaceableCollectionType method calls to
|
|
/// increment each method's counter.
|
|
public struct LoggingRangeReplaceableCollection<
|
|
Base: RangeReplaceableCollectionType
|
|
> : RangeReplaceableCollectionType, LoggingType {
|
|
|
|
public typealias Index = Base.Index
|
|
public typealias Log = RangeReplaceableCollectionLog
|
|
|
|
public var base: Base
|
|
|
|
public init() {
|
|
self.base = Base()
|
|
Log.init_[selfType] += 1
|
|
}
|
|
|
|
public init<
|
|
S : SequenceType where S.Generator.Element == Generator.Element
|
|
>(_ elements: S) {
|
|
self.base = Base(elements)
|
|
Log.initWithSequence[selfType] += 1
|
|
}
|
|
|
|
public init(_ base: Base) {
|
|
self.base = base
|
|
}
|
|
|
|
public var count: Base.Index.Distance {
|
|
return base.count
|
|
}
|
|
|
|
public var first: Base.Generator.Element? {
|
|
return base.first
|
|
}
|
|
|
|
public var isEmpty: Bool {
|
|
return base.isEmpty
|
|
}
|
|
|
|
public var startIndex: Base.Index {
|
|
return base.startIndex
|
|
}
|
|
|
|
public var endIndex: Base.Index {
|
|
return base.endIndex
|
|
}
|
|
|
|
public subscript(position: Base.Index) -> Base.Generator.Element {
|
|
return base[position]
|
|
}
|
|
|
|
public mutating func replaceRange<
|
|
C : CollectionType where C.Generator.Element == Base.Generator.Element
|
|
>(
|
|
subRange: Range<Base.Index>, with newElements: C
|
|
) {
|
|
Log.replaceRange[selfType] += 1
|
|
base.replaceRange(subRange, with: newElements)
|
|
}
|
|
|
|
public mutating func append(newElement: Base.Generator.Element) {
|
|
Log.append[selfType] += 1
|
|
base.append(newElement)
|
|
}
|
|
|
|
public mutating func appendContentsOf<
|
|
S : SequenceType where S.Generator.Element == Base.Generator.Element
|
|
>(newElements: S) {
|
|
Log.appendContentsOf[selfType] += 1
|
|
base.appendContentsOf(newElements)
|
|
}
|
|
|
|
public mutating func insert(
|
|
newElement: Base.Generator.Element, atIndex i: Base.Index
|
|
) {
|
|
Log.insert[selfType] += 1
|
|
base.insert(newElement, atIndex: i)
|
|
}
|
|
|
|
public mutating func removeAtIndex(index: Base.Index) -> Base.Generator.Element {
|
|
Log.removeAtIndex[selfType] += 1
|
|
return base.removeAtIndex(index)
|
|
}
|
|
|
|
public mutating func _customRemoveLast() -> Base.Generator.Element? {
|
|
Log._customRemoveLast[selfType] += 1
|
|
return base._customRemoveLast()
|
|
}
|
|
|
|
public mutating func _customRemoveLast(n: Int) -> Bool {
|
|
Log._customRemoveLastN[selfType] += 1
|
|
return base._customRemoveLast(n)
|
|
}
|
|
|
|
public mutating func removeFirst() -> Base.Generator.Element {
|
|
Log.removeFirst[selfType] += 1
|
|
return base.removeFirst()
|
|
}
|
|
|
|
public mutating func removeFirst(n: Int) {
|
|
Log.removeFirstN[selfType] += 1
|
|
base.removeFirst(n)
|
|
}
|
|
|
|
public mutating func removeRange(subRange: Range<Base.Index>) {
|
|
Log.removeRange[selfType] += 1
|
|
base.removeRange(subRange)
|
|
}
|
|
|
|
public mutating func removeAll(keepCapacity keepCapacity: Bool) {
|
|
Log.removeAll[selfType] += 1
|
|
base.removeAll(keepCapacity: keepCapacity)
|
|
}
|
|
|
|
public mutating func reserveCapacity(n: Base.Index.Distance) {
|
|
Log.reserveCapacity[selfType] += 1
|
|
base.reserveCapacity(n)
|
|
}
|
|
|
|
public mutating func insertContentsOf<
|
|
C : CollectionType where C.Generator.Element == Base.Generator.Element
|
|
>(newElements: C, at i: Base.Index) {
|
|
Log.insertContentsOf[selfType] += 1
|
|
base.insertContentsOf(newElements, at: i)
|
|
}
|
|
|
|
@warn_unused_result
|
|
public func map<T>(
|
|
@noescape transform: (Base.Generator.Element) throws -> T
|
|
) rethrows -> [T] {
|
|
return try base.map(transform)
|
|
}
|
|
|
|
@warn_unused_result
|
|
public func filter(
|
|
@noescape includeElement: (Base.Generator.Element) throws -> Bool
|
|
) rethrows -> [Base.Generator.Element] {
|
|
return try base.filter(includeElement)
|
|
}
|
|
|
|
public func generate() -> Base.Generator {
|
|
return base.generate()
|
|
}
|
|
}
|
|
|
|
public class ForwardIndexLog {
|
|
public static var successor = TypeIndexed(0)
|
|
public static var advancedBy = TypeIndexed(0)
|
|
public static var advancedByWithLimit = TypeIndexed(0)
|
|
public static var distanceTo = TypeIndexed(0)
|
|
|
|
public class func dispatchTester<I : ForwardIndexType>(
|
|
i: I
|
|
) -> LoggingForwardIndex<LoggingForwardIndex<I>> {
|
|
return LoggingForwardIndex(LoggingForwardIndex(i))
|
|
}
|
|
}
|
|
|
|
public class BidirectionalIndexLog : ForwardIndexLog {
|
|
public static var predecessor = TypeIndexed(0)
|
|
|
|
public class func dispatchTester<I : BidirectionalIndexType>(
|
|
i: I
|
|
) -> LoggingBidirectionalIndex<LoggingBidirectionalIndex<I>> {
|
|
return LoggingBidirectionalIndex(LoggingBidirectionalIndex(i))
|
|
}
|
|
}
|
|
|
|
public class RandomAccessIndexLog : BidirectionalIndexLog {
|
|
public class func dispatchTester<I : RandomAccessIndexType>(
|
|
i: I
|
|
) -> LoggingRandomAccessIndex<LoggingRandomAccessIndex<I>> {
|
|
return LoggingRandomAccessIndex(LoggingRandomAccessIndex(i))
|
|
}
|
|
}
|
|
|
|
public class SequenceLog {
|
|
public static func dispatchTester<S: SequenceType>(
|
|
s: S
|
|
) -> LoggingSequence<LoggingSequence<S>> {
|
|
return LoggingSequence(LoggingSequence(s))
|
|
}
|
|
public static var forEach = TypeIndexed(0)
|
|
public static var generate = TypeIndexed(0)
|
|
public static var underestimateCount = TypeIndexed(0)
|
|
public static var map = TypeIndexed(0)
|
|
public static var filter = TypeIndexed(0)
|
|
public static var dropFirst = TypeIndexed(0)
|
|
public static var dropLast = TypeIndexed(0)
|
|
public static var prefix = TypeIndexed(0)
|
|
public static var suffix = TypeIndexed(0)
|
|
public static var split = TypeIndexed(0)
|
|
public static var _customContainsEquatableElement = TypeIndexed(0)
|
|
public static var _preprocessingPass = TypeIndexed(0)
|
|
public static var _copyToNativeArrayBuffer = TypeIndexed(0)
|
|
public static var _initializeTo = TypeIndexed(0)
|
|
}
|
|
|
|
public class CollectionLog : SequenceLog {
|
|
public class func dispatchTester<C : CollectionType>(
|
|
c: C
|
|
) -> LoggingCollection<LoggingCollection<C>> {
|
|
return LoggingCollection(LoggingCollection(c))
|
|
}
|
|
public static var startIndex = TypeIndexed(0)
|
|
public static var endIndex = TypeIndexed(0)
|
|
public static var prefixUpTo = TypeIndexed(0)
|
|
public static var prefixThrough = TypeIndexed(0)
|
|
public static var subscriptIndex = TypeIndexed(0)
|
|
public static var subscriptRange = TypeIndexed(0)
|
|
public static var suffixFrom = TypeIndexed(0)
|
|
public static var isEmpty = TypeIndexed(0)
|
|
public static var count = TypeIndexed(0)
|
|
public static var _customIndexOfEquatableElement = TypeIndexed(0)
|
|
public static var first = TypeIndexed(0)
|
|
}
|
|
|
|
public class MutableCollectionLog : CollectionLog {
|
|
public class func dispatchTester<C : MutableCollectionType>(
|
|
c: C
|
|
) -> LoggingMutableCollection<LoggingMutableCollection<C>> {
|
|
return LoggingMutableCollection(LoggingMutableCollection(c))
|
|
}
|
|
public static var subscriptIndexSet = TypeIndexed(0)
|
|
public static var subscriptRangeSet = TypeIndexed(0)
|
|
public static var _withUnsafeMutableBufferPointerIfSupported = TypeIndexed(0)
|
|
public static var _withUnsafeMutableBufferPointerIfSupportedNonNilReturns =
|
|
TypeIndexed(0)
|
|
}
|
|
|
|
% for Kind in ['ForwardIndex', 'BidirectionalIndex', 'RandomAccessIndex']:
|
|
public struct Logging${Kind}<
|
|
Base: ${Kind}Type
|
|
> : ${Kind}Type, LoggingType {
|
|
|
|
public typealias Log = ${Kind}Log
|
|
public typealias Distance = Base.Distance
|
|
|
|
public var base: Base
|
|
|
|
public init(_ base: Base) {
|
|
self.base = base
|
|
}
|
|
|
|
public func successor() -> Logging${Kind} {
|
|
Log.successor[selfType] += 1
|
|
return Logging${Kind}(base.successor())
|
|
}
|
|
|
|
% if Kind == 'BidirectionalIndex' or Kind == 'RandomAccessIndex':
|
|
public func predecessor() -> Logging${Kind}<Base> {
|
|
Log.predecessor[selfType] += 1
|
|
return Logging${Kind}(base.predecessor())
|
|
}
|
|
% end
|
|
|
|
public func distanceTo(end: Logging${Kind}<Base>) -> Base.Distance {
|
|
Log.distanceTo[selfType] += 1
|
|
return base.distanceTo(end.base)
|
|
}
|
|
|
|
public func advancedBy(n: Base.Distance) -> Logging${Kind}<Base> {
|
|
Log.advancedBy[selfType] += 1
|
|
return Logging${Kind}(base.advancedBy(n))
|
|
}
|
|
|
|
public func advancedBy(n: Base.Distance, limit: Logging${Kind}<Base>)
|
|
-> Logging${Kind} {
|
|
Log.advancedByWithLimit[selfType] += 1
|
|
return Logging${Kind}(base.advancedBy(n, limit: limit.base))
|
|
}
|
|
}
|
|
|
|
public func ==<Base>(lhs: Logging${Kind}<Base>, rhs: Logging${Kind}<Base>)
|
|
-> Bool {
|
|
return lhs.base == rhs.base
|
|
}
|
|
% end
|
|
|
|
% for Kind in 'Sequence', 'Collection', 'MutableCollection':
|
|
public struct Logging${Kind}<Base: ${Kind}Type> : ${Kind}Type, LoggingType {
|
|
|
|
public typealias Log = ${Kind}Log
|
|
|
|
public init(_ base: Base) {
|
|
self.base = base
|
|
}
|
|
|
|
% if Kind == 'Collection' or Kind == 'MutableCollection':
|
|
public var startIndex: Base.Index {
|
|
Log.startIndex[selfType] += 1
|
|
return base.startIndex
|
|
}
|
|
|
|
public var endIndex: Base.Index {
|
|
Log.endIndex[selfType] += 1
|
|
return base.endIndex
|
|
}
|
|
|
|
public subscript(position: Base.Index) -> Base.Generator.Element {
|
|
get {
|
|
Log.subscriptIndex[selfType] += 1
|
|
return base[position]
|
|
}
|
|
% if Kind == 'MutableCollection':
|
|
set {
|
|
Log.subscriptIndexSet[selfType] += 1
|
|
base[position] = newValue
|
|
}
|
|
% end
|
|
}
|
|
|
|
public subscript(bounds: Range<Base.Index>) -> Base.SubSequence {
|
|
get {
|
|
Log.subscriptRange[selfType] += 1
|
|
return base[bounds]
|
|
}
|
|
% if Kind == 'MutableCollection':
|
|
set {
|
|
Log.subscriptRangeSet[selfType] += 1
|
|
base[bounds] = newValue
|
|
}
|
|
% end
|
|
}
|
|
|
|
public var isEmpty: Bool {
|
|
Log.isEmpty[selfType] += 1
|
|
return base.isEmpty
|
|
}
|
|
|
|
public var count: Base.Index.Distance {
|
|
Log.count[selfType] += 1
|
|
return base.count
|
|
}
|
|
|
|
public func _customIndexOfEquatableElement(
|
|
element: Base.Generator.Element
|
|
) -> Base.Index?? {
|
|
Log._customIndexOfEquatableElement[selfType] += 1
|
|
return base._customIndexOfEquatableElement(element)
|
|
}
|
|
|
|
public var first: Base.Generator.Element? {
|
|
Log.first[selfType] += 1
|
|
return base.first
|
|
}
|
|
% end
|
|
|
|
% if Kind == 'MutableCollection':
|
|
public mutating func _withUnsafeMutableBufferPointerIfSupported<R>(
|
|
@noescape body: (UnsafeMutablePointer<Generator.Element>, Int) throws -> R
|
|
) rethrows -> R? {
|
|
Log._withUnsafeMutableBufferPointerIfSupported[selfType] += 1
|
|
let result = try base._withUnsafeMutableBufferPointerIfSupported(body)
|
|
if result != nil {
|
|
Log._withUnsafeMutableBufferPointerIfSupportedNonNilReturns[selfType] += 1
|
|
}
|
|
return result
|
|
}
|
|
% end
|
|
|
|
public func generate() -> LoggingGenerator<Base.Generator> {
|
|
Log.generate[selfType] += 1
|
|
return LoggingGenerator(base.generate())
|
|
}
|
|
|
|
public func underestimateCount() -> Int {
|
|
Log.underestimateCount[selfType] += 1
|
|
return base.underestimateCount()
|
|
}
|
|
|
|
public func forEach(
|
|
@noescape body: (Base.Generator.Element) throws -> Void
|
|
) rethrows {
|
|
Log.forEach[selfType] += 1
|
|
try base.forEach(body)
|
|
}
|
|
|
|
@warn_unused_result
|
|
public func map<T>(
|
|
@noescape transform: (Base.Generator.Element) throws -> T
|
|
) rethrows -> [T] {
|
|
Log.map[selfType] += 1
|
|
return try base.map(transform)
|
|
}
|
|
|
|
@warn_unused_result
|
|
public func filter(
|
|
@noescape includeElement: (Base.Generator.Element) throws -> Bool
|
|
) rethrows -> [Base.Generator.Element] {
|
|
Log.filter[selfType] += 1
|
|
return try base.filter(includeElement)
|
|
}
|
|
|
|
public func dropFirst(n: Int) -> Base.SubSequence {
|
|
Log.dropFirst[selfType] += 1
|
|
return base.dropFirst(n)
|
|
}
|
|
|
|
public func dropLast(n: Int) -> Base.SubSequence {
|
|
Log.dropLast[selfType] += 1
|
|
return base.dropLast(n)
|
|
}
|
|
|
|
public func prefix(maxLength: Int) -> Base.SubSequence {
|
|
Log.prefix[selfType] += 1
|
|
return base.prefix(maxLength)
|
|
}
|
|
|
|
public func suffix(maxLength: Int) -> Base.SubSequence {
|
|
Log.suffix[selfType] += 1
|
|
return base.suffix(maxLength)
|
|
}
|
|
|
|
public func split(
|
|
maxSplit: Int = Int.max,
|
|
allowEmptySlices: Bool = false,
|
|
@noescape isSeparator: (Base.Generator.Element) throws -> Bool
|
|
) rethrows -> [Base.SubSequence] {
|
|
Log.split[selfType] += 1
|
|
return try base.split(maxSplit, allowEmptySlices: allowEmptySlices,
|
|
isSeparator: isSeparator)
|
|
}
|
|
|
|
% if Kind == 'Collection' or Kind == 'MutableCollection':
|
|
|
|
public func prefixUpTo(end: Index) -> Base.SubSequence {
|
|
Log.prefixUpTo[selfType] += 1
|
|
return base.prefixUpTo(end)
|
|
}
|
|
|
|
public func suffixFrom(start: Index) -> Base.SubSequence {
|
|
Log.suffixFrom[selfType] += 1
|
|
return base.suffixFrom(start)
|
|
}
|
|
|
|
public func prefixThrough(position: Index) -> Base.SubSequence {
|
|
Log.prefixThrough[selfType] += 1
|
|
return base.prefixThrough(position)
|
|
}
|
|
|
|
% end
|
|
|
|
public func _customContainsEquatableElement(
|
|
element: Base.Generator.Element
|
|
) -> Bool? {
|
|
Log._customContainsEquatableElement[selfType] += 1
|
|
return base._customContainsEquatableElement(element)
|
|
}
|
|
|
|
/// If `self` is multi-pass (i.e., a `CollectionType`), invoke
|
|
/// `preprocess` on `self` and return its result. Otherwise, return
|
|
/// `nil`.
|
|
public func _preprocessingPass<R>(
|
|
@noescape preprocess: () -> R
|
|
) -> R? {
|
|
Log._preprocessingPass[selfType] += 1
|
|
return base._preprocessingPass { preprocess() }
|
|
}
|
|
|
|
/// Create a native array buffer containing the elements of `self`,
|
|
/// in the same order.
|
|
public func _copyToNativeArrayBuffer()
|
|
-> _ContiguousArrayBuffer<Base.Generator.Element> {
|
|
Log._copyToNativeArrayBuffer[selfType] += 1
|
|
return base._copyToNativeArrayBuffer()
|
|
}
|
|
|
|
/// Copy a Sequence into an array.
|
|
public func _initializeTo(ptr: UnsafeMutablePointer<Base.Generator.Element>)
|
|
-> UnsafeMutablePointer<Base.Generator.Element> {
|
|
Log._initializeTo[selfType] += 1
|
|
return base._initializeTo(ptr)
|
|
}
|
|
|
|
public var base: Base
|
|
}
|
|
% end
|
|
|
|
public func expectCustomizable<
|
|
T : WrapperType where
|
|
T : LoggingType,
|
|
T.Base : WrapperType, T.Base : LoggingType,
|
|
T.Log == T.Base.Log
|
|
>(_: T, _ counters: TypeIndexed<Int>,
|
|
//===--- TRACE boilerplate ----------------------------------------------===//
|
|
@autoclosure _ message: () -> String = "",
|
|
showFrame: Bool = true,
|
|
stackTrace: SourceLocStack = SourceLocStack(),
|
|
file: String = #file, line: UInt = #line
|
|
) {
|
|
let newTrace = stackTrace.pushIf(showFrame, file: file, line: line)
|
|
expectNotEqual(0, counters[T.self], message(), stackTrace: newTrace)
|
|
expectEqual(
|
|
counters[T.self], counters[T.Base.self], message(), stackTrace: newTrace)
|
|
}
|
|
|
|
public func expectNotCustomizable<
|
|
T : WrapperType where
|
|
T : LoggingType,
|
|
T.Base : WrapperType, T.Base : LoggingType,
|
|
T.Log == T.Base.Log
|
|
>(_: T, _ counters: TypeIndexed<Int>,
|
|
//===--- TRACE boilerplate ----------------------------------------------===//
|
|
@autoclosure _ message: () -> String = "",
|
|
showFrame: Bool = true,
|
|
stackTrace: SourceLocStack = SourceLocStack(),
|
|
file: String = #file, line: UInt = #line
|
|
) {
|
|
let newTrace = stackTrace.pushIf(showFrame, file: file, line: line)
|
|
expectNotEqual(0, counters[T.self], message(), stackTrace: newTrace)
|
|
expectEqual(0, counters[T.Base.self], message(), stackTrace: newTrace)
|
|
}
|