Skip to content

Commit 753e7c5

Browse files
committed
Update the testFilters to contain all the logic for processing test filters regardless of type, regex or tag
1 parent acead4a commit 753e7c5

1 file changed

Lines changed: 40 additions & 35 deletions

File tree

Sources/Testing/ABI/EntryPoints/EntryPoint.swift

Lines changed: 40 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -624,48 +624,53 @@ public func configurationForEntryPoint(from args: __CommandLineArguments_v0) thr
624624

625625
// Filtering
626626
var filters = [Configuration.TestFilter]()
627-
func testFilter(forRegularExpressions regexes: [String]?, label: String, membership: Configuration.TestFilter.Membership) throws -> Configuration.TestFilter {
628-
guard let regexes, !regexes.isEmpty else {
629-
// Return early if empty, even though the `reduce` logic below can handle
630-
// this case, in order to avoid the `#available` guard.
631-
return .unfiltered
627+
func testFilters(forOptionArguments optionArguments: [String]?, label: String, membership: Configuration.TestFilter.Membership) throws -> [Configuration.TestFilter] {
628+
629+
// Filters will come in two flavors: those with `tag:` as a prefix, and
630+
// those without. We split them into two collections, taking care to handle
631+
// an escaped colon, treating it as a pseudo-operator.
632+
let tagPrefix = "tag:"
633+
let escapedTagPrefix = #"tag\:"#
634+
var tags = [Tag]()
635+
var regexes = [String]()
636+
637+
// Loop through all the option arguments, separating tags from regex filters
638+
for var optionArg in optionArguments ?? [] {
639+
if optionArg.hasPrefix(tagPrefix) {
640+
// Running into the `tag:` prefix means we should strip it and use the
641+
// actual tag name the user has provided
642+
let tagStringWithoutPrefix = String(optionArg.dropFirst(tagPrefix.count))
643+
tags.append(Tag(userProvidedStringValue: tagStringWithoutPrefix))
644+
} else {
645+
// If we run into the escaped tag prefix, the user has indicated they
646+
// want to us to treat it as a regex filter. We need to to unescape it
647+
// before adding it as a regex filter
648+
if optionArg.hasPrefix(escapedTagPrefix) {
649+
optionArg.replaceSubrange(escapedTagPrefix.startIndex..<escapedTagPrefix.endIndex, with: tagPrefix)
650+
}
651+
regexes.append(optionArg)
652+
}
632653
}
633654

634-
return try Configuration.TestFilter(membership: membership, matchingAnyOf: regexes)
635-
}
636-
637-
// Extract any filters or skips without the `tag:` prefix; those will be treated as normal regexes.
638-
let tagPrefix = "tag:"
639-
let escapedTagPrefix = "tag\\:"
640-
var nonTagFilterRegexes: [String] = []
641-
var nonTagSkipRegexes: [String] = []
642-
643-
for var filter in args.filter ?? [] {
644-
if filter.hasPrefix(tagPrefix) {
645-
filters.append(Configuration.TestFilter(includingAnyOf: [Tag(userProvidedStringValue: String(filter.dropFirst(4)))]))
646-
} else {
647-
// If we run into the escaped tag prefix, we need to to remove the escape character before adding it as a regex filter
648-
if filter.hasPrefix(escapedTagPrefix) {
649-
filter.replaceSubrange(escapedTagPrefix.startIndex..<escapedTagPrefix.endIndex, with: tagPrefix)
650-
}
651-
nonTagFilterRegexes.append(filter)
655+
// If we didn't find any tags, the tagFilter should be .unfiltered,
656+
// otherwise we construct it with the provided tags
657+
let tagFilter: Configuration.TestFilter = switch (membership, tags.isEmpty) {
658+
case (_, true): .unfiltered
659+
case (.including, false): Configuration.TestFilter(includingAnyOf: tags)
660+
case (.excluding, false): Configuration.TestFilter(excludingAnyOf: tags)
652661
}
653-
}
654662

655-
for var skip in args.skip ?? [] {
656-
if skip.hasPrefix(tagPrefix) {
657-
filters.append(Configuration.TestFilter(includingAnyOf: [Tag(userProvidedStringValue: String(skip.dropFirst(4)))]))
658-
} else {
659-
// If we run into the escaped tag prefix, we need to to remove the escape character before adding it as a regex filter
660-
if skip.hasPrefix(escapedTagPrefix) {
661-
skip.replaceSubrange(escapedTagPrefix.startIndex..<escapedTagPrefix.endIndex, with: tagPrefix)
662-
}
663-
nonTagSkipRegexes.append(skip)
663+
guard !regexes.isEmpty else {
664+
// Return early with just the tag filter, even though the `reduce` logic
665+
// below can handle this case, in order to avoid the `#available` guard.
666+
return [tagFilter]
664667
}
668+
669+
return [try Configuration.TestFilter(membership: membership, matchingAnyOf: regexes), tagFilter]
665670
}
666671

667-
filters.append(try testFilter(forRegularExpressions: nonTagFilterRegexes, label: "--filter", membership: .including))
668-
filters.append(try testFilter(forRegularExpressions: nonTagSkipRegexes, label: "--skip", membership: .excluding))
672+
filters += try testFilters(forOptionArguments: args.filter, label: "--filter", membership: .including)
673+
filters += try testFilters(forOptionArguments: args.skip, label: "--skip", membership: .excluding)
669674

670675
configuration.testFilter = filters.reduce(.unfiltered) { $0.combining(with: $1) }
671676
if args.includeHiddenTests == true {

0 commit comments

Comments
 (0)