@@ -101,4 +101,36 @@ public struct PackageGraph {
101101 self . reachableTargets = reachableTargets
102102 self . reachableProducts = reachableProducts
103103 }
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+ }
104136}
0 commit comments