@@ -69,4 +69,140 @@ final class InterfaceTypeTests: XCTestCase {
6969 XCTAssertEqual ( symbol. api. name, " A " )
7070 }
7171 }
72+
73+ func testFunctionsInPublicExtension( ) throws {
74+ let source = #"""
75+ public extension Int {
76+ func a() {}
77+ public func b() {}
78+ internal func c() {}
79+ fileprivate func d() {}
80+ private func e() {}
81+ }
82+ """#
83+
84+ let url = try temporaryFile ( contents: source)
85+ let sourceFile = try SourceFile ( file: url, relativeTo: url. deletingLastPathComponent ( ) )
86+ let module = Module ( name: " Module " , sourceFiles: [ sourceFile] )
87+
88+ XCTAssertEqual ( sourceFile. symbols. count, 5 )
89+ XCTAssertTrue ( sourceFile. symbols [ 0 ] . isPublic, " Function `a()` should BE marked as public - its visibility is specified by extension " )
90+ XCTAssertTrue ( sourceFile. symbols [ 1 ] . isPublic, " Function `b()` should BE marked as public - its visibility is public " )
91+ XCTAssertFalse ( sourceFile. symbols [ 2 ] . isPublic, " Function `c()` should NOT be marked as public - its visibility is internal " )
92+ XCTAssertFalse ( sourceFile. symbols [ 3 ] . isPublic, " Function `d()` should NOT be marked as public - its visibility is fileprivate " )
93+ XCTAssertFalse ( sourceFile. symbols [ 4 ] . isPublic, " Function `e()` should NOT be marked as public - its visibility is private " )
94+
95+ XCTAssertEqual ( module. interface. symbols. count, 2 )
96+ XCTAssertEqual ( module. interface. symbols [ 0 ] . name, " a() " , " Function `a()` should be in documented interface " )
97+ XCTAssertEqual ( module. interface. symbols [ 1 ] . name, " b() " , " Function `b()` should be in documented interface " )
98+ }
99+
100+ func testComputedPropertiesInPublicExtension( ) throws {
101+ let source = #"""
102+ public extension Int {
103+ var a: Int { 1 }
104+ public var b: Int { 1 }
105+ internal var c: Int { 1 }
106+ fileprivate var d: Int { 1 }
107+ private var e: Int { 1 }
108+ }
109+ """#
110+
111+ let url = try temporaryFile ( contents: source)
112+ let sourceFile = try SourceFile ( file: url, relativeTo: url. deletingLastPathComponent ( ) )
113+ let module = Module ( name: " Module " , sourceFiles: [ sourceFile] )
114+
115+ XCTAssertEqual ( sourceFile. symbols. count, 5 )
116+ XCTAssertTrue ( sourceFile. symbols [ 0 ] . isPublic, " Property `a` should BE marked as public - its visibility is specified by extension " )
117+ XCTAssertTrue ( sourceFile. symbols [ 1 ] . isPublic, " Property `b` should BE marked as public - its visibility is public " )
118+ XCTAssertFalse ( sourceFile. symbols [ 2 ] . isPublic, " Property `c` should NOT be marked as public - its visibility is internal " )
119+ XCTAssertFalse ( sourceFile. symbols [ 3 ] . isPublic, " Property `d` should NOT be marked as public - its visibility is fileprivate " )
120+ XCTAssertFalse ( sourceFile. symbols [ 4 ] . isPublic, " Property `e` should NOT be marked as public - its visibility is private " )
121+
122+ XCTAssertEqual ( module. interface. symbols. count, 2 )
123+ XCTAssertEqual ( module. interface. symbols [ 0 ] . name, " a " , " Property `a` should be in documented interface " )
124+ XCTAssertEqual ( module. interface. symbols [ 1 ] . name, " b " , " Property `b` should be in documented interface " )
125+ }
126+
127+ func testComputedPropertiesWithMultipleAccessModifiersInPublicExtension( ) throws {
128+ let source = #"""
129+ public extension Int {
130+ internal(set) var a: Int {
131+ get { 1 }
132+ set {}
133+ }
134+ private(set) var b: Int {
135+ get { 1 }
136+ set {}
137+ }
138+ public internal(set) var c: Int {
139+ get { 1 }
140+ set {}
141+ }
142+ public fileprivate(set) var d: Int {
143+ get { 1 }
144+ set {}
145+ }
146+ public private(set) var e: Int {
147+ get { 1 }
148+ set {}
149+ }
150+ }
151+ """#
152+
153+ let url = try temporaryFile ( contents: source)
154+ let sourceFile = try SourceFile ( file: url, relativeTo: url. deletingLastPathComponent ( ) )
155+ let module = Module ( name: " Module " , sourceFiles: [ sourceFile] )
156+
157+ XCTAssertEqual ( sourceFile. symbols. count, 5 )
158+ XCTAssertTrue ( sourceFile. symbols [ 0 ] . isPublic, " Property `a` should be marked as public - the visibility of its getter is public " )
159+ XCTAssertTrue ( sourceFile. symbols [ 1 ] . isPublic, " Property `b` should be marked as public - the visibility of its getter is public " )
160+ XCTAssertTrue ( sourceFile. symbols [ 2 ] . isPublic, " Property `c` should be marked as public - the visibility of its getter is public " )
161+ XCTAssertTrue ( sourceFile. symbols [ 3 ] . isPublic, " Property `d` should be marked as public - the visibility of its getter is public " )
162+ XCTAssertTrue ( sourceFile. symbols [ 4 ] . isPublic, " Property `e` should be marked as public - the visibility of its getter is public " )
163+
164+ XCTAssertEqual ( module. interface. symbols. count, 5 )
165+ XCTAssertEqual ( module. interface. symbols [ 0 ] . name, " a " , " Property `a` should be in documented interface " )
166+ XCTAssertEqual ( module. interface. symbols [ 1 ] . name, " b " , " Property `b` should be in documented interface " )
167+ XCTAssertEqual ( module. interface. symbols [ 2 ] . name, " c " , " Property `c` should be in documented interface " )
168+ XCTAssertEqual ( module. interface. symbols [ 3 ] . name, " d " , " Property `d` should be in documented interface " )
169+ XCTAssertEqual ( module. interface. symbols [ 4 ] . name, " e " , " Property `e` should be in documented interface " )
170+ }
171+
172+ func testNestedPropertiesInPublicExtension( ) throws {
173+ let source = #"""
174+ public class RootController {}
175+
176+ public extension RootController {
177+ class ControllerExtension {
178+ public var public_properties: ExtendedProperties = ExtendedProperties()
179+ internal var internal_properties: InternalProperties = InternalProperties()
180+ }
181+ }
182+
183+ public extension RootController.ControllerExtension {
184+ struct ExtendedProperties {
185+ public var public_prop: Int = 1
186+ }
187+ }
188+
189+ internal extension RootController.ControllerExtension {
190+ struct InternalProperties {
191+ internal var internal_prop: String = "FOO"
192+ }
193+ }
194+ """#
195+
196+
197+ let url = try temporaryFile ( contents: source)
198+ let sourceFile = try SourceFile ( file: url, relativeTo: url. deletingLastPathComponent ( ) )
199+ let module = Module ( name: " Module " , sourceFiles: [ sourceFile] )
200+
201+ XCTAssertEqual ( module. interface. symbols. count, 5 )
202+ XCTAssertEqual ( module. interface. symbols [ 0 ] . name, " RootController " )
203+ XCTAssertEqual ( module. interface. symbols [ 1 ] . name, " ControllerExtension " )
204+ XCTAssertEqual ( module. interface. symbols [ 2 ] . name, " public_properties " )
205+ XCTAssertEqual ( module. interface. symbols [ 3 ] . name, " ExtendedProperties " )
206+ XCTAssertEqual ( module. interface. symbols [ 4 ] . name, " public_prop " )
207+ }
72208}
0 commit comments