File tree Expand file tree Collapse file tree 8 files changed +77
-0
lines changed
Tests/SwiftFormatTests/Rules Expand file tree Collapse file tree 8 files changed +77
-0
lines changed Original file line number Diff line number Diff line change @@ -189,6 +189,7 @@ Force-unwraps are strongly discouraged and must be documented.
189
189
190
190
This rule does not apply to test code, defined as code which:
191
191
* Contains the line ` import XCTest `
192
+ * The function is marked with ` @Test ` attribute
192
193
193
194
Lint: If a force unwrap is used, a lint warning is raised.
194
195
@@ -200,6 +201,7 @@ Force-try (`try!`) is forbidden.
200
201
201
202
This rule does not apply to test code, defined as code which:
202
203
* Contains the line ` import XCTest `
204
+ * The function is marked with ` @Test ` attribute
203
205
204
206
Lint: Using ` try! ` results in a lint error.
205
207
@@ -215,6 +217,7 @@ Certain properties (e.g. `@IBOutlet`) tied to the UI lifecycle are ignored.
215
217
216
218
This rule does not apply to test code, defined as code which:
217
219
* Contains the line ` import XCTest `
220
+ * The function is marked with ` @Test ` attribute
218
221
219
222
TODO: Create exceptions for other UI elements (ex: viewDidLoad)
220
223
Original file line number Diff line number Diff line change @@ -149,6 +149,21 @@ extension SyntaxProtocol {
149
149
}
150
150
return leadingTrivia. hasAnyComments
151
151
}
152
+
153
+ /// Indicates whether the node has any function ancestor marked with `@Test` attribute.
154
+ var hasTestAncestor : Bool {
155
+ var parent = self . parent
156
+ while let existingParent = parent {
157
+ if let functionDecl = existingParent. as ( FunctionDeclSyntax . self) ,
158
+ functionDecl. attributes. contains ( where: {
159
+ $0. as ( AttributeSyntax . self) ? . attributeName. as ( IdentifierTypeSyntax . self) ? . name. text == " Test "
160
+ } ) {
161
+ return true
162
+ }
163
+ parent = existingParent. parent
164
+ }
165
+ return false
166
+ }
152
167
}
153
168
154
169
extension SyntaxCollection {
Original file line number Diff line number Diff line change @@ -34,6 +34,8 @@ public final class NeverForceUnwrap: SyntaxLintRule {
34
34
35
35
public override func visit( _ node: ForceUnwrapExprSyntax ) -> SyntaxVisitorContinueKind {
36
36
guard context. importsXCTest == . doesNotImportXCTest else { return . skipChildren }
37
+ // Allow force unwrapping if it is in a function marked with @Test attribute.
38
+ if node. hasTestAncestor { return . skipChildren }
37
39
diagnose ( . doNotForceUnwrap( name: node. expression. trimmedDescription) , on: node)
38
40
return . skipChildren
39
41
}
@@ -44,6 +46,8 @@ public final class NeverForceUnwrap: SyntaxLintRule {
44
46
guard context. importsXCTest == . doesNotImportXCTest else { return . skipChildren }
45
47
guard let questionOrExclamation = node. questionOrExclamationMark else { return . skipChildren }
46
48
guard questionOrExclamation. tokenKind == . exclamationMark else { return . skipChildren }
49
+ // Allow force cast if it is in a function marked with @Test attribute.
50
+ if node. hasTestAncestor { return . skipChildren }
47
51
diagnose ( . doNotForceCast( name: node. type. trimmedDescription) , on: node)
48
52
return . skipChildren
49
53
}
Original file line number Diff line number Diff line change @@ -36,6 +36,8 @@ public final class NeverUseForceTry: SyntaxLintRule {
36
36
public override func visit( _ node: TryExprSyntax ) -> SyntaxVisitorContinueKind {
37
37
guard context. importsXCTest == . doesNotImportXCTest else { return . skipChildren }
38
38
guard let mark = node. questionOrExclamationMark else { return . visitChildren }
39
+ // Allow force try if it is in a function marked with @Test attribute.
40
+ if node. hasTestAncestor { return . skipChildren }
39
41
if mark. tokenKind == . exclamationMark {
40
42
diagnose ( . doNotForceTry, on: node. tryKeyword)
41
43
}
Original file line number Diff line number Diff line change @@ -39,6 +39,8 @@ public final class NeverUseImplicitlyUnwrappedOptionals: SyntaxLintRule {
39
39
40
40
public override func visit( _ node: VariableDeclSyntax ) -> SyntaxVisitorContinueKind {
41
41
guard context. importsXCTest == . doesNotImportXCTest else { return . skipChildren }
42
+ // Allow implicitly unwrapping if it is in a function marked with @Test attribute.
43
+ if node. hasTestAncestor { return . skipChildren }
42
44
// Ignores IBOutlet variables
43
45
for attribute in node. attributes {
44
46
if ( attribute. as ( AttributeSyntax . self) ) ? . attributeName. as ( IdentifierTypeSyntax . self) ? . name. text == " IBOutlet " {
Original file line number Diff line number Diff line change @@ -40,4 +40,23 @@ final class NeverForceUnwrapTests: LintOrFormatRuleTestCase {
40
40
findings: [ ]
41
41
)
42
42
}
43
+
44
+ func testIgnoreTestAttributeFunction( ) {
45
+ assertLint (
46
+ NeverForceUnwrap . self,
47
+ """
48
+ @Test
49
+ func testSomeFunc() {
50
+ var b = a as! Int
51
+ }
52
+ @Test
53
+ func testAnotherFunc() {
54
+ func nestedFunc() {
55
+ let c = someValue()!
56
+ }
57
+ }
58
+ """ ,
59
+ findings: [ ]
60
+ )
61
+ }
43
62
}
Original file line number Diff line number Diff line change @@ -38,4 +38,20 @@ final class NeverUseForceTryTests: LintOrFormatRuleTestCase {
38
38
findings: [ ]
39
39
)
40
40
}
41
+
42
+ func testAllowForceTryInTestAttributeFunction( ) {
43
+ assertLint (
44
+ NeverUseForceTry . self,
45
+ """
46
+ @Test
47
+ func testSomeFunc() {
48
+ let document = try! Document(path: " important.data " )
49
+ func nestedFunc() {
50
+ let x = try! someThrowingFunction()
51
+ }
52
+ }
53
+ """ ,
54
+ findings: [ ]
55
+ )
56
+ }
41
57
}
Original file line number Diff line number Diff line change @@ -35,4 +35,20 @@ final class NeverUseImplicitlyUnwrappedOptionalsTests: LintOrFormatRuleTestCase
35
35
findings: [ ]
36
36
)
37
37
}
38
+
39
+ func testIgnoreTestAttrinuteFunction( ) {
40
+ assertLint (
41
+ NeverUseImplicitlyUnwrappedOptionals . self,
42
+ """
43
+ @Test
44
+ func testSomeFunc() {
45
+ var s: String!
46
+ func nestedFunc() {
47
+ var f: Foo!
48
+ }
49
+ }
50
+ """ ,
51
+ findings: [ ]
52
+ )
53
+ }
38
54
}
You can’t perform that action at this time.
0 commit comments