@@ -101,4 +101,36 @@ public struct PackageGraph {
101
101
self . reachableTargets = reachableTargets
102
102
self . reachableProducts = reachableProducts
103
103
}
104
+
105
+ /// Computes a map from each executable target in any of the root packages to the corresponding test targets.
106
+ public func computeTestTargetsForExecutableTargets( ) -> [ ResolvedTarget : [ ResolvedTarget ] ] {
107
+ var result = [ ResolvedTarget: [ ResolvedTarget] ] ( )
108
+
109
+ let rootTargets = rootPackages. map ( { $0. targets } ) . flatMap ( { $0 } )
110
+
111
+ // Create map of test target to set of its direct dependencies.
112
+ let testTargetDepMap : [ ResolvedTarget : Set < ResolvedTarget > ] = {
113
+ let testTargetDeps = rootTargets. filter ( { $0. type == . test } ) . map ( {
114
+ ( $0, Set ( $0. dependencies. compactMap ( { $0. target } ) ) )
115
+ } )
116
+ return Dictionary ( uniqueKeysWithValues: testTargetDeps)
117
+ } ( )
118
+
119
+ for target in rootTargets where target. type == . executable {
120
+ // Find all dependencies of this target within its package.
121
+ let dependencies = try ! topologicalSort ( target. dependencies, successors: {
122
+ $0. dependencies. compactMap ( { $0. target } ) . map ( ResolvedTarget . Dependency. target)
123
+ } ) . compactMap ( { $0. target } )
124
+
125
+ // Include the test targets whose dependencies intersect with the
126
+ // current target's (recursive) dependencies.
127
+ let testTargets = testTargetDepMap. filter ( { ( testTarget, deps) in
128
+ !deps. intersection ( dependencies + [ target] ) . isEmpty
129
+ } ) . map ( { $0. key } )
130
+
131
+ result [ target] = testTargets
132
+ }
133
+
134
+ return result
135
+ }
104
136
}
0 commit comments