Skip to content

Commit 58f43da

Browse files
committed
[PlaygroundLogger] Added tests for recursive logging.
Added tests for both the new and legacy entrypoints to ensure that recursive logging does not occur. In both cases, a struct whose implementation of `CustomStringConvertible` logs `self` is logged. Without the changes in the previous commit, this causes infinite recursion. With those changes, these tests pass as expected. This is for <rdar://problem/41460357> / SR-8349.
1 parent c8af268 commit 58f43da

File tree

4 files changed

+132
-1
lines changed

4 files changed

+132
-1
lines changed

PlaygroundLogger/PlaygroundLogger.xcodeproj/project.pbxproj

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@
8282
5E5D77842040F5E900EBC3A9 /* LoggingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E5D77832040F5E900EBC3A9 /* LoggingError.swift */; };
8383
5E5F600B20409D4E007EF0A8 /* LogPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E5F600A20409D4E007EF0A8 /* LogPolicy.swift */; };
8484
5E5FE50B202D13C800E28C3C /* PGLConcurrentMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E5FE50A202D13C800E28C3C /* PGLConcurrentMap.swift */; };
85+
5EB651C0213A01D0001CC984 /* LegacyEntrypointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EB651BF213A01D0001CC984 /* LegacyEntrypointTests.swift */; };
86+
5EB651C1213A01D0001CC984 /* LegacyEntrypointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EB651BF213A01D0001CC984 /* LegacyEntrypointTests.swift */; };
87+
5EB651C2213A01D0001CC984 /* LegacyEntrypointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EB651BF213A01D0001CC984 /* LegacyEntrypointTests.swift */; };
88+
5EB651C4213A081A001CC984 /* LoggerEntrypointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EB651C3213A081A001CC984 /* LoggerEntrypointTests.swift */; };
89+
5EB651C5213A081A001CC984 /* LoggerEntrypointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EB651C3213A081A001CC984 /* LoggerEntrypointTests.swift */; };
90+
5EB651C6213A081A001CC984 /* LoggerEntrypointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EB651C3213A081A001CC984 /* LoggerEntrypointTests.swift */; };
8591
5ECE8F911FFCD2A70034D9BC /* LegacyPlaygroundLoggerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ECE8F901FFCD2A70034D9BC /* LegacyPlaygroundLoggerTests.swift */; };
8692
5EE3867420352F3200D625F0 /* CGFloat+CustomOpaqueLoggable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EE3867320352F3200D625F0 /* CGFloat+CustomOpaqueLoggable.swift */; };
8793
5EF581532041387C00AC14FE /* CustomPlaygroundDisplayConvertibleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EF581512041384700AC14FE /* CustomPlaygroundDisplayConvertibleTests.swift */; };
@@ -262,6 +268,8 @@
262268
5E5D77832040F5E900EBC3A9 /* LoggingError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggingError.swift; sourceTree = "<group>"; };
263269
5E5F600A20409D4E007EF0A8 /* LogPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogPolicy.swift; sourceTree = "<group>"; };
264270
5E5FE50A202D13C800E28C3C /* PGLConcurrentMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PGLConcurrentMap.swift; sourceTree = "<group>"; };
271+
5EB651BF213A01D0001CC984 /* LegacyEntrypointTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyEntrypointTests.swift; sourceTree = "<group>"; };
272+
5EB651C3213A081A001CC984 /* LoggerEntrypointTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggerEntrypointTests.swift; sourceTree = "<group>"; };
265273
5ECE8F901FFCD2A70034D9BC /* LegacyPlaygroundLoggerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyPlaygroundLoggerTests.swift; sourceTree = "<group>"; };
266274
5EE3867320352F3200D625F0 /* CGFloat+CustomOpaqueLoggable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGFloat+CustomOpaqueLoggable.swift"; sourceTree = "<group>"; };
267275
5EF581512041384700AC14FE /* CustomPlaygroundDisplayConvertibleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomPlaygroundDisplayConvertibleTests.swift; sourceTree = "<group>"; };
@@ -405,6 +413,8 @@
405413
5EF581512041384700AC14FE /* CustomPlaygroundDisplayConvertibleTests.swift */,
406414
5E48E0A92042925B00C7712D /* LogEntryTests.swift */,
407415
5E5D777F2040BD7D00EBC3A9 /* LogPolicyTests.swift */,
416+
5EB651C3213A081A001CC984 /* LoggerEntrypointTests.swift */,
417+
5EB651BF213A01D0001CC984 /* LegacyEntrypointTests.swift */,
408418
5ECE8F901FFCD2A70034D9BC /* LegacyPlaygroundLoggerTests.swift */,
409419
);
410420
path = PlaygroundLoggerTests;
@@ -980,6 +990,8 @@
980990
isa = PBXSourcesBuildPhase;
981991
buildActionMask = 2147483647;
982992
files = (
993+
5EB651C0213A01D0001CC984 /* LegacyEntrypointTests.swift in Sources */,
994+
5EB651C4213A081A001CC984 /* LoggerEntrypointTests.swift in Sources */,
983995
5E5D77802040BD7D00EBC3A9 /* LogPolicyTests.swift in Sources */,
984996
5E48E0AA2042925B00C7712D /* LogEntryTests.swift in Sources */,
985997
5EF581532041387C00AC14FE /* CustomPlaygroundDisplayConvertibleTests.swift in Sources */,
@@ -991,6 +1003,8 @@
9911003
isa = PBXSourcesBuildPhase;
9921004
buildActionMask = 2147483647;
9931005
files = (
1006+
5EB651C1213A01D0001CC984 /* LegacyEntrypointTests.swift in Sources */,
1007+
5EB651C5213A081A001CC984 /* LoggerEntrypointTests.swift in Sources */,
9941008
5E5D77812040BD7D00EBC3A9 /* LogPolicyTests.swift in Sources */,
9951009
5E48E0AB2042925B00C7712D /* LogEntryTests.swift in Sources */,
9961010
5EF581542041387C00AC14FE /* CustomPlaygroundDisplayConvertibleTests.swift in Sources */,
@@ -1020,6 +1034,8 @@
10201034
isa = PBXSourcesBuildPhase;
10211035
buildActionMask = 2147483647;
10221036
files = (
1037+
5EB651C2213A01D0001CC984 /* LegacyEntrypointTests.swift in Sources */,
1038+
5EB651C6213A081A001CC984 /* LoggerEntrypointTests.swift in Sources */,
10231039
5E5D77822040BD7D00EBC3A9 /* LogPolicyTests.swift in Sources */,
10241040
5E48E0AC2042925B00C7712D /* LogEntryTests.swift in Sources */,
10251041
5EF581552041387C00AC14FE /* CustomPlaygroundDisplayConvertibleTests.swift in Sources */,

PlaygroundLogger/PlaygroundLogger/SendData.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
import Foundation
1414

15-
fileprivate func unsetSendData(_: NSData) {
15+
internal /*testable*/ func unsetSendData(_: NSData) {
1616
fatalError("PlaygroundLogger not initialized")
1717
}
1818

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===--- LegacyEntrypointTests.swift --------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import XCTest
14+
@testable import PlaygroundLogger
15+
16+
class LegacyEntrypointTests: XCTestCase {
17+
func testRecursiveLogging() {
18+
// Create a struct which, as a side effect of being logged, tries to log itself.
19+
// This is representative of a playground where `self` is logged in places like a CustomStringConvertible conformance.
20+
struct Struct: CustomStringConvertible {
21+
let x: Int
22+
let y: Int
23+
24+
var description: String {
25+
// This direct call to the logger mirrors what would happen if this property were instrumented by the playground logger and there were a bare reference to `self`.
26+
let logData = legacyLog(instance: self, name: "self", id: 0, startLine: 1, endLine: 1, startColumn: 1, endColumn: 1)
27+
28+
// Since `description` is only ever called by logging, we can assert that we have nil.
29+
// If we called `description` by other means we'd need to vary this assertion to match.
30+
XCTAssertNil(logData)
31+
32+
return "(\(x), \(y))"
33+
}
34+
}
35+
36+
let subject = Struct(x: 0, y: 0)
37+
38+
// Log an instance of `Struct`. This should succeed (i.e. return data).
39+
let logData = legacyLog(instance: subject, name: "subject", id: 0, startLine: 1, endLine: 1, startColumn: 1, endColumn: 1)
40+
41+
XCTAssertNotNil(logData)
42+
}
43+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//===--- LoggerEntrypointTests.swift --------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import XCTest
14+
@testable import PlaygroundLogger
15+
16+
fileprivate var numberOfDataSent: Int = 0
17+
18+
fileprivate func countData(_: NSData) -> Void {
19+
numberOfDataSent += 1
20+
}
21+
22+
class LoggerEntrypointTests: XCTestCase {
23+
override class func setUp() {
24+
super.setUp()
25+
26+
// Tell PlaygroundLogger to use our function for counting data.
27+
PlaygroundLogger.sendData = countData
28+
}
29+
30+
override class func tearDown() {
31+
super.tearDown()
32+
33+
// Reset PlaygroundLogger.
34+
PlaygroundLogger.sendData = unsetSendData
35+
}
36+
37+
override func setUp() {
38+
// Reset the data counter.
39+
numberOfDataSent = 0
40+
41+
super.setUp()
42+
}
43+
44+
func testRecursiveLogging() {
45+
// Create a struct which, as a side effect of being logged, tries to log itself.
46+
// This is representative of a playground where `self` is logged in places like a CustomStringConvertible conformance.
47+
struct Struct: CustomStringConvertible {
48+
let x: Int
49+
let y: Int
50+
51+
var description: String {
52+
// Capture the previous number of data sent so we can check against it later.
53+
let previousNumberOfDataSent = numberOfDataSent
54+
55+
// This direct call to the logger mirrors what would happen if this property were instrumented by the playground logger and there were a bare reference to `self`.
56+
PlaygroundLogger.logResult(self, named: "self", withIdentifier: 0, startLine: 1, endLine: 1, startColumn: 1, endColumn: 1)
57+
58+
// Since `description` is only ever called by logging, we can assert that no additional data was sent.
59+
// If we called `description` by other means we'd need to vary this assertion to match.
60+
XCTAssertEqual(previousNumberOfDataSent, numberOfDataSent, "We don't expect any more data to be sent by that previous log line!")
61+
62+
return "(\(x), \(y))"
63+
}
64+
}
65+
66+
let subject = Struct(x: 0, y: 0)
67+
68+
PlaygroundLogger.logResult(subject, named: "subject", withIdentifier: 0, startLine: 1, endLine: 1, startColumn: 1, endColumn: 1)
69+
70+
XCTAssertEqual(numberOfDataSent, 1, "We expect only one data to be sent over the course of this test")
71+
}
72+
}

0 commit comments

Comments
 (0)