Improve handling of Swift tests

Tulsi needs to make sure that it doesn't include the modulemap file
for any direct dependencies of the test targt as it may conflict
with the source files that are added to the Test Target in Xcode.

PiperOrigin-RevId: 209838173
diff --git a/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl b/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl
index 412433b..5eccac7 100644
--- a/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl
+++ b/src/TulsiGenerator/Bazel/tulsi/tulsi_aspects.bzl
@@ -765,9 +765,11 @@
         target_includes = [_convert_outpath_to_symlink_path(x) for x in provider.includes.to_list()]
         swift_transitive_modules = _depset_to_file_metadata_list(provider.swift_modules)
         objc_module_maps = _depset_to_file_metadata_list(provider.module_maps)
+        test_deps = provider.deps.to_list()
     else:
         swift_transitive_modules = swift_transitive_modules.to_list()
         objc_module_maps = objc_module_maps.to_list()
+        test_deps = None
 
     info = _struct_omitting_none(
         artifacts = artifacts,
@@ -778,6 +780,7 @@
         objc_defines = objc_defines,
         swift_defines = swift_defines,
         deps = compile_deps,
+        test_deps = test_deps,
         extensions = extensions,
         framework_imports = _collect_framework_imports(rule_attr),
         generated_files = generated_files,
diff --git a/src/TulsiGenerator/BazelAspectInfoExtractor.swift b/src/TulsiGenerator/BazelAspectInfoExtractor.swift
index 983d14a..3486ba4 100644
--- a/src/TulsiGenerator/BazelAspectInfoExtractor.swift
+++ b/src/TulsiGenerator/BazelAspectInfoExtractor.swift
@@ -336,6 +336,8 @@
       let swiftDefines = dict["swift_defines"] as? [String]
       let deps = dict["deps"] as? [String] ?? []
       let dependencyLabels = Set(deps.map({ BuildLabel($0) }))
+      let testDeps = dict["test_deps"] as? [String] ?? []
+      let testDependencyLabels = Set(testDeps.map { BuildLabel($0) })
       let frameworkImports = MakeBazelFileInfos("framework_imports")
       let buildFilePath = dict["build_file"] as? String
       let osDeploymentTarget = dict["os_deployment_target"] as? String
@@ -396,6 +398,7 @@
                                 sourceFiles: sources,
                                 nonARCSourceFiles: nonARCSources,
                                 dependencies: dependencyLabels,
+                                testDependencies: testDependencyLabels,
                                 frameworkImports: frameworkImports,
                                 secondaryArtifacts: secondaryArtifacts,
                                 extensions: extensions,
diff --git a/src/TulsiGenerator/RuleEntry.swift b/src/TulsiGenerator/RuleEntry.swift
index 9bbaca4..48c7fce 100644
--- a/src/TulsiGenerator/RuleEntry.swift
+++ b/src/TulsiGenerator/RuleEntry.swift
@@ -197,6 +197,9 @@
   /// Set of the labels that this rule depends on.
   public let dependencies: Set<BuildLabel>
 
+  /// Set of the labels that this test rule's binary depends on.
+  public let testDependencies: Set<BuildLabel>
+
   /// Set of ios_application extension labels that this rule utilizes.
   public let extensions: Set<BuildLabel>
 
@@ -321,6 +324,7 @@
        sourceFiles: [BazelFileInfo] = [],
        nonARCSourceFiles: [BazelFileInfo] = [],
        dependencies: Set<BuildLabel> = Set(),
+       testDependencies: Set<BuildLabel> = Set(),
        frameworkImports: [BazelFileInfo] = [],
        secondaryArtifacts: [BazelFileInfo] = [],
        weakDependencies: Set<BuildLabel>? = nil,
@@ -363,6 +367,7 @@
     self.sourceFiles = sourceFiles
     self.nonARCSourceFiles = nonARCSourceFiles
     self.dependencies = dependencies
+    self.testDependencies = testDependencies
     self.frameworkImports = frameworkImports
     self.secondaryArtifacts = secondaryArtifacts
     if let weakDependencies = weakDependencies {
@@ -396,9 +401,26 @@
     // Unfortunately, this breaks Xcode's indexing (it doesn't really make sense to ask SourceKit
     // to index some source files in a module while at the same time giving it a compiled version
     // of the same module), so we must exclude it.
-    if let labelFileName = label.asFileName {
-      let selfModuleMap = "\(labelFileName).modulemaps/module.modulemap"
-      self.objCModuleMaps = objCModuleMaps.filter { !$0.fullPath.contains(selfModuleMap) }
+    //
+    // We must do the same thing for tests, except that it may apply to multiple modules as we
+    // combine sources from potentially multiple targets into one test target.
+    let targetsToAvoid = testDependencies + [label]
+    let moduleMapsToAvoid = targetsToAvoid.flatMap { targetLabel in
+      if let fileName = targetLabel.asFileName {
+        return "\(fileName).modulemaps/module.modulemap"
+      }
+      return nil
+    }
+    if !moduleMapsToAvoid.isEmpty {
+      self.objCModuleMaps = objCModuleMaps.filter { moduleMapFileInfo in
+        let moduleMapPath = moduleMapFileInfo.fullPath
+        for mapToAvoid in moduleMapsToAvoid {
+          if moduleMapPath.hasSuffix(mapToAvoid) {
+            return false
+          }
+        }
+        return true
+      }
     } else {
       self.objCModuleMaps = objCModuleMaps
     }
@@ -419,6 +441,7 @@
                    sourceFiles: [BazelFileInfo] = [],
                    nonARCSourceFiles: [BazelFileInfo] = [],
                    dependencies: Set<BuildLabel> = Set(),
+                   testDependencies: Set<BuildLabel> = Set(),
                    frameworkImports: [BazelFileInfo] = [],
                    secondaryArtifacts: [BazelFileInfo] = [],
                    weakDependencies: Set<BuildLabel>? = nil,
@@ -446,6 +469,7 @@
               sourceFiles: sourceFiles,
               nonARCSourceFiles: nonARCSourceFiles,
               dependencies: dependencies,
+              testDependencies: testDependencies,
               frameworkImports: frameworkImports,
               secondaryArtifacts: secondaryArtifacts,
               weakDependencies: weakDependencies,