@@ -1043,6 +1043,178 @@ class BlockDirectiveArgumentParserTests: XCTestCase {
1043
1043
"""
1044
1044
XCTAssertEqual ( expected, documentation. debugDescription ( ) )
1045
1045
}
1046
+
1047
+ func testParsingDirectiveArgumentsWithWhitespaceBeforeDirective( ) throws {
1048
+ struct ExpectedArgumentInfo {
1049
+ var line : Int
1050
+ let name : String
1051
+ var nameRange : Range < Int >
1052
+ let value : String
1053
+ var valueRange : Range < Int >
1054
+ }
1055
+
1056
+ func assertDirectiveArguments(
1057
+ _ expectedArguments: ExpectedArgumentInfo ... ,
1058
+ parsing content: String ,
1059
+ file: StaticString = #file,
1060
+ line: UInt = #line
1061
+ ) throws {
1062
+ func substring( with range: SourceRange ) -> String {
1063
+ let line = content. split ( omittingEmptySubsequences: false , whereSeparator: \. isNewline) [ range. lowerBound. line - 1 ]
1064
+ let startIndex = line. utf8. index ( line. utf8. startIndex, offsetBy: range. lowerBound. column - 1 )
1065
+ let endIndex = line. utf8. index ( line. utf8. startIndex, offsetBy: range. upperBound. column - 1 )
1066
+ return String ( line [ startIndex ..< endIndex] )
1067
+ }
1068
+
1069
+ let source = URL ( fileURLWithPath: " /test-file-location " )
1070
+ let document = Document ( parsing: content, source: source, options: . parseBlockDirectives)
1071
+ let directive = try XCTUnwrap ( document. children. compactMap ( { $0 as? BlockDirective } ) . first, file: file, line: line)
1072
+ let arguments = directive. argumentText. parseNameValueArguments ( )
1073
+ XCTAssertEqual ( arguments. count, expectedArguments. count, file: file, line: line)
1074
+ for expectedArgument in expectedArguments {
1075
+ let argument = try XCTUnwrap ( arguments [ expectedArgument. name] , file: file, line: line)
1076
+
1077
+ XCTAssertEqual ( expectedArgument. name, argument. name, file: file, line: line)
1078
+ XCTAssertEqual (
1079
+ argument. nameRange,
1080
+ SourceLocation ( line: expectedArgument. line, column: expectedArgument. nameRange. lowerBound, source: source) ..< SourceLocation ( line: expectedArgument. line, column: expectedArgument. nameRange. upperBound, source: source) ,
1081
+ file: file,
1082
+ line: line
1083
+ )
1084
+ XCTAssertEqual ( expectedArgument. name, argument. nameRange. map ( substring ( with: ) ) , file: file, line: line)
1085
+
1086
+ XCTAssertEqual ( expectedArgument. value, argument. value, file: file, line: line)
1087
+ XCTAssertEqual (
1088
+ argument. valueRange,
1089
+ SourceLocation ( line: expectedArgument. line, column: expectedArgument. valueRange. lowerBound, source: source) ..< SourceLocation ( line: expectedArgument. line, column: expectedArgument. valueRange. upperBound, source: source) ,
1090
+ file: file,
1091
+ line: line
1092
+ )
1093
+ XCTAssertEqual ( expectedArgument. value, argument. valueRange. map ( substring ( with: ) ) , file: file, line: line)
1094
+ }
1095
+ }
1096
+
1097
+ // One argument
1098
+
1099
+ try assertDirectiveArguments (
1100
+ ExpectedArgumentInfo ( line: 1 , name: " firstArgument " , nameRange: 16 ..< 29 , value: " firstValue " , valueRange: 31 ..< 41 ) ,
1101
+ parsing: " @DirectiveName(firstArgument: firstValue) "
1102
+ )
1103
+
1104
+ try assertDirectiveArguments (
1105
+ ExpectedArgumentInfo ( line: 2 , name: " firstArgument " , nameRange: 16 ..< 29 , value: " firstValue " , valueRange: 31 ..< 41 ) ,
1106
+ parsing: """
1107
+
1108
+ @DirectiveName(firstArgument: firstValue)
1109
+ """
1110
+ )
1111
+
1112
+ // Argument on single line
1113
+
1114
+ try assertDirectiveArguments (
1115
+ ExpectedArgumentInfo ( line: 1 , name: " firstArgument " , nameRange: 17 ..< 30 , value: " firstValue " , valueRange: 31 ..< 41 ) ,
1116
+ ExpectedArgumentInfo ( line: 1 , name: " secondArgument " , nameRange: 44 ..< 58 , value: " secondValue " , valueRange: 62 ..< 73 ) ,
1117
+ parsing: " @DirectiveName( firstArgument:firstValue , \t secondArgument: \t secondValue) "
1118
+ )
1119
+
1120
+ try assertDirectiveArguments (
1121
+ ExpectedArgumentInfo ( line: 2 , name: " firstArgument " , nameRange: 17 ..< 30 , value: " firstValue " , valueRange: 31 ..< 41 ) ,
1122
+ ExpectedArgumentInfo ( line: 2 , name: " secondArgument " , nameRange: 44 ..< 58 , value: " secondValue " , valueRange: 62 ..< 73 ) ,
1123
+ parsing: """
1124
+
1125
+ @DirectiveName( firstArgument:firstValue , \t secondArgument: \t secondValue)
1126
+ """
1127
+ )
1128
+
1129
+ try assertDirectiveArguments (
1130
+ ExpectedArgumentInfo ( line: 2 , name: " firstArgument " , nameRange: 19 ..< 32 , value: " firstValue " , valueRange: 33 ..< 43 ) ,
1131
+ ExpectedArgumentInfo ( line: 2 , name: " secondArgument " , nameRange: 46 ..< 60 , value: " secondValue " , valueRange: 64 ..< 75 ) ,
1132
+ parsing: """
1133
+
1134
+ @DirectiveName( firstArgument:firstValue , \t secondArgument: \t secondValue)
1135
+ """
1136
+ )
1137
+
1138
+ // Second argument on new line
1139
+
1140
+ try assertDirectiveArguments (
1141
+ ExpectedArgumentInfo ( line: 1 , name: " firstArgument " , nameRange: 17 ..< 30 , value: " firstValue " , valueRange: 31 ..< 41 ) ,
1142
+ ExpectedArgumentInfo ( line: 2 , name: " secondArgument " , nameRange: 16 ..< 30 , value: " secondValue " , valueRange: 34 ..< 45 ) ,
1143
+ parsing: """
1144
+ @DirectiveName( firstArgument:firstValue ,
1145
+ secondArgument: \t secondValue)
1146
+ """
1147
+ )
1148
+
1149
+ try assertDirectiveArguments (
1150
+ ExpectedArgumentInfo ( line: 2 , name: " firstArgument " , nameRange: 17 ..< 30 , value: " firstValue " , valueRange: 31 ..< 41 ) ,
1151
+ ExpectedArgumentInfo ( line: 3 , name: " secondArgument " , nameRange: 16 ..< 30 , value: " secondValue " , valueRange: 34 ..< 45 ) ,
1152
+ parsing: """
1153
+
1154
+ @DirectiveName( firstArgument:firstValue ,
1155
+ secondArgument: \t secondValue)
1156
+ """
1157
+ )
1158
+
1159
+ try assertDirectiveArguments (
1160
+ ExpectedArgumentInfo ( line: 2 , name: " firstArgument " , nameRange: 19 ..< 32 , value: " firstValue " , valueRange: 33 ..< 43 ) ,
1161
+ ExpectedArgumentInfo ( line: 3 , name: " secondArgument " , nameRange: 18 ..< 32 , value: " secondValue " , valueRange: 36 ..< 47 ) ,
1162
+ parsing: """
1163
+
1164
+ @DirectiveName( firstArgument:firstValue ,
1165
+ secondArgument: \t secondValue)
1166
+ """
1167
+ )
1168
+
1169
+ // Arguments on separate lines
1170
+
1171
+ try assertDirectiveArguments (
1172
+ ExpectedArgumentInfo ( line: 2 , name: " firstArgument " , nameRange: 3 ..< 16 , value: " firstValue " , valueRange: 17 ..< 27 ) ,
1173
+ ExpectedArgumentInfo ( line: 3 , name: " secondArgument " , nameRange: 2 ..< 16 , value: " secondValue " , valueRange: 20 ..< 31 ) ,
1174
+ parsing: """
1175
+ @DirectiveName(
1176
+ firstArgument:firstValue ,
1177
+ \t secondArgument: \t secondValue
1178
+ )
1179
+ """
1180
+ )
1181
+
1182
+ try assertDirectiveArguments (
1183
+ ExpectedArgumentInfo ( line: 3 , name: " firstArgument " , nameRange: 3 ..< 16 , value: " firstValue " , valueRange: 17 ..< 27 ) ,
1184
+ ExpectedArgumentInfo ( line: 4 , name: " secondArgument " , nameRange: 2 ..< 16 , value: " secondValue " , valueRange: 20 ..< 31 ) ,
1185
+ parsing: """
1186
+
1187
+ @DirectiveName(
1188
+ firstArgument:firstValue ,
1189
+ \t secondArgument: \t secondValue
1190
+ )
1191
+ """
1192
+ )
1193
+
1194
+ try assertDirectiveArguments (
1195
+ ExpectedArgumentInfo ( line: 3 , name: " firstArgument " , nameRange: 5 ..< 18 , value: " firstValue " , valueRange: 19 ..< 29 ) ,
1196
+ ExpectedArgumentInfo ( line: 4 , name: " secondArgument " , nameRange: 4 ..< 18 , value: " secondValue " , valueRange: 22 ..< 33 ) ,
1197
+ parsing: """
1198
+
1199
+ @DirectiveName(
1200
+ firstArgument:firstValue ,
1201
+ \t secondArgument: \t secondValue
1202
+ )
1203
+ """
1204
+ )
1205
+
1206
+ // Content and directives with emoji
1207
+
1208
+ try assertDirectiveArguments (
1209
+ ExpectedArgumentInfo ( line: 3 , name: " firstArgument " , nameRange: 20 ..< 33 , value: " first💻Value " , valueRange: 35 ..< 49 ) ,
1210
+ ExpectedArgumentInfo ( line: 3 , name: " secondArgument " , nameRange: 51 ..< 65 , value: " secondValue " , valueRange: 67 ..< 78 ) ,
1211
+ parsing: """
1212
+ Paragraph before with emoji: 💻
1213
+
1214
+ @Directive💻Name(firstArgument: first💻Value, secondArgument: secondValue)
1215
+ """
1216
+ )
1217
+ }
1046
1218
1047
1219
// FIXME: swift-testing macro for specifying the relationship between a bug and a test
1048
1220
// Uncomment the following code when we integrate swift-testing
0 commit comments